// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. types module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.

// Moved mechanically from scripts/src/ci.ts:1-267 for #903.

import { randomUUID } from "node:crypto";
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, posix as posixPath } from "node:path";
import { blockedCatalogArtifactIds, catalogSummary, findCiCatalogArtifact, loadCiCatalog, supportedSourceBuildArtifactIds, type CiCatalogArtifact, type CiSourceBuildCatalogArtifact, type CiUpstreamImageCatalogArtifact } from "../ci-catalog";
import { runCommand } from "../command";
import { type UniDeskConfig, repoRoot, rootPath } from "../config";
import { ensureGithubSshIdentityForProvider, gitSshHttpConnectProxySource } from "../deploy-ssh-identity";
import { jobWithTail, listJobs, readJob, startJob } from "../jobs";
import { coreInternalFetch } from "../microservices";
import {
  artifactRegistryReadonlyResultFromCommand,
  buildArtifactRegistryReadonlyProbe,
  parseArtifactRegistryOptions,
  type ArtifactRegistryReadonlyProbe,
} from "../artifact-registry";
import { d601K3sGuardShellLines, d601NativeKubeconfig } from "../d601-k3s-guard";
import { runSshCommandCapture } from "../ssh";
import { cicdTargetSummary, resolveCicdTarget, type TargetConfigSource } from "../ops/targets";

import { status } from "./cleanup";
import { stringOption } from "./options";

const d601YamlTarget = resolveCicdTarget("D601");
const g14YamlTarget = resolveCicdTarget("G14");

export const d601ProviderId = d601YamlTarget.providerId;

export const d601Kubeconfig = d601YamlTarget.kubeconfig;

export const tektonPipelineVersion = "v1.12.0";

export const tektonTriggersVersion = "v0.34.0";

export const tektonPipelineReleaseUrl = `https://infra.tekton.dev/tekton-releases/pipeline/previous/${tektonPipelineVersion}/release.yaml`;

export const tektonTriggersReleaseUrl = `https://infra.tekton.dev/tekton-releases/triggers/previous/${tektonTriggersVersion}/release.yaml`;

export const tektonTriggersInterceptorsUrl = `https://infra.tekton.dev/tekton-releases/triggers/previous/${tektonTriggersVersion}/interceptors.yaml`;

export const providerGatewayWsEgressProxyUrl = "http://127.0.0.1:18789";

export const ciCodeQueueImage = "unidesk-code-queue:dev";

export const codeQueueDirectDockerBaseImage = "unidesk-code-queue:d601";

export const providerDispatchCompletionLagMs = 45_000;

export const defaultCiPipelineManifest = d601YamlTarget.pipelineManifest;

export const g14CiPipelineManifest = g14YamlTarget.pipelineManifest;

export const ciRuntimeImages = [
  "rancher/mirrored-pause:3.6",
  "rancher/mirrored-library-busybox:1.36.1",
  "cgr.dev/chainguard/busybox@sha256:19f02276bf8dbdd62f069b922f10c65262cc34b710eea26ff928129a736be791",
  "ghcr.io/tektoncd/pipeline/entrypoint-bff0a22da108bc2f16c818c97641a296:v1.12.0",
  "ghcr.io/tektoncd/pipeline/workingdirinit-0c558922ec6a1b739e550e349f2d5fc1:v1.12.0",
  "ghcr.io/tektoncd/pipeline/nop-8eac7c133edad5df719dc37b36b62482:v1.12.0",
  "ghcr.io/tektoncd/pipeline/events-a9042f7efb0cbade2a868a1ee5ddd52c:v1.12.0",
  "ghcr.io/tektoncd/triggers/eventlistenersink-7ad1faa98cddbcb0c24990303b220bb8:v0.34.0",
  "oven/bun:1-debian",
  "alpine/git:2.45.2",
  ciCodeQueueImage,
];

export function ciTarget(providerId: string | null): CiTarget {
  const target = resolveCicdTarget(providerId);
  return {
    targetId: target.targetId,
    providerId: target.providerId,
    kubeRoute: target.kubeRoute,
    kubeconfig: target.kubeconfig,
    hostCwd: target.hostCwd,
    homeDir: target.homeDir,
    pipelineManifest: target.pipelineManifest,
    codeQueueImage: target.codeQueueImage,
    guardName: target.guardName,
    requiredNodeName: target.requiredNodeName,
    requiredNodeLabel: target.requiredNodeLabel,
    artifactRegistryConfigRef: target.artifactRegistryConfigRef,
    configSource: target.configSource,
  };
}

export function providerIdOption(args: string[]): string | null {
  return stringOption(args, "--target") ?? stringOption(args, "--provider-id") ?? stringOption(args, "--provider");
}

export function ciTargetSourceSummary(target: CiTarget): Record<string, unknown> {
  return cicdTargetSummary({
    targetId: target.targetId,
    providerId: target.providerId,
    kubeRoute: target.kubeRoute,
    kubeconfig: target.kubeconfig,
    hostCwd: target.hostCwd,
    homeDir: target.homeDir,
    pipelineManifest: target.pipelineManifest,
    codeQueueImage: target.codeQueueImage,
    guardName: target.guardName,
    requiredNodeName: target.requiredNodeName,
    requiredNodeLabel: target.requiredNodeLabel,
    artifactRegistryConfigRef: target.artifactRegistryConfigRef,
    configSource: target.configSource,
  });
}

