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

// Moved mechanically from scripts/src/hwlab-g14.ts:8075-8386 for #903.

import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { createHash, randomBytes } from "node:crypto";
import { repoRoot, rootPath, type Config } from "../config";
import { runCommand } from "../command";
import { cancelJob, listJobs, readJob, startJob } from "../jobs";
import { hwlabRequiredNoProxyEntries, hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec, isHwlabRuntimeLane, type HwlabRuntimeLane, type HwlabRuntimeLaneSpec } from "../hwlab-node-lanes";

import type { CommandJsonResult, G14ControlPlaneOptions, G14GitMirrorOptions, G14ToolsImageOptions, G14UpstreamImageOptions } from "./types";
import { statusText } from "./pr-monitor";
import { cliJson, isCommandSuccess, record, shellQuote } from "./remote";
import { G14_CI_TOOLS_IMAGE_REPO, G14_PROVIDER, GIT_MIRROR_NAMESPACE, V02_REGISTRY_PREFIX, V02_WORKSPACE } from "./types";

export function startAsyncHwlabG14Job(name: string, command: string[], note: string): Record<string, unknown> {
  const job = startJob(name, command, note);
  const statusCommand = `bun scripts/cli.ts job status ${job.id} --tail-bytes 12000`;
  return {
    ok: true,
    mode: "async-job",
    job,
    statusCommand,
    tailCommand: `tail -f ${job.stdoutFile}`,
    next: {
      status: statusCommand,
      tail: `tail -f ${job.stdoutFile}`,
    },
  };
}

export function startControlPlaneTriggerJob(options: G14ControlPlaneOptions): Record<string, unknown> {
  const command = [
    "bun",
    "scripts/cli.ts",
    "hwlab",
    "g14",
    "control-plane",
    "trigger-current",
    "--lane",
    options.lane,
    "--confirm",
    "--timeout-seconds",
    String(options.timeoutSeconds),
    "--wait",
  ];
  if (options.rerun) command.splice(command.length - 1, 0, "--rerun");
  return {
    command: `hwlab g14 control-plane trigger-current --lane ${options.lane}`,
    lane: options.lane,
    reason: "confirmed trigger can spend tens of seconds syncing git mirror and creating PipelineRun; default is fire-and-forget to avoid silent blocking",
    waitCommand: command.join(" "),
    ...startAsyncHwlabG14Job(
      `hwlab_g14_${options.lane}_trigger_current`,
      command,
      `Trigger HWLAB ${options.lane} current commit PipelineRun with git mirror pre-sync through G14 control-plane`,
    ),
  };
}

export function startGitMirrorJob(options: G14GitMirrorOptions): Record<string, unknown> {
  const command = [
    "bun",
    "scripts/cli.ts",
    "hwlab",
    "g14",
    "git-mirror",
    options.action,
    "--lane",
    options.lane,
    "--confirm",
    "--timeout-seconds",
    String(options.timeoutSeconds),
    "--wait",
  ];
  return {
    command: `hwlab g14 git-mirror ${options.action} --lane ${options.lane}`,
    lane: options.lane,
    namespace: GIT_MIRROR_NAMESPACE,
    reason: "manual git mirror sync/flush waits for a Kubernetes Job; default is fire-and-forget to keep CLI output immediately visible",
    waitCommand: command.join(" "),
    ...startAsyncHwlabG14Job(
      `hwlab_g14_git_mirror_${options.action}`,
      command,
      `Run HWLAB devops-infra git mirror ${options.action} through a bounded manual Kubernetes Job`,
    ),
  };
}

export function g14HostScript(script: string, timeoutMs = 120_000): CommandJsonResult {
  return cliJson(["ssh", G14_PROVIDER, "sh", "--", script], timeoutMs);
}

export function g14CiToolsImage(tag: string): string {
  return `${G14_CI_TOOLS_IMAGE_REPO}:${tag}`;
}

