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

// Moved mechanically from scripts/src/deploy.ts:1-212 for #903.

import { createHash } from "node:crypto";
import { existsSync, mkdirSync, readFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
import { runCommand } from "../command";
import { type UniDeskConfig, type UniDeskMicroserviceConfig, repoRoot, rootPath } from "../config";
import { ensureGithubSshIdentityForProvider } from "../deploy-ssh-identity";
import { baiduNetdiskRuntimeSecretRequirements, runtimeSecretContractFromEnvText, type RuntimeSecretContract, runArtifactRegistryCommand } from "../artifact-registry";
import { startJob } from "../jobs";
import { coreInternalFetch } from "../microservices";
import { codeQueueSourceImportPreflight, codeQueueSourceSubdir } from "../code-queue-source-guard";
import { d601K3sGuardShellLines, d601NativeKubeconfig } from "../d601-k3s-guard";
import { composeRuntimeEnvValue } from "../runtime-env";
import { resolveArtifactRegistryTarget } from "../ops/targets";
import {
  compareDeployJsonExecutorMirrors,
  deployJsonCommitImage,
  deployJsonDriftResult,
  deployJsonSourceOfTruth,
  encodeDeployJsonServiceContract,
  hasDeployJsonExecutorContract,
  k3sManifestExecutorMirror,
  parseDeployJsonServiceContract,
  type DeployJsonExecutorMirror,
  type DeployJsonServiceContract,
} from "../deploy-json-contract";

import { step } from "./remote";

export type DeployAction = "check" | "plan" | "apply";

export type DeployEnvironment = "dev" | "prod";

export type DeployManifestService = DeployJsonServiceContract;

export interface DeployManifest {
  schemaVersion: 1 | 2;
  environment: DeployEnvironment | null;
  services: DeployManifestService[];
}

export interface DeployOptions {
  file: string;
  environment: DeployEnvironment | null;
  serviceId: string | null;
  commitOverride: string | null;
  providerId: string;
  runNow: boolean;
  dryRun: boolean;
  force: boolean;
  timeoutMs: number;
}

export interface StepResult {
  step: string;
  ok: boolean;
  detail: string;
  startedAt: string;
  finishedAt: string;
  raw?: unknown;
}

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

export interface BackgroundPoll {
  done: boolean;
  exitCode: number | null;
  logTail: string;
  raw: unknown;
}

export interface RemoteScriptUpload {
  ok: boolean;
  path: string;
  error: string;
  raw: unknown[];
}

export interface ServiceRuntimeState {
  serviceId: string;
  ok: boolean;
  supported: boolean;
  reason: string | null;
  desiredRepo: string;
  desiredCommit: string;
  providerId: string;
  deploymentMode: string;
  currentCommit: string | null;
  healthCommit: string | null;
  healthRequestedCommit: string | null;
  imageCommit: string | null;
  orchestratorCommit: string | null;
  healthOk: boolean;
  upToDate: boolean;
  raw?: unknown;
}

export interface DeployEnvironmentTarget {
  environment: DeployEnvironment;
  remote: string;
  branch: string;
  gitRef: string;
  namespace: string;
  runtimeScope: string;
  database: {
    serviceId: string;
    host: string;
    port: number;
    name: string;
  };
  provider: {
    providerId: string;
    nodeId: string;
    credentialScope: string;
  };
}

export interface DeployEnvironmentManifestSource {
  source: "git-ref";
  path: "deploy.json";
  ref: string;
  remote: string;
  branch: string;
  commit: string;
  blob: string;
  fetchedAt: string;
}

export type ArtifactConsumerPlanKind = "main-server-compose" | "d601-direct-compose" | "d601-k3s-managed" | "d601-dev-target-side-build" | "unsupported";

export const defaultDeployFile = "deploy.json";

export const defaultTimeoutMs = 900_000;

export const resolveFetchTimeout = "120s";

export const shortDispatchWaitMs = 60_000;

export const shortRemoteTimeoutMs = 20_000;

export const providerDispatchCompletionLagMs = 45_000;

const d601ArtifactRegistryTarget = resolveArtifactRegistryTarget("D601");

export const d601DeployProviderId = d601ArtifactRegistryTarget.providerId;

export const d601DeployNodeId = d601ArtifactRegistryTarget.targetId;

export const pollIntervalMs = 5_000;

export const remoteDeployRoot = "/home/ubuntu/.unidesk/deploy";

export const k8sNamespace = "unidesk";

export const k8sKubeconfig = d601NativeKubeconfig;

export // Production k3s hostPath repo. Code Queue production Pods mount this path as /app and /root/unidesk,
// so deploy guards must validate this tree rather than config.json development.worktreePath.
const k3sProductionHostPathRepoDir = "/home/ubuntu/cq-deploy";

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

export const nativeK3sInstallVersion = "v1.34.1+k3s1";

export const nativeK3sImage = "rancher/k3s:v1.34.1-k3s1";

export const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock";

export const unideskRepoUrl = "https://github.com/pikasTech/unidesk";

export const d601MaintenanceDeployAllowedServiceIds = new Set<string>(["k3sctl-adapter"]);

export const devApplySupportedServiceIds = new Set<string>();

export const devArtifactConsumerServiceIds = new Set<string>(["auth-broker", "backend-core", "baidu-netdisk", "claudeqq", "code-queue", "code-queue-mgr", "decision-center", "findjob", "frontend", "mdtodo", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);

export const devArtifactConsumerProdDesiredFallbackServiceIds = new Set<string>(["code-queue-mgr", "oa-event-flow", "project-manager", "todo-note"]);

export const prodArtifactConsumerServiceIds = new Set<string>(["auth-broker", "backend-core", "baidu-netdisk", "claudeqq", "code-queue-mgr", "decision-center", "findjob", "frontend", "k3sctl-adapter", "mdtodo", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);

export const prodForbiddenTargetSideBuildServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "claudeqq", "decision-center", "findjob", "frontend", "k3sctl-adapter", "mdtodo", "met-nonlinear", "pipeline"]);

export const prodArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
  ["auth-broker", "auth-broker is registered for source/contract/profile dry-run only; live production apply requires a separate credential mounting and exposure review."],
  ["code-queue-mgr", "code-queue-mgr is the main-server Code Queue control-plane sidecar; live production apply requires explicit supervisor confirmation."],
  ["met-nonlinear", "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts."],
  ["k3sctl-adapter", "k3sctl-adapter is an infrastructure control bridge; this executor exposes artifact consumer plan/dry-run only. Real production deployment requires supervisor confirmation outside this task."],
]);

