// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. cleanup-scripts module for scripts/src/agentrun.ts.

// Moved mechanically from scripts/src/agentrun.ts:3187-3310 for #903.

// SPEC: PJ2026-01020108 cancel lifecycle + PJ2026-01020205 AipodSpec binding + PJ2026-01020302 session policy + PJ2026-01020305 cancel control + PJ2026-01060305/06 YAML execution policy and bounded output draft-2026-06-25-p0.
// Exposes AgentRun lane-scoped policy, AipodSpec SecretRef binding, cancel lifecycle, and bounded default output in the UniDesk CLI.
import { chmodSync, copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { spawnSync } from "node:child_process";
import { rootPath, type UniDeskConfig } from "../config";
import type { RenderedCliResult } from "../output";
import { applyLocalCaddyManagedSite } from "../pk01-caddy";
import { runSshCommandCapture, type SshCaptureResult } from "../ssh";
import { runRemoteSshCommandCapture } from "../remote";
import { startJob } from "../jobs";
import {
  AGENTRUN_CONFIG_PATH,
  agentRunLaneSummary,
  agentRunPipelineRunName,
  agentRunProviderCredentialRefs,
  resolveAgentRunLaneTarget,
  type AgentRunCancelLifecycleSpec,
  type AgentRunLaneSpec,
} from "../agentrun-lanes";
import {
  agentRunImageArtifact,
  placeholderAgentRunImage,
  renderedFilesDigest,
  renderedObjectsDigest,
  renderAgentRunControlPlaneManifests,
  renderAgentRunGitopsFiles,
  type AgentRunArtifactService,
} from "../agentrun-manifests";
import { sha256Fingerprint } from "../platform-infra-ops-library";

import { runYamlLaneGitMirrorFlushJob, runYamlLaneGitMirrorSyncJob, yamlLanePipelineRunCreateScript } from "./secrets";
import { capture, captureJsonPayload, compactCapture, isGitSha, progressEvent, stringOrNull } from "./utils";
import { runYamlLaneGitopsPublishJob, runYamlLaneK3sBuildImageJob, waitForYamlLaneBuildImage, waitForYamlLaneSourceBootstrap, yamlLaneBuildImageSubmitScript, yamlLaneK3sSourceStatusScript, yamlLaneSourceBootstrapSubmitScript, yamlLaneSourceRestoreScript } from "./yaml-lane";

export async function triggerCurrentYamlLaneConfirmed(config: UniDeskConfig, spec: AgentRunLaneSpec, configPath: string, waited: boolean): Promise<Record<string, unknown>> {
  const result = await triggerCurrentYamlLaneConfirmedSteps(config, spec, configPath, waited);
  if (spec.source.statusMode === "k3s-git-mirror") {
    return {
      ...result,
      sourceWorkspaceRestore: { ok: true, status: "skipped", statusMode: spec.source.statusMode, reason: "k3s-git-mirror-does-not-use-host-worktree", valuesPrinted: false },
      valuesPrinted: false,
    };
  }
  const restore = await capture(config, spec.nodeRoute, ["sh", "--", yamlLaneSourceRestoreScript(spec)]);
  const restorePayload = captureJsonPayload(restore);
  const restoreOk = restore.exitCode === 0 && restorePayload.ok === true;
  const existingWarnings = Array.isArray(result.warnings) ? result.warnings.filter((item): item is string => typeof item === "string") : [];
  return {
    ...result,
    warnings: restoreOk ? existingWarnings : Array.from(new Set([...existingWarnings, "source-worktree-restore-failed"])),
    sourceWorkspaceRestore: restorePayload,
    sourceWorkspaceRestoreCapture: compactCapture(restore, { full: !restoreOk, stdoutTailChars: 3000, stderrTailChars: 3000 }),
    valuesPrinted: false,
  };
}

export async function triggerCurrentYamlLaneConfirmedSteps(config: UniDeskConfig, spec: AgentRunLaneSpec, configPath: string, waited: boolean): Promise<Record<string, unknown>> {
  const source = await resolveTriggerCurrentSource(config, spec, configPath, waited);
  if (source.ok !== true) return source;
  const sourceCommit = stringOrNull(source.sourceCommit);
  const bootstrapPayload = source.sourcePayload;
  if (sourceCommit === null || !isGitSha(sourceCommit)) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "source-resolve",
      degradedReason: "yaml-lane-source-commit-invalid",
      result: bootstrapPayload,
      valuesPrinted: false,
    };
  }
  const buildResult = await buildTriggerCurrentImage(config, spec, sourceCommit, bootstrapPayload, configPath, waited);
  if (buildResult.ok !== true) return buildResult;
  const build = buildResult.buildStatus;
  const buildSubmitPayload = buildResult.buildSubmitPayload;
  const buildPayload = build.payload;
  const digest = stringOrNull(buildPayload.digest);
  const envIdentity = stringOrNull(buildPayload.envIdentity);
  if (build.ok !== true || digest === null || envIdentity === null) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "image-build",
      sourceCommit,
      degradedReason: "yaml-lane-image-build-failed",
      sourceBootstrap: bootstrapPayload,
      buildSubmit: buildSubmitPayload,
      result: buildPayload,
      buildStatus: build,
      valuesPrinted: false,
    };
  }
  const image = agentRunImageArtifact(spec, { sourceCommit, envIdentity, digest, status: stringOrNull(buildPayload.status) ?? "built" });
  const renderedFiles = renderAgentRunGitopsFiles(spec, { sourceCommit, image });
  const mirrorPrePublish = await runYamlLaneGitMirrorSyncJob(config, spec);
  if (mirrorPrePublish.ok !== true) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "git-mirror-prepublish-sync",
      sourceCommit,
      image,
      degradedReason: "yaml-lane-git-mirror-prepublish-sync-failed",
      sourceBootstrap: bootstrapPayload,
      imageBuild: buildPayload,
      result: mirrorPrePublish,
      valuesPrinted: false,
    };
  }
  progressEvent("agentrun.yaml-lane.gitops-publish.progress", {
    node: spec.nodeId,
    lane: spec.lane,
    sourceCommit,
    status: "submitting",
  });
  const gitops = await runYamlLaneGitopsPublishJob(config, spec, sourceCommit, renderedFiles);
  const gitopsPayload = gitops.payload;
  if (gitops.ok !== true || gitopsPayload.ok === false) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "gitops-publish",
      sourceCommit,
      image,
      degradedReason: "yaml-lane-gitops-publish-failed",
      sourceBootstrap: bootstrapPayload,
      imageBuild: buildPayload,
      gitMirrorPrePublish: mirrorPrePublish,
      result: gitopsPayload,
      gitopsPublishStatus: gitops,
      valuesPrinted: false,
    };
  }
  const mirrorFlush = await runYamlLaneGitMirrorFlushJob(config, spec);
  if (mirrorFlush.ok !== true) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "git-mirror-flush",
      sourceCommit,
      image,
      gitops: gitopsPayload,
      gitMirrorPrePublish: mirrorPrePublish,
      degradedReason: "yaml-lane-git-mirror-flush-failed",
      result: mirrorFlush,
      valuesPrinted: false,
    };
  }
  const pipelineRun = agentRunPipelineRunName(spec, sourceCommit);
  const created = await capture(config, spec.nodeKubeRoute, ["sh", "--", yamlLanePipelineRunCreateScript(spec, sourceCommit, pipelineRun)]);
  const createPayload = captureJsonPayload(created);
  return {
    ok: created.exitCode === 0 && createPayload.ok !== false,
    command: "agentrun control-plane trigger-current",
    mode: waited ? "confirmed-waited" : "confirmed-trigger",
    mutation: true,
    configPath,
    target: agentRunLaneSummary(spec),
    sourceCommit,
    pipelineRun,
    image,
    sourceBootstrap: bootstrapPayload,
    imageBuildSubmit: buildSubmitPayload,
    imageBuild: buildPayload,
    renderedFiles: {
      count: renderedFiles.length,
      digest: renderedFilesDigest(renderedFiles),
    },
    gitops: gitopsPayload,
    gitMirrorPrePublish: mirrorPrePublish,
    gitMirror: mirrorFlush,
    created: createPayload,
    capture: compactCapture(created, { full: created.exitCode !== 0, stdoutTailChars: 4000, stderrTailChars: 4000 }),
    next: {
      status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
      statusByPipelineRun: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane} --pipeline-run ${pipelineRun} --full`,
    },
    valuesPrinted: false,
  };
}

async function resolveTriggerCurrentSource(config: UniDeskConfig, spec: AgentRunLaneSpec, configPath: string, waited: boolean): Promise<Record<string, unknown> & { ok: boolean; sourceCommit?: string | null; sourcePayload?: Record<string, unknown> }> {
  if (spec.source.statusMode === "k3s-git-mirror") {
    progressEvent("agentrun.yaml-lane.source-snapshot.progress", {
      node: spec.nodeId,
      lane: spec.lane,
      statusMode: spec.source.statusMode,
      status: "syncing",
    });
    const sourceSync = await runYamlLaneGitMirrorSyncJob(config, spec);
    if (sourceSync.ok !== true) {
      return {
        ok: false,
        command: "agentrun control-plane trigger-current",
        mode: waited ? "confirmed-waited" : "confirmed-trigger",
        configPath,
        target: agentRunLaneSummary(spec),
        phase: "source-snapshot-sync",
        degradedReason: "yaml-lane-k3s-source-snapshot-sync-failed",
        result: sourceSync,
        valuesPrinted: false,
      };
    }
    progressEvent("agentrun.yaml-lane.source-status.progress", {
      node: spec.nodeId,
      lane: spec.lane,
      statusMode: spec.source.statusMode,
      status: "probing-snapshot",
    });
    const sourceStatus = await capture(config, spec.nodeKubeRoute, ["sh", "--", yamlLaneK3sSourceStatusScript(spec)]);
    const sourcePayload = captureJsonPayload(sourceStatus);
    const sourceCommit = stringOrNull(sourcePayload.sourceCommit) ?? stringOrNull(sourcePayload.remoteBranchCommit);
    if (sourceStatus.exitCode !== 0 || sourcePayload.ok !== true || sourceCommit === null || !isGitSha(sourceCommit)) {
      return {
        ok: false,
        command: "agentrun control-plane trigger-current",
        mode: waited ? "confirmed-waited" : "confirmed-trigger",
        configPath,
        target: agentRunLaneSummary(spec),
        phase: "source-status",
        degradedReason: stringOrNull(sourcePayload.degradedReason) ?? "yaml-lane-k3s-source-status-failed",
        gitMirrorSync: sourceSync,
        result: sourcePayload,
        capture: compactCapture(sourceStatus, { full: true, stdoutTailChars: 5000, stderrTailChars: 5000 }),
        valuesPrinted: false,
      };
    }
    return { ok: true, sourceCommit, sourcePayload: { ...sourcePayload, gitMirrorSync: sourceSync, valuesPrinted: false }, valuesPrinted: false };
  }

  progressEvent("agentrun.yaml-lane.source-bootstrap.progress", {
    node: spec.nodeId,
    lane: spec.lane,
    status: "submitting",
  });
  const bootstrapSubmit = await capture(config, spec.nodeRoute, ["sh", "--", yamlLaneSourceBootstrapSubmitScript(spec)]);
  const bootstrapSubmitPayload = captureJsonPayload(bootstrapSubmit);
  if (bootstrapSubmit.exitCode !== 0 || bootstrapSubmitPayload.ok === false) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "source-bootstrap-submit",
      degradedReason: "yaml-lane-source-bootstrap-submit-failed",
      result: bootstrapSubmitPayload,
      capture: compactCapture(bootstrapSubmit, { full: true, stdoutTailChars: 5000, stderrTailChars: 5000 }),
      valuesPrinted: false,
    };
  }
  const bootstrap = await waitForYamlLaneSourceBootstrap(config, spec, stringOrNull(bootstrapSubmitPayload.jobId));
  const sourcePayload = bootstrap.payload;
  const sourceCommit = stringOrNull(sourcePayload.sourceCommit);
  if (bootstrap.ok !== true || sourceCommit === null || !isGitSha(sourceCommit)) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "source-bootstrap",
      degradedReason: "yaml-lane-source-bootstrap-failed",
      result: sourcePayload,
      bootstrapStatus: bootstrap,
      valuesPrinted: false,
    };
  }
  return { ok: true, sourceCommit, sourcePayload, sourceBootstrapSubmit: bootstrapSubmitPayload, valuesPrinted: false };
}

async function buildTriggerCurrentImage(config: UniDeskConfig, spec: AgentRunLaneSpec, sourceCommit: string, sourcePayload: Record<string, unknown>, configPath: string, waited: boolean): Promise<Record<string, unknown> & { ok: boolean; buildStatus?: Record<string, unknown> & { ok: boolean; payload: Record<string, unknown> }; buildSubmitPayload?: Record<string, unknown> }> {
  if (spec.source.statusMode === "k3s-git-mirror") {
    const build = await runYamlLaneK3sBuildImageJob(config, spec, sourceCommit);
    const buildSubmitPayload = {
      ok: build.ok !== false,
      status: "submitted",
      mode: "k3s-buildkit-job",
      jobName: stringOrNull(build.jobName) ?? null,
      valuesPrinted: false,
    };
    if (build.ok !== true) {
      return {
        ok: false,
        command: "agentrun control-plane trigger-current",
        mode: waited ? "confirmed-waited" : "confirmed-trigger",
        configPath,
        target: agentRunLaneSummary(spec),
        phase: "image-build",
        sourceCommit,
        degradedReason: "yaml-lane-k3s-image-build-failed",
        sourceBootstrap: sourcePayload,
        buildSubmit: buildSubmitPayload,
        result: build.payload,
        buildStatus: build,
        valuesPrinted: false,
      };
    }
    return { ok: true, buildStatus: build, buildSubmitPayload, valuesPrinted: false };
  }

  const buildSubmit = await capture(config, spec.nodeRoute, ["sh", "--", yamlLaneBuildImageSubmitScript(spec, sourceCommit)]);
  const buildSubmitPayload = captureJsonPayload(buildSubmit);
  if (buildSubmit.exitCode !== 0 || buildSubmitPayload.ok === false) {
    return {
      ok: false,
      command: "agentrun control-plane trigger-current",
      mode: waited ? "confirmed-waited" : "confirmed-trigger",
      configPath,
      target: agentRunLaneSummary(spec),
      phase: "image-build-submit",
      sourceCommit,
      degradedReason: "yaml-lane-image-build-submit-failed",
      sourceBootstrap: sourcePayload,
      result: buildSubmitPayload,
      capture: compactCapture(buildSubmit, { full: true, stdoutTailChars: 5000, stderrTailChars: 5000 }),
      valuesPrinted: false,
    };
  }
  const build = await waitForYamlLaneBuildImage(config, spec, sourceCommit, stringOrNull(buildSubmitPayload.jobId));
  return { ok: true, buildStatus: build, buildSubmitPayload, valuesPrinted: false };
}