export function runG14ToolsImageStatus(options: G14ToolsImageOptions): Record<string, unknown> {
  const image = g14CiToolsImage(options.tag);
  const script = [
    "set -u",
    `image=${shellQuote(image)}`,
    "exists=false",
    "image_id=",
    "created=",
    "size=",
    "node_version=",
    "npm_version=",
    "bun_version=",
    "git_version=",
    "docker_version=",
    "python_version=",
    "registry_tags=",
    "if docker image inspect \"$image\" >/tmp/hwlab-tools-image-inspect.json 2>/tmp/hwlab-tools-image-inspect.err; then",
    "  exists=true",
    "  image_id=$(docker image inspect \"$image\" --format '{{.Id}}' 2>/dev/null || true)",
    "  created=$(docker image inspect \"$image\" --format '{{.Created}}' 2>/dev/null || true)",
    "  size=$(docker image inspect \"$image\" --format '{{.Size}}' 2>/dev/null || true)",
    "  node_version=$(docker run --rm \"$image\" node --version 2>/dev/null || true)",
    "  npm_version=$(docker run --rm \"$image\" npm --version 2>/dev/null || true)",
    "  bun_version=$(docker run --rm \"$image\" bun --version 2>/dev/null || true)",
    "  git_version=$(docker run --rm \"$image\" git --version 2>/dev/null || true)",
    "  docker_version=$(docker run --rm \"$image\" docker --version 2>/dev/null || true)",
    "  python_version=$(docker run --rm \"$image\" python3 --version 2>/dev/null || true)",
    "fi",
    `registry_tags=$(curl -fsS --max-time 10 http://127.0.0.1:5000/v2/hwlab/hwlab-ci-node-tools/tags/list 2>/dev/null || true)`,
    "export image exists image_id created size node_version npm_version bun_version git_version docker_version python_version registry_tags",
    "node - <<'NODE'",
    "const fs = require('node:fs');",
    "const env = process.env;",
    "const payload = {",
    "  image: env.image,",
    "  exists: env.exists === 'true',",
    "  imageId: env.image_id || null,",
    "  created: env.created || null,",
    "  sizeBytes: env.size ? Number(env.size) : null,",
    "  tools: {",
    "    node: env.node_version || null,",
    "    npm: env.npm_version || null,",
    "    bun: env.bun_version || null,",
    "    git: env.git_version || null,",
    "    docker: env.docker_version || null,",
    "    python: env.python_version || null",
    "  },",
    "  registryTagsRaw: env.registry_tags || null",
    "};",
    "console.log(JSON.stringify(payload, null, 2));",
    "NODE",
  ].join("\n");
  const result = g14HostScript(script, 180_000);
  let parsedStatus: unknown = null;
  const text = statusText(result);
  if (text.length > 0) {
    try {
      parsedStatus = JSON.parse(text) as unknown;
    } catch {
      parsedStatus = null;
    }
  }
  return {
    ok: isCommandSuccess(result) && record(parsedStatus).exists === true,
    command: "hwlab g14 tools-image status --name ci-node-tools",
    name: options.name,
    image,
    status: parsedStatus ?? text,
    result,
  };
}