export const devArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
  ["auth-broker", "auth-broker is registered for source/contract/profile dry-run only; live DEV apply requires a separate credential mounting and exposure review."],
  ["code-queue", "Code Queue DEV live apply is self-bootstrap sensitive: a running Code Queue task may produce dry-run evidence only. A human operator or supervisor must explicitly authorize DEV apply outside Code Queue after reviewing the CI artifact digest and dry-run target list."],
]);

export const artifactConsumerDryRunBlockedServiceIds = new Map<string, string>([
  ["met-nonlinear", "runtime-verification-blocked: CI publishes the ML image Dockerfile contract, but the long-running Compose service is met-nonlinear-ts; CD cannot yet prove the running container image label matches the requested commit."],
]);

export const deployEnvironmentTargets: Record<DeployEnvironment, DeployEnvironmentTarget> = {
  dev: {
    environment: "dev",
    remote: "origin",
    branch: "master",
    gitRef: "origin/master",
    namespace: "unidesk-dev",
    runtimeScope: "d601-k3s-dev",
    database: {
      serviceId: "postgres-dev",
      host: "postgres-dev.unidesk-dev.svc.cluster.local",
      port: 5432,
      name: "unidesk_dev",
    },
    provider: {
      providerId: "D601-dev",
      nodeId: "D601",
      credentialScope: "dev-only",
    },
  },
  prod: {
    environment: "prod",
    remote: "origin",
    branch: "master",
    gitRef: "origin/master",
    namespace: "unidesk",
    runtimeScope: "prod-main-server-compose-and-d601-k3s",
    database: {
      serviceId: "postgres-prod",
      host: "database.unidesk-main-server",
      port: 5432,
      name: "unidesk",
    },
    provider: {
      providerId: d601DeployProviderId,
      nodeId: d601DeployNodeId,
      credentialScope: "prod",
    },
  },
};