export interface CiOptions {
  repoUrl: string;
  revision: string;
  waitMs: number;
  target: CiTarget;
}

export interface CiInstallOptions {
  target: CiTarget;
  skipPrewarm: boolean;
  skipTektonInstall: boolean;
  wait: boolean;
}

export interface CiTarget {
  targetId: string;
  providerId: string;
  kubeRoute: string;
  kubeconfig: string;
  hostCwd: string;
  homeDir: string;
  pipelineManifest: string;
  codeQueueImage: string;
  guardName: string;
  requiredNodeName?: string;
  requiredNodeLabel?: { key: string; value: string };
  artifactRegistryConfigRef?: string;
  configSource: TargetConfigSource;
}

export interface CiPublishBackendCoreOptions {
  repoUrl: string;
  commit: string;
  waitMs: number;
  sourceHostPath: string;
  dockerfile: string;
  imageRepository: string;
  dryRun: boolean;
}

export interface CiPublishUserServiceArtifactOptions {
  repoUrl: string;
  commit: string;
  waitMs: number;
  sourceHostPath: string;
  serviceId: string;
  dockerfile: string;
  imageRepository: string;
  dryRun: boolean;
  transport: CiPublishTransport;
}

export type CiPublishTransport = "auto" | "tekton" | "direct-docker";

export interface CiDevE2EOptions {
  repoUrl: string;
  desiredRef: string;
  deployCommit: string;
  environment: "dev";
  scriptRepo: string;
  scriptPath: string;
  scriptTimeoutMs: number;
  services: Array<{ id: string; commitId: string; repo: string }>;
  runId: string;
  keepNamespace: boolean;
  waitMs: number;
}

export interface DispatchResult {
  ok: boolean;
  taskId: string | null;
  status: string | null;
  stdout: string;
  stderr: string;
  exitCode: number | null;
  raw: unknown;
}

export interface CiLogsOptions {
  tailLines: number;
  capture: "dispatch-task" | "ssh-stream";
}

export interface CiCleanupRunsOptions {
  target: CiTarget;
  minAgeMinutes: number;
  limit: number;
  confirm: boolean;
}

export interface CiCleanupFailedPodsOptions {
  target: CiTarget;
  namespace: string;
  minAgeMinutes: number;
  limit: number;
  confirm: boolean;
}

export type PublishPreflightFailureClassification = "auth-missing" | "remote-proxy-missing" | "provider-unreachable" | "local-docker-required" | "registry-not-installed" | "registry-unhealthy" | "remote-command-timeout" | "ssh-helper-command-shape-incompatible" | "ci-runner-not-ready";

export type PublishPreflightControlChannel = "backend-core" | "database" | "provider" | "registry";

export type PublishPreflightDetailedChannel = "backend-core-api" | "provider-dispatch" | "provider-host-ssh" | "database" | "artifact-registry";

export interface PublishPreflightChannelProbe {
  channel: PublishPreflightDetailedChannel;
  controlChannel: PublishPreflightControlChannel;
  ok: boolean;
  requiredFor: string;
  detail: unknown;
}

export interface PublishPreflightControlChannelProbe {
  channel: PublishPreflightControlChannel;
  ok: boolean;
  requiredFor: string[];
  probes: PublishPreflightDetailedChannel[];
}

export interface PublishPreflight {
  ok: boolean;
  runnerDisposition: "ready" | "infra-blocked";
  failureClassification: PublishPreflightFailureClassification | null;
  serviceId: string;
  commit: string;
  providerId: string;
  supportedArtifactPublish: boolean;
  missingChannels: string[];
  missingControlChannels: PublishPreflightControlChannel[];
  controlChannels: PublishPreflightControlChannelProbe[];
  channels: PublishPreflightChannelProbe[];
  registry: unknown;
  controlPlane: Record<string, unknown>;
  recommendedAction: string;
  remoteCommandShape: string;
  next: string[];
  boundary: string;
}

export interface PublishPreflightTransport {
  kind?: "local-docker" | "remote-frontend" | "provider-tunnel";
  remoteHost?: string | null;
  coreFetch: (path: string, init?: { method?: string; body?: unknown; maxResponseBytes?: number }) => unknown | Promise<unknown>;
  dispatchHostSsh: (command: string, waitMs: number, remoteTimeoutMs: number) => Promise<DispatchResult>;
  commandCwd: string;
  artifactRegistryCommand: (probe: ArtifactRegistryReadonlyProbe) => string[];
}

export interface PipelineRunCondition {
  ok: boolean | null;
  status: string;
  reason: string;
  message: string;
  query: {
    ok: boolean;
    status: string | null;
    exitCode: number | null;
    stdoutTail: string;
    stderrTail: string;
  };
}

export interface DeployDevManifestSummary {
  deployCommit: string;
  desiredRef: string;
  environment: "dev";
  ci: {
    repo: string;
    scriptPath: string;
    timeoutMs: number;
  };
  services: Array<{ id: string; commitId: string; repo: string }>;
}

export interface ArtifactSummary {
  serviceId: string;
  sourceCommit: string;
  sourceRepo: string;
  dockerfile: string;
  registry: string;
  repository: string;
  tag: string;
  imageRef: string;
  digest: string | null;
  digestRef: string | null;
}

export interface ArtifactSummaryContext {
  serviceId: string;
  commit: string;
  repoUrl: string;
  dockerfile: string;
  imageRepository: string;
}