export function runG14ToolsImageBuild(options: G14ToolsImageOptions): Record<string, unknown> {
  const image = g14CiToolsImage(options.tag);
  const script = [
    "set -eu",
    `cd ${shellQuote(V02_WORKSPACE)}`,
    "git fetch origin v0.2 --prune",
    "git checkout v0.2 >/dev/null 2>&1 || true",
    "git merge --ff-only origin/v0.2",
    `test -f ${shellQuote(options.dockerfile)}`,
    `image=${shellQuote(image)}`,
    `dockerfile=${shellQuote(options.dockerfile)}`,
    "echo \"{\\\"phase\\\":\\\"preflight\\\",\\\"image\\\":\\\"$image\\\",\\\"dockerfile\\\":\\\"$dockerfile\\\",\\\"commit\\\":\\\"$(git rev-parse HEAD)\\\"}\"",
    "export HTTP_PROXY=http://127.0.0.1:10808 HTTPS_PROXY=http://127.0.0.1:10808 http_proxy=http://127.0.0.1:10808 https_proxy=http://127.0.0.1:10808",
    "export NO_PROXY=localhost,127.0.0.1,::1,host.docker.internal,74.48.78.17,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,10.42.0.0/16,10.43.0.0/16,.svc,.svc.cluster.local,.cluster.local,kubernetes,kubernetes.default,kubernetes.default.svc,127.0.0.1:5000,localhost:5000",
    "export no_proxy=$NO_PROXY",
    "docker build --pull --build-arg HTTP_PROXY --build-arg HTTPS_PROXY --build-arg http_proxy --build-arg https_proxy --build-arg NO_PROXY --build-arg no_proxy -f \"$dockerfile\" -t \"$image\" .",
    "docker run --rm \"$image\" sh -lc 'node --version && npm --version && bun --version && git --version && python3 --version && docker --version && ssh -V'",
    "docker push \"$image\"",
    "digest=$(docker image inspect \"$image\" --format '{{index .RepoDigests 0}}' 2>/dev/null || true)",
    "echo \"{\\\"phase\\\":\\\"published\\\",\\\"image\\\":\\\"$image\\\",\\\"digest\\\":\\\"$digest\\\"}\"",
  ].join("\n");
  if (options.dryRun) {
    return {
      ok: true,
      command: "hwlab g14 tools-image build --name ci-node-tools",
      mode: "dry-run",
      image,
      workspace: V02_WORKSPACE,
      dockerfile: options.dockerfile,
      buildScriptPreview: script.split(/\n/u),
      next: { build: `bun scripts/cli.ts hwlab g14 tools-image build --name ci-node-tools --tag ${options.tag} --confirm` },
    };
  }
  const result = g14HostScript(script, options.timeoutSeconds * 1000);
  return {
    ok: isCommandSuccess(result),
    command: "hwlab g14 tools-image build --name ci-node-tools",
    mode: "confirmed-build",
    image,
    workspace: V02_WORKSPACE,
    dockerfile: options.dockerfile,
    result,
    status: runG14ToolsImageStatus({ ...options, action: "status", dryRun: true, confirm: false }),
  };
}

export function runG14ToolsImage(options: G14ToolsImageOptions): Record<string, unknown> {
  if (options.action === "status") return runG14ToolsImageStatus(options);
  return runG14ToolsImageBuild(options);
}

export function g14UpstreamImageTarget(options: G14UpstreamImageOptions): string {
  return `${V02_REGISTRY_PREFIX}/${options.name}:${options.tag}`;
}

export function g14UpstreamImageSource(options: G14UpstreamImageOptions): string {
  if (options.name === "openfga") return `docker.io/openfga/openfga:${options.tag}`;
  return `${options.name}:${options.tag}`;
}

export function runG14UpstreamImageStatus(options: G14UpstreamImageOptions): Record<string, unknown> {
  const sourceImage = g14UpstreamImageSource(options);
  const targetImage = g14UpstreamImageTarget(options);
  const script = [
    "set +e",
    `source_image=${shellQuote(sourceImage)}`,
    `target_image=${shellQuote(targetImage)}`,
    `repo_path=${shellQuote(`hwlab/${options.name}`)}`,
    `tag=${shellQuote(options.tag)}`,
    "local_id=$(docker image inspect \"$target_image\" --format '{{.Id}}' 2>/dev/null || true)",
    "local_created=$(docker image inspect \"$target_image\" --format '{{.Created}}' 2>/dev/null || true)",
    "registry_tags=$(curl -fsS --max-time 10 \"http://127.0.0.1:5000/v2/$repo_path/tags/list\" 2>/dev/null || true)",
    "registry_has_tag=false",
    "if printf '%s' \"$registry_tags\" | grep -F '\"'$tag'\"' >/dev/null 2>&1; then registry_has_tag=true; fi",
    "export source_image target_image local_id local_created registry_tags registry_has_tag",
    "node <<'NODE'",
    "const env = process.env;",
    "console.log(JSON.stringify({",
    "  sourceImage: env.source_image,",
    "  targetImage: env.target_image,",
    "  localExists: Boolean(env.local_id),",
    "  localImageId: env.local_id || null,",
    "  localCreated: env.local_created || null,",
    "  registryHasTag: env.registry_has_tag === 'true',",
    "  registryTagsRaw: env.registry_tags || null",
    "}, null, 2));",
    "NODE",
  ].join("\n");
  const result = g14HostScript(script, 120_000);
  let parsedStatus: unknown = null;
  const text = statusText(result);
  if (text.length > 0) {
    try {
      parsedStatus = JSON.parse(text) as unknown;
    } catch {
      parsedStatus = null;
    }
  }
  return {
    ok: isCommandSuccess(result) && record(parsedStatus).registryHasTag === true,
    command: "hwlab g14 upstream-image status --name openfga",
    name: options.name,
    tag: options.tag,
    sourceImage,
    targetImage,
    status: parsedStatus ?? text,
    result,
  };
}

export function runG14UpstreamImageEnsure(options: G14UpstreamImageOptions): Record<string, unknown> {
  const sourceImage = g14UpstreamImageSource(options);
  const targetImage = g14UpstreamImageTarget(options);
  if (options.dryRun) {
    return {
      ok: true,
      command: "hwlab g14 upstream-image ensure --name openfga",
      mode: "dry-run",
      name: options.name,
      tag: options.tag,
      sourceImage,
      targetImage,
      mutation: false,
      next: { confirm: `bun scripts/cli.ts hwlab g14 upstream-image ensure --name ${options.name} --tag ${options.tag} --confirm` },
    };
  }
  const script = [
    "set -eu",
    `source_image=${shellQuote(sourceImage)}`,
    `target_image=${shellQuote(targetImage)}`,
    "export HTTP_PROXY=http://127.0.0.1:10808 HTTPS_PROXY=http://127.0.0.1:10808 http_proxy=http://127.0.0.1:10808 https_proxy=http://127.0.0.1:10808",
    "export NO_PROXY=localhost,127.0.0.1,::1,host.docker.internal,74.48.78.17,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,10.42.0.0/16,10.43.0.0/16,.svc,.svc.cluster.local,.cluster.local,kubernetes,kubernetes.default,kubernetes.default.svc,127.0.0.1:5000,localhost:5000",
    "export no_proxy=$NO_PROXY",
    "echo \"{\\\"phase\\\":\\\"pull\\\",\\\"sourceImage\\\":\\\"$source_image\\\"}\"",
    "docker pull \"$source_image\"",
    "docker tag \"$source_image\" \"$target_image\"",
    "echo \"{\\\"phase\\\":\\\"push\\\",\\\"targetImage\\\":\\\"$target_image\\\"}\"",
    "docker push \"$target_image\"",
    "digest=$(docker image inspect \"$target_image\" --format '{{index .RepoDigests 0}}' 2>/dev/null || true)",
    "echo \"{\\\"phase\\\":\\\"published\\\",\\\"targetImage\\\":\\\"$target_image\\\",\\\"digest\\\":\\\"$digest\\\"}\"",
  ].join("\n");
  const result = g14HostScript(script, options.timeoutSeconds * 1000);
  const status = runG14UpstreamImageStatus(options);
  return {
    ok: isCommandSuccess(result) && status.ok === true,
    command: "hwlab g14 upstream-image ensure --name openfga",
    mode: "confirmed-ensure",
    name: options.name,
    tag: options.tag,
    sourceImage,
    targetImage,
    mutation: true,
    result,
    status,
  };
}

export function runG14UpstreamImage(options: G14UpstreamImageOptions): Record<string, unknown> {
  if (options.action === "status") return runG14UpstreamImageStatus(options);
  return runG14UpstreamImageEnsure(options);
}
