import { Buffer } from "node:buffer";
import { spawnSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { dirname, isAbsolute, relative, sep } from "node:path";

import type { UniDeskConfig } from "./config";
import { renderMachine } from "./cicd-render";
import type { RenderedCliResult } from "./output";
import { CliInputError } from "./output";
import {
  capture,
  compactCapture,
  assertNoDuplicateYamlMappingKeys,
  parseJsonOutput,
  readYamlRecord,
  resolveRepoPath,
  sha256Fingerprint,
  shQuote,
} from "./platform-infra-ops-library";

type PublicEdgeAction = "plan" | "apply" | "reconcile" | "status";

interface PublicEdgeOptions {
  action: PublicEdgeAction;
  configPath: string;
  targetId: string | null;
  siteId: string | null;
  dryRun: boolean;
  confirm: boolean;
  authorityId: string | null;
  sourceCommit: string | null;
  ancestryFile: string | null;
  full: boolean;
}

interface PublicEdgeDelivery {
  enabled: boolean;
  authorityId: string;
  sourceBranch: string;
  pipelineId: string;
}

export interface PublicEdgeArchiveReconcileInput {
  configPath: string;
  targetId: string;
  authorityId: string;
  sourceCommit: string;
  ancestry: string[];
}

export interface SiteReference {
  id: string;
  configRef: string;
  path: string;
  sourceCommit?: string;
}

export interface ResolvedSiteRoute {
  path: string;
  upstream: string;
  responseHeaderTimeout?: string;
  forwardAuth?: { upstream: string; uri: string };
}

export interface ResolvedSite extends SiteReference {
  hostname: string;
  upstream: string;
  upstreamTlsServerName?: string;
  healthPath: string;
  expectedA: string;
  healthExpectedStatuses?: number[];
  accessPolicy?: {
    allowedMethods: string[];
    basicAuth: {
      sourceRef: string;
      usernameKey: string;
      passwordHashKey: string;
    };
  };
  routes?: ResolvedSiteRoute[];
}

export interface PublicEdgeTarget {
  id: string;
  route: string;
  publicAddress: string;
  listener: {
    httpPort: number;
    httpsPort: number;
    protocols: string[];
  };
  isolation: {
    excludedRoutes: string[];
    preservedUdpPorts: number[];
  };
  runtime: {
    image: string;
    containerName: string;
    workDir: string;
    composePath: string;
    caddyfilePath: string;
    dataDir: string;
    configDir: string;
    statePath: string;
    lockPath: string;
    resourceProtection: {
      cpuShares: number;
      memoryReservation: string;
      memoryLimit: string;
    };
    legacy: {
      containerName: string;
      composePath: string;
      caddyfilePath: string;
    };
    dnsServers: string[];
    responseHeaderTimeoutSeconds: number;
  };
  siteReferences: SiteReference[];
}

interface ResolutionResult {
  sites: ResolvedSite[];
  unresolved: Array<SiteReference & { code: string; detail: string }>;
}

export function publicEdgeHelp(): Record<string, unknown> {
  return {
    ok: true,
    command: "platform-infra public-edge",
    usage: [
      "bun scripts/cli.ts platform-infra public-edge plan --target NC01",
      "bun scripts/cli.ts platform-infra public-edge apply --target NC01 --dry-run",
      "bun scripts/cli.ts platform-infra public-edge status --target NC01",
      "bun scripts/cli.ts platform-infra public-edge status --target NC01 --site superapi",
      "bun scripts/cli.ts platform-infra public-edge status --target NC01 --full",
    ],
    source: "config/platform-infra/public-edge.yaml",
    guarantees: [
      "平台 YAML 只拥有 listener、Caddy runtime 和 site 聚合顺序。",
      "hostname 与 upstream 只从产品 owning YAML 的 configRef/path 解析。",
      "apply 每次重新读取 YAML 与运行面，缺失引用以具名非阻塞 warning 跳过。",
      "交互式 apply 只允许 dry-run；mutation 只接受 immutable master PaC archive reconcile。",
      "站点以 owner managed block 合并，禁止服务或 worktree 整文件强写。",
      "reconcile 使用 host lock 与 source commit ancestor-only CAS，拒绝旧提交和分叉提交。",
      "候选先校验，再原子安装并重建唯一 Caddy，同时记录 redacted provenance。",
      "只有安装或唯一 Caddy 重建失败时回滚；站点探测失败只输出非阻塞 warning。",
    ],
  };
}

export async function runPlatformInfraPublicEdgeCommand(config: UniDeskConfig, args: string[]): Promise<RenderedCliResult> {
  if (args.length === 0 || args.some((arg) => arg === "--help" || arg === "-h")) {
    return renderMachine("platform-infra public-edge", publicEdgeHelp(), "json");
  }
  const options = parseOptions(args);
  const root = readConfig(options.configPath);
  const delivery = readDelivery(root);
  const target = readTarget(root, options.targetId);
  const resolution = resolveSites(target);
  if (options.action === "plan") {
    const result = planResult(options.configPath, target, resolution, "plan");
    return renderMachine("platform-infra public-edge plan", compactPlan(result), "json", result.ok === true);
  }
  if (options.action === "apply") {
    const result = planResult(options.configPath, target, resolution, "dry-run");
    return renderMachine("platform-infra public-edge apply", compactPlan(result), "json", result.ok === true);
  }
  if (options.action === "status") {
    const result = await status(config, options.configPath, delivery, target, resolution);
    const visible = options.siteId !== null
      ? narrowStatusToSite(result, options.siteId)
      : options.full
        ? result
        : compactStatus(result);
    return renderMachine("platform-infra public-edge status", visible, "json", visible.ok === true);
  }
  if (resolution.sites.length === 0) {
    throw inputError("没有可安全渲染的 public-edge 站点", "public-edge-no-resolved-sites", "--config");
  }
  if (options.authorityId !== delivery.authorityId) {
    throw inputError("reconcile authority 与 owning YAML 不一致", "reconcile-authority-mismatch", "--authority");
  }
  if (process.env.UNIDESK_PUBLIC_EDGE_RECONCILE !== "1") {
    throw inputError("reconcile 仅允许 immutable PaC archive helper 调用", "reconcile-automation-required");
  }
  const ancestry = readAncestry(options.ancestryFile, options.sourceCommit);
  const result = await reconcile(config, options.configPath, delivery, target, resolution.sites, options.sourceCommit!, ancestry);
  return renderMachine("platform-infra public-edge reconcile", result, "json", result.ok === true);
}

function parseOptions(args: string[]): PublicEdgeOptions {
  const action = args[0];
  if (action !== "plan" && action !== "apply" && action !== "reconcile" && action !== "status") {
    throw inputError("public-edge action 必须是 plan、apply、reconcile 或 status", "invalid-action", action ?? "<missing>");
  }
  let configPath = resolveRepoPath("config/platform-infra/public-edge.yaml");
  let targetId: string | null = null;
  let siteId: string | null = null;
  let dryRun = false;
  let confirm = false;
  let authorityId: string | null = null;
  let sourceCommit: string | null = null;
  let ancestryFile: string | null = null;
  let full = false;
  for (let index = 1; index < args.length; index += 1) {
    const arg = args[index]!;
    if (arg === "--config" || arg === "--target" || arg === "--site" || arg === "--authority" || arg === "--source-commit" || arg === "--ancestry-file") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw inputError(`${arg} 需要参数`, "missing-option-value", arg);
      if (arg === "--config") configPath = resolveRepoPath(value);
      else if (arg === "--target") targetId = value;
      else if (arg === "--site") siteId = value;
      else if (arg === "--authority") authorityId = value;
      else if (arg === "--source-commit") sourceCommit = value;
      else ancestryFile = value;
      index += 1;
    } else if (arg === "--dry-run") {
      dryRun = true;
    } else if (arg === "--confirm") {
      confirm = true;
    } else if (arg === "--full") {
      full = true;
    } else {
      throw inputError(`不支持的 public-edge 参数：${arg}`, "unsupported-option", arg);
    }
  }
  if (action === "apply") {
    if (confirm) throw inputError("交互式 apply --confirm 已禁用；提交 owning YAML 后由唯一 PaC reconcile", "interactive-mutation-disabled", "--confirm");
    if (!dryRun) throw inputError("apply 只接受 --dry-run", "apply-dry-run-required");
  } else if (action === "reconcile") {
    if (!confirm || dryRun) throw inputError("reconcile 必须使用 --confirm", "reconcile-confirm-required");
    if (authorityId === null || sourceCommit === null || ancestryFile === null) {
      throw inputError("reconcile 缺少 --authority、--source-commit 或 --ancestry-file", "reconcile-provenance-required");
    }
    if (!/^[0-9a-f]{40}$/u.test(sourceCommit)) throw inputError("--source-commit 必须是 40 位 commit", "invalid-source-commit");
  } else if (dryRun || confirm || authorityId !== null || sourceCommit !== null || ancestryFile !== null) {
    throw inputError(`${action} 不接受 mutation/provenance 参数`, "mutation-option-not-allowed");
  }
  if (siteId !== null && action !== "status") {
    throw inputError("--site 只适用于 status", "site-filter-not-allowed", "--site");
  }
  if (full && action !== "status") {
    throw inputError("--full 只适用于 status", "full-disclosure-not-allowed", "--full");
  }
  return { action, configPath, targetId, siteId, dryRun, confirm, authorityId, sourceCommit, ancestryFile, full };
}

function readConfig(configPath: string): Record<string, unknown> {
  if (!existsSync(configPath)) throw inputError(`找不到 owning YAML：${configPath}`, "config-not-found", "--config");
  return readYamlRecord(configPath, "platform-infra-public-edge");
}

function readDelivery(root: Record<string, unknown>): PublicEdgeDelivery {
  const delivery = record(root.delivery, "delivery");
  const parsed = {
    enabled: boolean(delivery.enabled, "delivery.enabled"),
    authorityId: string(delivery.authorityId, "delivery.authorityId"),
    sourceBranch: string(delivery.sourceBranch, "delivery.sourceBranch"),
    pipelineId: string(delivery.pipelineId, "delivery.pipelineId"),
  };
  if (!parsed.enabled) throw inputError("delivery.enabled 必须为 true", "delivery-disabled", "delivery.enabled");
  return parsed;
}

function readTarget(root: Record<string, unknown>, requestedTargetId: string | null): PublicEdgeTarget {
  const defaults = record(root.defaults, "defaults");
  const targets = record(root.targets, "targets");
  const targetId = requestedTargetId ?? string(defaults.targetId, "defaults.targetId");
  const target = record(targets[targetId], `targets.${targetId}`);
  const listener = record(target.listener, `targets.${targetId}.listener`);
  const isolation = record(target.isolation, `targets.${targetId}.isolation`);
  const runtime = record(target.runtime, `targets.${targetId}.runtime`);
  const resourceProtection = record(runtime.resourceProtection, `targets.${targetId}.runtime.resourceProtection`);
  const legacy = record(runtime.legacy, `targets.${targetId}.runtime.legacy`);
  const sites = array(target.sites, `targets.${targetId}.sites`);
  const parsed: PublicEdgeTarget = {
    id: targetId,
    route: string(target.route, `targets.${targetId}.route`),
    publicAddress: ipv4(target.publicAddress, `targets.${targetId}.publicAddress`),
    listener: {
      httpPort: port(listener.httpPort, `targets.${targetId}.listener.httpPort`),
      httpsPort: port(listener.httpsPort, `targets.${targetId}.listener.httpsPort`),
      protocols: stringArray(listener.protocols, `targets.${targetId}.listener.protocols`),
    },
    isolation: {
      excludedRoutes: stringArray(isolation.excludedRoutes, `targets.${targetId}.isolation.excludedRoutes`),
      preservedUdpPorts: portArray(isolation.preservedUdpPorts, `targets.${targetId}.isolation.preservedUdpPorts`),
    },
    runtime: {
      image: string(runtime.image, `targets.${targetId}.runtime.image`),
      containerName: string(runtime.containerName, `targets.${targetId}.runtime.containerName`),
      workDir: absolutePath(runtime.workDir, `targets.${targetId}.runtime.workDir`),
      composePath: absolutePath(runtime.composePath, `targets.${targetId}.runtime.composePath`),
      caddyfilePath: absolutePath(runtime.caddyfilePath, `targets.${targetId}.runtime.caddyfilePath`),
      dataDir: absolutePath(runtime.dataDir, `targets.${targetId}.runtime.dataDir`),
      configDir: absolutePath(runtime.configDir, `targets.${targetId}.runtime.configDir`),
      statePath: absolutePath(runtime.statePath, `targets.${targetId}.runtime.statePath`),
      lockPath: absolutePath(runtime.lockPath, `targets.${targetId}.runtime.lockPath`),
      resourceProtection: {
        cpuShares: positiveInteger(resourceProtection.cpuShares, `targets.${targetId}.runtime.resourceProtection.cpuShares`),
        memoryReservation: dockerMemory(resourceProtection.memoryReservation, `targets.${targetId}.runtime.resourceProtection.memoryReservation`),
        memoryLimit: dockerMemory(resourceProtection.memoryLimit, `targets.${targetId}.runtime.resourceProtection.memoryLimit`),
      },
      legacy: {
        containerName: string(legacy.containerName, `targets.${targetId}.runtime.legacy.containerName`),
        composePath: absolutePath(legacy.composePath, `targets.${targetId}.runtime.legacy.composePath`),
        caddyfilePath: absolutePath(legacy.caddyfilePath, `targets.${targetId}.runtime.legacy.caddyfilePath`),
      },
      dnsServers: array(runtime.dnsServers, `targets.${targetId}.runtime.dnsServers`).map((value, index) => ipv4(value, `targets.${targetId}.runtime.dnsServers[${index}]`)),
      responseHeaderTimeoutSeconds: positiveInteger(runtime.responseHeaderTimeoutSeconds, `targets.${targetId}.runtime.responseHeaderTimeoutSeconds`),
    },
    siteReferences: sites.map((value, index) => {
      const site = record(value, `targets.${targetId}.sites[${index}]`);
      return {
        id: string(site.id, `targets.${targetId}.sites[${index}].id`),
        configRef: yamlConfigPath(site.configRef, `targets.${targetId}.sites[${index}].configRef`),
        path: string(site.path, `targets.${targetId}.sites[${index}].path`),
        ...(site.sourceCommit === undefined
          ? {}
          : { sourceCommit: gitCommit(site.sourceCommit, `targets.${targetId}.sites[${index}].sourceCommit`) }),
      };
    }),
  };
  if (dockerMemoryBytes(parsed.runtime.resourceProtection.memoryReservation) > dockerMemoryBytes(parsed.runtime.resourceProtection.memoryLimit)) {
    throw inputError(`targets.${targetId}.runtime.resourceProtection.memoryReservation 不得大于 memoryLimit`, "invalid-resource-protection", `targets.${targetId}.runtime.resourceProtection`);
  }
  const routeId = parsed.route.split(":", 1)[0]!;
  if (parsed.isolation.excludedRoutes.includes(routeId) || parsed.isolation.excludedRoutes.includes(parsed.id)) {
    throw inputError(`target route 命中 excludedRoutes：${parsed.route}`, "excluded-target-route", `targets.${targetId}.route`);
  }
  if (parsed.listener.protocols.includes("h3") && parsed.isolation.preservedUdpPorts.includes(parsed.listener.httpsPort)) {
    throw inputError(`h3 会抢占保留 UDP 端口 ${parsed.listener.httpsPort}`, "preserved-udp-port-conflict", `targets.${targetId}.listener.protocols`);
  }
  return parsed;
}

export function resolveSites(target: PublicEdgeTarget): ResolutionResult {
  const sites: ResolvedSite[] = [];
  const unresolved: ResolutionResult["unresolved"] = [];
  const hostnames = new Map<string, string>();
  for (const reference of target.siteReferences) {
    try {
      const ownerPath = reference.configRef.startsWith("/")
        ? reference.configRef
        : resolveRepoPath(reference.configRef);
      const owner = resolveObjectPath(readSiteOwner(reference, ownerPath), reference.path);
      const exposure = exposureObject(owner);
      const dns = optionalRecord(exposure.dns);
      const label = `${reference.configRef}#${reference.path}`;
      let publicBaseUrlHostname: string | null = null;
      if (exposure.publicBaseUrl !== undefined) {
        const publicBaseUrl = string(exposure.publicBaseUrl, `${label}.publicBaseUrl`);
        const url = new URL(publicBaseUrl);
        if (url.protocol !== "https:") throw new Error(`publicBaseUrl 必须使用 https：${publicBaseUrl}`);
        publicBaseUrlHostname = hostnameValue(url.hostname, `${label}.publicBaseUrl`);
      }
      const hostname = hostnameValue(exposure.hostname ?? dns?.hostname ?? publicBaseUrlHostname, `${label}.hostname`);
      if (publicBaseUrlHostname !== null && publicBaseUrlHostname !== hostname) {
        throw new Error(`publicBaseUrl hostname 与 hostname 不一致：${publicBaseUrlHostname} != ${hostname}`);
      }
      const expectedA = ipv4(dns?.expectedA ?? exposure.expectedA, `${reference.configRef}#${reference.path}.expectedA`);
      if (expectedA !== target.publicAddress) throw new Error(`expectedA 尚未迁移到 ${target.publicAddress}，当前为 ${expectedA}`);
      const upstream = resolveUpstream(exposure, label);
      const upstreamTlsServerName = exposure.upstreamTlsServerName === undefined
        ? undefined
        : hostnameValue(exposure.upstreamTlsServerName, `${label}.upstreamTlsServerName`);
      if (upstreamTlsServerName !== undefined && !upstream.startsWith("https://")) {
        throw new Error(`${label}.upstreamTlsServerName 仅允许 HTTPS upstream`);
      }
      const healthPath = resolveHealthPath(owner, exposure, label);
      const healthExpectedStatuses = resolveHealthExpectedStatuses(exposure, label);
      const accessPolicy = resolveAccessPolicy(owner, exposure, label);
      const routes = resolveSiteRoutes(exposure, label);
      const previous = hostnames.get(hostname);
      if (previous !== undefined) throw new Error(`hostname 与 site ${previous} 重复：${hostname}`);
      hostnames.set(hostname, reference.id);
      sites.push({
        ...reference,
        hostname,
        upstream,
        upstreamTlsServerName,
        healthPath,
        expectedA,
        ...(healthExpectedStatuses === undefined ? {} : { healthExpectedStatuses }),
        ...(accessPolicy === undefined ? {} : { accessPolicy }),
        ...(routes === undefined ? {} : { routes }),
      });
    } catch (error) {
      unresolved.push({ ...reference, code: "config-ref-unresolved", detail: error instanceof Error ? error.message : String(error) });
    }
  }
  return { sites, unresolved };
}

function resolveHealthExpectedStatuses(exposure: Record<string, unknown>, label: string): number[] | undefined {
  if (exposure.healthExpectedStatuses === undefined) return undefined;
  const statuses = array(exposure.healthExpectedStatuses, `${label}.healthExpectedStatuses`).map((value, index) => {
    if (!Number.isInteger(value) || Number(value) < 100 || Number(value) > 599) {
      throw new Error(`${label}.healthExpectedStatuses[${index}] 必须是 HTTP status`);
    }
    return Number(value);
  });
  if (statuses.length === 0) throw new Error(`${label}.healthExpectedStatuses 不能为空`);
  return [...new Set(statuses)];
}

function resolveAccessPolicy(
  owner: Record<string, unknown>,
  exposure: Record<string, unknown>,
  label: string,
): ResolvedSite["accessPolicy"] {
  if (exposure.accessPolicy === undefined) return undefined;
  const policy = record(exposure.accessPolicy, `${label}.accessPolicy`);
  const allowedMethods = stringArray(policy.allowedMethods, `${label}.accessPolicy.allowedMethods`);
  if (allowedMethods.length === 0 || allowedMethods.some((method) => !/^[A-Z]+$/u.test(method))) {
    throw new Error(`${label}.accessPolicy.allowedMethods 必须是非空大写 HTTP method 列表`);
  }
  const auth = record(owner.auth, `${label}.auth`);
  return {
    allowedMethods: [...new Set(allowedMethods)],
    basicAuth: {
      sourceRef: absolutePath(auth.sourceRef, `${label}.auth.sourceRef`),
      usernameKey: envName(auth.usernameKey, `${label}.auth.usernameKey`),
      passwordHashKey: envName(auth.passwordHashKey, `${label}.auth.passwordHashKey`),
    },
  };
}

function readSiteOwner(reference: SiteReference, ownerPath: string): Record<string, unknown> {
  if (!isAbsolute(reference.configRef)) {
    if (reference.sourceCommit !== undefined) throw new Error(`仓库内 configRef 不接受 sourceCommit：${reference.configRef}`);
    if (!existsSync(ownerPath)) throw new Error(`configRef 文件不存在：${reference.configRef}`);
    return readYamlRecord(ownerPath);
  }
  if (reference.sourceCommit === undefined) {
    throw new Error(`绝对 configRef 必须声明 sourceCommit：${reference.configRef}`);
  }
  const repository = spawnSync("git", ["-C", dirname(ownerPath), "rev-parse", "--show-toplevel"], {
    encoding: "utf8",
    timeout: 10_000,
  });
  const repositoryRoot = repository.status === 0 ? repository.stdout.trim() : "";
  if (!isAbsolute(repositoryRoot)) throw new Error(`外部 configRef 不在可读 Git 仓库：${reference.configRef}`);
  const repositoryPath = relative(repositoryRoot, ownerPath);
  if (repositoryPath.length === 0 || repositoryPath === ".." || repositoryPath.startsWith(`..${sep}`) || isAbsolute(repositoryPath)) {
    throw new Error(`外部 configRef 不属于解析出的 Git 仓库：${reference.configRef}`);
  }
  const gitPath = repositoryPath.split(sep).join("/");
  const source = spawnSync("git", ["-C", repositoryRoot, "show", `${reference.sourceCommit}:${gitPath}`], {
    encoding: "utf8",
    timeout: 10_000,
    maxBuffer: 4 * 1024 * 1024,
  });
  if (source.status !== 0) {
    throw new Error(`外部 configRef 无法从 pinned commit 读取：${reference.configRef}@${reference.sourceCommit}`);
  }
  assertNoDuplicateYamlMappingKeys(source.stdout, `${reference.configRef}@${reference.sourceCommit}`);
  return record(Bun.YAML.parse(source.stdout) as unknown, `${reference.configRef}@${reference.sourceCommit}`);
}

function resolveObjectPath(root: unknown, path: string): Record<string, unknown> {
  let value: unknown = root;
  for (const segment of path.split(".")) {
    const match = /^([A-Za-z0-9_-]+)(?:\[id=([A-Za-z0-9_-]+)\])?$/u.exec(segment);
    if (match === null) throw new Error(`path segment 不合法：${segment}`);
    const key = match[1]!;
    value = record(value, path)[key];
    if (match[2] !== undefined) {
      const values = array(value, `${path}.${key}`);
      value = values.find((item) => optionalRecord(item)?.id === match[2]);
      if (value === undefined) throw new Error(`path 未找到 id=${match[2]}：${path}`);
    }
    if (value === undefined) throw new Error(`path 不存在：${path}`);
  }
  return record(value, path);
}

function exposureObject(owner: Record<string, unknown>): Record<string, unknown> {
  if (optionalRecord(owner.publicExposure) !== null) return record(owner.publicExposure, "publicExposure");
  if (optionalRecord(owner.exposure) !== null) return record(owner.exposure, "exposure");
  return owner;
}

function resolveUpstream(exposure: Record<string, unknown>, label: string): string {
  if (typeof exposure.upstream === "string") return upstreamValue(exposure.upstream, `${label}.upstream`);
  const upstream = optionalRecord(exposure.upstream);
  if (upstream !== null) return upstreamValue(`${string(upstream.host, `${label}.upstream.host`)}:${port(upstream.port, `${label}.upstream.port`)}`, `${label}.upstream`);
  return upstreamValue(`${string(exposure.hostIP, `${label}.hostIP`)}:${port(exposure.port, `${label}.port`)}`, `${label}.upstream`);
}

function resolveHealthPath(owner: Record<string, unknown>, exposure: Record<string, unknown>, label: string): string {
  if (exposure.healthPath !== undefined) return httpPath(exposure.healthPath, `${label}.healthPath`);
  const exposureProbes = optionalRecord(exposure.probes);
  if (exposureProbes !== null && exposureProbes.healthPath !== undefined) return httpPath(exposureProbes.healthPath, `${label}.probes.healthPath`);
  const probes = optionalRecord(owner.probes);
  if (probes !== null) {
    if (probes.healthPath !== undefined) return httpPath(probes.healthPath, `${label}.probes.healthPath`);
    const web = optionalRecord(probes.web);
    if (web !== null && web.livenessPath !== undefined) return httpPath(web.livenessPath, `${label}.probes.web.livenessPath`);
  }
  throw new Error(`${label} 缺少 probes.healthPath 或 probes.web.livenessPath`);
}

function resolveSiteRoutes(exposure: Record<string, unknown>, label: string): ResolvedSiteRoute[] | undefined {
  if (exposure.routes === undefined) return undefined;
  const routes = array(exposure.routes, `${label}.routes`).map((value, index) => {
    const route = record(value, `${label}.routes[${index}]`);
    const path = route.path === "*" ? "*" : httpPath(route.path, `${label}.routes[${index}].path`);
    const forwardAuth = optionalRecord(route.forwardAuth);
    return {
      path,
      upstream: upstreamValue(route.upstream, `${label}.routes[${index}].upstream`),
      ...(route.responseHeaderTimeout === undefined
        ? {}
        : { responseHeaderTimeout: duration(route.responseHeaderTimeout, `${label}.routes[${index}].responseHeaderTimeout`) }),
      ...(forwardAuth === null
        ? {}
        : {
          forwardAuth: {
            upstream: upstreamValue(forwardAuth.upstream, `${label}.routes[${index}].forwardAuth.upstream`),
            uri: httpPath(forwardAuth.uri, `${label}.routes[${index}].forwardAuth.uri`),
          },
        }),
    };
  });
  if (routes.at(-1)?.path !== "*") throw new Error(`${label}.routes 最后一项必须是 * fallback`);
  const seen = new Set<string>();
  for (const route of routes) {
    if (seen.has(route.path)) throw new Error(`${label}.routes path 重复：${route.path}`);
    seen.add(route.path);
  }
  return routes;
}

function planResult(configPath: string, target: PublicEdgeTarget, resolution: ResolutionResult, mode: string): Record<string, unknown> & { ok: boolean } {
  const complete = resolution.unresolved.length === 0;
  const rendered = renderPublicEdgeArtifacts(target, resolution.sites);
  return {
    ok: true,
    action: "platform-infra-public-edge-plan",
    mode,
    mutation: false,
    configRef: `${configPath}#targets.${target.id}`,
    target: targetSummary(target),
    sites: resolution.sites,
    unresolved: resolution.unresolved,
    warnings: resolution.unresolved.map((item) => ({ ...item, level: "warning", blocking: false })),
    complete,
    rendered: {
      desiredSourceCommit: checkoutSourceCommit(),
      caddyfileFingerprint: sha256Fingerprint(rendered.caddyfile),
      composeFingerprint: sha256Fingerprint(rendered.compose),
      siteCount: resolution.sites.length,
    },
    valuesPrinted: false,
  };
}

async function reconcile(
  config: UniDeskConfig,
  configPath: string,
  delivery: PublicEdgeDelivery,
  target: PublicEdgeTarget,
  sites: ResolvedSite[],
  sourceCommit: string,
  ancestry: string[],
): Promise<Record<string, unknown>> {
  const artifacts = renderPublicEdgeArtifacts(target, sites);
  const result = await capture(
    config,
    target.route,
    ["sh"],
    applyScript(target, sites, artifacts, { authorityId: delivery.authorityId, sourceCommit, ancestry }),
    { runtimeTimeoutMs: 120_000 },
  );
  const runtime = parseJsonOutput(result.stdout) ?? { ok: false, capture: compactCapture(result, { full: true }) };
  return {
    ok: result.exitCode === 0 && runtime.ok !== false,
    action: "platform-infra-public-edge-reconcile",
    mutation: result.exitCode === 0 && runtime.ok !== false && runtime.mutation === true,
    authority: { id: delivery.authorityId, sourceBranch: delivery.sourceBranch, pipelineId: delivery.pipelineId },
    sourceCommit,
    configRef: `${configPath}#targets.${target.id}`,
    target: targetSummary(target),
    sites,
    runtime,
    valuesPrinted: false,
  };
}

export function buildPublicEdgeArchiveReconcile(input: PublicEdgeArchiveReconcileInput): {
  script: string;
  authorityId: string;
  sourceCommit: string;
  targetId: string;
  siteCount: number;
} {
  const root = readConfig(input.configPath);
  const delivery = readDelivery(root);
  if (input.authorityId !== delivery.authorityId) {
    throw inputError("reconcile authority 与 owning YAML 不一致", "reconcile-authority-mismatch", "--authority");
  }
  if (!/^[0-9a-f]{40}$/u.test(input.sourceCommit)) {
    throw inputError("source commit 必须是 40 位 commit", "invalid-source-commit", "--source-commit");
  }
  if (
    input.ancestry.length === 0
    || input.ancestry.some((value) => !/^[0-9a-f]{40}$/u.test(value))
    || !input.ancestry.includes(input.sourceCommit)
  ) {
    throw inputError("archive ancestry proof 无效", "reconcile-ancestry-invalid", "--ancestry-file");
  }
  const target = readTarget(root, input.targetId);
  const resolution = resolveSites(target);
  if (resolution.sites.length === 0) {
    throw inputError("没有可安全渲染的 public-edge 站点", "public-edge-no-resolved-sites", "--config");
  }
  const artifacts = renderPublicEdgeArtifacts(target, resolution.sites);
  return {
    script: applyScript(target, resolution.sites, artifacts, {
      authorityId: delivery.authorityId,
      sourceCommit: input.sourceCommit,
      ancestry: input.ancestry,
    }),
    authorityId: delivery.authorityId,
    sourceCommit: input.sourceCommit,
    targetId: target.id,
    siteCount: resolution.sites.length,
  };
}

async function status(
  config: UniDeskConfig,
  configPath: string,
  delivery: PublicEdgeDelivery,
  target: PublicEdgeTarget,
  resolution: ResolutionResult,
): Promise<Record<string, unknown>> {
  const artifacts = renderPublicEdgeArtifacts(target, resolution.sites);
  const desiredSourceCommit = checkoutSourceCommit();
  const result = await capture(
    config,
    target.route,
    ["sh"],
    renderPublicEdgeStatusScript(
      target,
      resolution.sites,
      artifacts.caddyfile,
      artifacts.compose,
      desiredSourceCommit,
      delivery.authorityId,
    ),
  );
  const runtime = parseJsonOutput(result.stdout) ?? { ok: false, capture: compactCapture(result, { full: true }) };
  const provenance = optionalRecord(runtime.provenance);
  const installed = optionalRecord(provenance?.installed);
  const installedSourceCommit = typeof installed?.sourceCommit === "string" ? installed.sourceCommit : null;
  const sourceRelation = classifyPublicEdgeSourceRelation(installedSourceCommit, desiredSourceCommit);
  const sourceAcceptable = sourceRelation === "same" || sourceRelation === "installed-ancestor";
  if (provenance !== null) {
    provenance.sourceRelation = sourceRelation;
    provenance.sourceAcceptable = sourceAcceptable;
  }
  runtime.ok = result.exitCode === 0 && runtime.ok !== false && sourceAcceptable;
  const ok = runtime.ok === true;
  return {
    ok,
    action: "platform-infra-public-edge-status",
    mutation: false,
    authority: { id: delivery.authorityId, sourceBranch: delivery.sourceBranch, pipelineId: delivery.pipelineId },
    configRef: `${configPath}#targets.${target.id}`,
    target: targetSummary(target),
    sites: resolution.sites,
    unresolved: resolution.unresolved,
    warnings: resolution.unresolved.map((item) => ({ ...item, level: "warning", blocking: false })),
    complete: resolution.unresolved.length === 0,
    runtime,
    valuesPrinted: false,
  };
}

function narrowStatusToSite(result: Record<string, unknown>, siteId: string): Record<string, unknown> {
  const sites = Array.isArray(result.sites)
    ? result.sites.filter((item) => optionalRecord(item)?.id === siteId)
    : [];
  const unresolved = Array.isArray(result.unresolved)
    ? result.unresolved.filter((item) => optionalRecord(item)?.id === siteId)
    : [];
  const runtime = optionalRecord(result.runtime) ?? {};
  const narrowCheck = (value: unknown): Record<string, unknown> => {
    const check = optionalRecord(value) ?? {};
    const failures = Array.isArray(check.failures)
      ? check.failures.filter((item) => optionalRecord(item)?.siteId === siteId)
      : [];
    return { ...check, exitCode: failures.length === 0 ? 0 : 1, failures };
  };
  const dns = narrowCheck(runtime.dns);
  dns.blocking = false;
  const siteProbes = narrowCheck(runtime.siteProbes);
  const exitCode = (value: unknown): number | null => {
    const parsed = optionalRecord(value)?.exitCode;
    return typeof parsed === "number" ? parsed : null;
  };
  const legacyRetired = optionalRecord(runtime.legacyContainer)?.retired === true;
  const configCurrent = optionalRecord(runtime.config)?.matchesDesired === true;
  const sourceAcceptable = optionalRecord(runtime.provenance)?.sourceAcceptable === true;
  const runtimeOk = ["container", "tcpListeners", "preservedUdpListeners", "validate"]
    .every((key) => exitCode(runtime[key]) === 0)
    && exitCode(siteProbes) === 0
    && legacyRetired
    && configCurrent
    && sourceAcceptable;
  const visibleRuntime = { ...runtime, ok: runtimeOk, dns, siteProbes };
  return {
    ...result,
    ok: runtimeOk,
    siteFilter: siteId,
    sites,
    unresolved,
    warnings: unresolved.map((item) => ({ ...record(item, "unresolved"), level: "warning", blocking: false })),
    complete: sites.length === 1 && unresolved.length === 0,
    runtime: visibleRuntime,
  };
}

function compactStatus(result: Record<string, unknown>): Record<string, unknown> {
  const runtime = optionalRecord(result.runtime) ?? {};
  const target = optionalRecord(result.target) ?? {};
  const authority = optionalRecord(result.authority) ?? {};
  const provenance = optionalRecord(runtime.provenance) ?? {};
  const installed = optionalRecord(provenance.installed) ?? {};
  const config = optionalRecord(runtime.config) ?? {};
  const dns = optionalRecord(runtime.dns) ?? {};
  const probes = optionalRecord(runtime.siteProbes) ?? {};
  const sites = Array.isArray(result.sites) ? result.sites : [];
  const unresolved = Array.isArray(result.unresolved) ? result.unresolved : [];
  const dnsFailures = Array.isArray(dns.failures) ? dns.failures : [];
  const probeFailures = Array.isArray(probes.failures) ? probes.failures : [];
  const declaredWarnings = Array.isArray(result.warnings) ? result.warnings : [];
  const warnings = [...declaredWarnings, ...dnsFailures];
  const listenerPorts = Array.isArray(target.listeners) ? target.listeners : [];
  const check = (key: string): { ok: boolean; exitCode: number | null } => {
    const exitCode = optionalRecord(runtime[key])?.exitCode;
    return { ok: exitCode === 0, exitCode: typeof exitCode === "number" ? exitCode : null };
  };
  return {
    ok: result.ok === true,
    action: result.action,
    mutation: false,
    target: {
      id: target.id ?? null,
      publicAddress: target.publicAddress ?? null,
      containerName: target.containerName ?? null,
      endpoints: listenerPorts.map((port) => ({
        scheme: port === 443 ? "https" : port === 80 ? "http" : "tcp",
        port,
        listenerReady: check("tcpListeners").ok,
      })),
    },
    authority: {
      id: authority.id ?? null,
      sourceBranch: authority.sourceBranch ?? null,
      pipelineId: authority.pipelineId ?? null,
    },
    configRef: result.configRef,
    complete: result.complete === true,
    siteSummary: {
      resolved: sites.length,
      unresolved: unresolved.length,
      probeFailures: probeFailures.length,
      dnsWarnings: dnsFailures.length,
    },
    runtime: {
      ok: runtime.ok === true,
      checks: {
        container: check("container"),
        tcpListeners: check("tcpListeners"),
        preservedUdpListeners: check("preservedUdpListeners"),
        caddyValidate: check("validate"),
        legacyRetired: optionalRecord(runtime.legacyContainer)?.retired === true,
        siteProbes: { ok: probes.exitCode === 0, exitCode: typeof probes.exitCode === "number" ? probes.exitCode : null },
      },
      source: {
        installedCommit: installed.sourceCommit ?? null,
        desiredCommit: provenance.desiredSourceCommit ?? null,
        relation: provenance.sourceRelation ?? null,
        acceptable: provenance.sourceAcceptable === true,
        matchesRuntime: provenance.matchesRuntime === true,
      },
      fingerprints: {
        managedConfig: {
          current: config.currentManagedFingerprint ?? null,
          desired: config.desiredManagedFingerprint ?? null,
        },
        compose: {
          current: config.currentComposeFingerprint ?? null,
          desired: config.desiredComposeFingerprint ?? null,
        },
        matchesDesired: config.matchesDesired === true,
      },
    },
    firstFailure: firstStatusFailure(runtime),
    warningCount: warnings.length,
    warning: warnings.length === 0 ? null : compactStatusWarning(warnings[0]),
    next: {
      site: `bun scripts/cli.ts platform-infra public-edge status --target ${String(target.id ?? "NC01")} --site <site-id>`,
      full: `bun scripts/cli.ts platform-infra public-edge status --target ${String(target.id ?? "NC01")} --full`,
    },
    valuesPrinted: false,
  };
}

function compactPlan(result: Record<string, unknown>): Record<string, unknown> {
  const target = optionalRecord(result.target) ?? {};
  const rendered = optionalRecord(result.rendered) ?? {};
  const sites = Array.isArray(result.sites) ? result.sites : [];
  const unresolved = Array.isArray(result.unresolved) ? result.unresolved : [];
  return {
    ok: result.ok === true,
    action: result.action,
    mode: result.mode,
    mutation: false,
    configRef: result.configRef,
    target: {
      id: target.id ?? null,
      route: target.route ?? null,
      publicAddress: target.publicAddress ?? null,
      listeners: target.listeners ?? [],
      containerName: target.containerName ?? null,
      resourceProtection: target.resourceProtection ?? null,
    },
    siteSummary: { resolved: sites.length, unresolved: unresolved.length },
    rendered,
    warning: unresolved.length === 0 ? null : compactStatusWarning(unresolved[0]),
    complete: result.complete === true,
    valuesPrinted: false,
  };
}

function firstStatusFailure(runtime: Record<string, unknown>): Record<string, unknown> | null {
  if (optionalRecord(runtime.capture) !== null) {
    return { stage: "remoteStatus", code: "public-edge-status-capture-failed" };
  }
  const failures: Array<[string, boolean, string]> = [
    ["container", optionalRecord(runtime.container)?.exitCode !== 0, "public-edge-container-not-running"],
    ["legacyContainer", optionalRecord(runtime.legacyContainer)?.retired !== true, "public-edge-legacy-container-active"],
    ["tcpListeners", optionalRecord(runtime.tcpListeners)?.exitCode !== 0, "public-edge-tcp-listener-not-ready"],
    ["preservedUdpListeners", optionalRecord(runtime.preservedUdpListeners)?.exitCode !== 0, "public-edge-preserved-udp-listener-not-ready"],
    ["caddyValidate", optionalRecord(runtime.validate)?.exitCode !== 0, "public-edge-caddy-invalid"],
    ["provenance", optionalRecord(runtime.provenance)?.matchesRuntime !== true, "public-edge-runtime-provenance-mismatch"],
    ["sourceCommit", optionalRecord(runtime.provenance)?.sourceAcceptable !== true, "public-edge-source-commit-unacceptable"],
    ["config", optionalRecord(runtime.config)?.matchesDesired !== true, "public-edge-config-drift"],
    ["siteProbes", optionalRecord(runtime.siteProbes)?.exitCode !== 0, "public-edge-site-probe-failed"],
  ];
  const failure = failures.find(([, failed]) => failed);
  if (failure === undefined) return null;
  const result: Record<string, unknown> = { stage: failure[0], code: failure[2] };
  if (failure[0] === "siteProbes") {
    const failures = optionalRecord(runtime.siteProbes)?.failures;
    if (Array.isArray(failures) && failures.length > 0) result.site = compactStatusWarning(failures[0]);
  }
  return result;
}

function compactStatusWarning(value: unknown): Record<string, unknown> {
  const warning = optionalRecord(value) ?? {};
  return {
    code: warning.code ?? "public-edge-warning",
    siteId: warning.siteId ?? warning.id ?? null,
    hostname: warning.hostname ?? null,
    path: warning.path ?? null,
    expectedA: warning.expectedA ?? null,
    detail: typeof warning.detail === "string" ? warning.detail.slice(0, 240) : null,
    blocking: warning.blocking === true,
  };
}

export function renderPublicEdgeArtifacts(target: PublicEdgeTarget, sites: ResolvedSite[]): { caddyfile: string; compose: string } {
  const protocols = target.listener.protocols.join(" ");
  const global = renderManagedBlock("public-edge-global", `\{\n\tservers \{\n\t\tprotocols ${protocols}\n\t\}\n\}`);
  const blocks = sites
    .map((site) => renderManagedBlock(`public-edge-site:${site.id}`, renderSiteBlock(site, target.runtime.responseHeaderTimeoutSeconds)))
    .join("\n");
  const dnsServers = target.runtime.dnsServers.map((server) => `      - ${server}`).join("\n");
  const envFiles = [...new Set(sites.flatMap((site) => site.accessPolicy === undefined ? [] : [site.accessPolicy.basicAuth.sourceRef]))];
  const envFileBlock = envFiles.length === 0 ? "" : `    env_file:\n${envFiles.map((path) => `      - ${path}`).join("\n")}\n`;
  const authMaterialFingerprint = envFiles.length === 0
    ? null
    : sha256Fingerprint(envFiles.map((path) => `${path}\n${readFileSync(path, "utf8")}`).join("\n"));
  const authFingerprintBlock = authMaterialFingerprint === null
    ? ""
    : `    environment:\n      UNIDESK_PUBLIC_EDGE_AUTH_MATERIAL_FINGERPRINT: ${authMaterialFingerprint}\n`;
  const compose = `services:\n  caddy:\n    image: ${target.runtime.image}\n    container_name: ${target.runtime.containerName}\n    network_mode: host\n    restart: unless-stopped\n    cpu_shares: ${target.runtime.resourceProtection.cpuShares}\n    mem_reservation: ${target.runtime.resourceProtection.memoryReservation}\n    mem_limit: ${target.runtime.resourceProtection.memoryLimit}\n${envFileBlock}${authFingerprintBlock}    dns:\n${dnsServers}\n    volumes:\n      - ${target.runtime.caddyfilePath}:/etc/caddy/Caddyfile:ro\n      - ${target.runtime.dataDir}:/data\n      - ${target.runtime.configDir}:/config\n`;
  return { caddyfile: `${global}\n${blocks}`, compose };
}

function renderManagedBlock(owner: string, body: string): string {
  return `# BEGIN unidesk managed ${owner}\n${body.trim()}\n# END unidesk managed ${owner}\n`;
}

function renderSiteBlock(site: ResolvedSite, defaultTimeoutSeconds: number): string {
  if (site.routes === undefined) {
    if (site.accessPolicy !== undefined) {
      const deniedMethods = site.accessPolicy.allowedMethods.join(" ");
      const auth = site.accessPolicy.basicAuth;
      return `${site.hostname} \{\n\troute \{\n\t\t@denied not method ${deniedMethods}\n\t\trespond @denied 405\n\t\tbasic_auth \{\n\t\t\t{$${auth.usernameKey}} {$${auth.passwordHashKey}}\n\t\t\}\n${renderReverseProxy(site.upstream, defaultTimeoutSeconds, site.upstreamTlsServerName, 2)}\n\t\}\n\}\n`;
    }
    return `${site.hostname} \{\n${renderReverseProxy(site.upstream, defaultTimeoutSeconds, site.upstreamTlsServerName, 1)}\n\}\n`;
  }
  const routes = site.routes.map((route) => {
    const matcher = route.path === "*" ? "" : ` ${route.path}`;
    const auth = route.forwardAuth === undefined
      ? ""
      : `\t\tforward_auth ${route.forwardAuth.upstream} \{\n\t\t\turi ${route.forwardAuth.uri}\n\t\t\}\n`;
    const timeout = route.responseHeaderTimeout ?? `${defaultTimeoutSeconds}s`;
    return `\thandle${matcher} \{\n${auth}${renderReverseProxy(route.upstream, timeout, undefined, 2, route.forwardAuth !== undefined)}\n\t\}`;
  }).join("\n");
  return `${site.hostname} \{\n${routes}\n\}\n`;
}

function renderReverseProxy(
  upstream: string,
  timeout: number | string,
  tlsServerName: string | undefined,
  indent: number,
  stripAuthorization = false,
): string {
  const tab = "\t".repeat(indent);
  return `${tab}reverse_proxy ${upstream} \{${stripAuthorization ? `\n${tab}\theader_up -Authorization` : ""}
${tab}\ttransport http \{
${tab}\t\tresponse_header_timeout ${typeof timeout === "number" ? `${timeout}s` : timeout}${tlsServerName === undefined ? "" : `\n${tab}\t\ttls_server_name ${tlsServerName}`}
${tab}\t\}
${tab}\}`;
}

export function applyScript(
  target: PublicEdgeTarget,
  sites: ResolvedSite[],
  artifacts: { caddyfile: string; compose: string },
  provenance: { authorityId: string; sourceCommit: string; ancestry: string[] },
): string {
  const caddyfile = Buffer.from(artifacts.caddyfile, "utf8").toString("base64");
  const compose = Buffer.from(artifacts.compose, "utf8").toString("base64");
  const ancestry = Buffer.from(`${provenance.ancestry.join("\n")}\n`, "utf8").toString("base64");
  const desiredCaddyFingerprint = sha256Fingerprint(artifacts.caddyfile);
  const desiredComposeFingerprint = sha256Fingerprint(artifacts.compose);
  const dnsItems = sites.map((site) => shQuote(`${site.hostname}|${site.expectedA}`)).join(" ");
  const probeItems = sites.map((site) => shQuote(`${site.hostname}|${site.healthPath}|${site.healthExpectedStatuses?.join(",") ?? "2xx3xx"}`)).join(" ");
  const authFiles = [...new Set(sites.flatMap((site) => site.accessPolicy === undefined ? [] : [site.accessPolicy.basicAuth.sourceRef]))];
  const authEnvKeys = [...new Set(sites.flatMap((site) => site.accessPolicy === undefined
    ? []
    : [site.accessPolicy.basicAuth.usernameKey, site.accessPolicy.basicAuth.passwordHashKey]))];
  const caddyEnvArgs = authEnvKeys.map((key) => `-e ${shQuote(key)}`).join(" ");
  return `set -u
mkdir -p "$(dirname ${shQuote(target.runtime.lockPath)})"
exec 9>${shQuote(target.runtime.lockPath)}
if ! flock -x 9; then
  printf '%s\\n' '{"ok":false,"mutation":false,"error":"public-edge-lock-failed","valuesPrinted":false}'
  exit 1
fi
tmp="$(mktemp -d)"
caddy_candidate=${shQuote(`${target.runtime.caddyfilePath}.next`)}.$$
compose_candidate=${shQuote(`${target.runtime.composePath}.next`)}.$$
trap 'rm -rf "$tmp"; rm -f "$caddy_candidate" "$compose_candidate"' EXIT
ancestry_file="$tmp/ancestors"
desired_caddy="$tmp/Caddyfile.desired"
current_caddy="$tmp/Caddyfile.current"
current_caddy_source="empty"
mkdir -p ${shQuote(target.runtime.workDir)} ${shQuote(target.runtime.dataDir)} ${shQuote(target.runtime.configDir)} "$(dirname ${shQuote(target.runtime.statePath)})"
${authFiles.map((path) => `[ -s ${shQuote(path)} ] || { printf '%s\\n' '{"ok":false,"mutation":false,"error":"public-edge-auth-source-missing","sourceRef":${JSON.stringify(path)},"valuesPrinted":false}'; exit 1; }`).join("\n")}
set -a
${authFiles.map((path) => `. ${shQuote(path)}`).join("\n")}
set +a
printf '%s' ${shQuote(ancestry)} | base64 -d >"$ancestry_file"
printf '%s' ${shQuote(caddyfile)} | base64 -d >"$desired_caddy"
printf '%s' ${shQuote(compose)} | base64 -d >"$compose_candidate"

installed_commit=""
installed_authority=""
installed_caddy_sha=""
installed_compose_sha=""
if [ -f ${shQuote(target.runtime.statePath)} ]; then
  state_fields="$tmp/installed-state-fields"
  python3 - ${shQuote(target.runtime.statePath)} "$state_fields" <<'PY' || {
import json, pathlib, re, sys
state = json.load(open(sys.argv[1], encoding="utf-8"))
valid = (
    state.get("version") == 1
    and isinstance(state.get("authorityId"), str) and bool(state["authorityId"])
    and isinstance(state.get("sourceCommit"), str) and re.fullmatch(r"[0-9a-f]{40}", state["sourceCommit"]) is not None
    and isinstance(state.get("managedCaddyFingerprint"), str) and re.fullmatch(r"sha256:[0-9a-f]{64}", state["managedCaddyFingerprint"]) is not None
    and isinstance(state.get("composeFingerprint"), str) and re.fullmatch(r"sha256:[0-9a-f]{64}", state["composeFingerprint"]) is not None
    and isinstance(state.get("siteCount"), int) and state["siteCount"] >= 0
)
if not valid:
    raise SystemExit(2)
pathlib.Path(sys.argv[2]).write_text("\\n".join([
    state["sourceCommit"],
    state["authorityId"],
    state["managedCaddyFingerprint"],
    state["composeFingerprint"],
]) + "\\n", encoding="utf-8")
PY
    printf '%s\\n' '{"ok":false,"mutation":false,"error":"installed-provenance-invalid","valuesPrinted":false}'
    exit 1
  }
  installed_commit="$(sed -n '1p' "$state_fields")"
  installed_authority="$(sed -n '2p' "$state_fields")"
  installed_caddy_sha="$(sed -n '3p' "$state_fields")"
  installed_compose_sha="$(sed -n '4p' "$state_fields")"
fi
if [ -n "$installed_authority" ] && [ "$installed_authority" != ${shQuote(provenance.authorityId)} ]; then
  printf '%s\\n' '{"ok":false,"mutation":false,"error":"installed-authority-mismatch","valuesPrinted":false}'
  exit 1
fi
if [ -n "$installed_commit" ] && ! grep -Fxq "$installed_commit" "$ancestry_file"; then
  python3 - "$installed_commit" ${shQuote(provenance.sourceCommit)} <<'PY'
import json, sys
print(json.dumps({"ok": False, "mutation": False, "error": "stale-or-diverged-source-commit", "installedSourceCommit": sys.argv[1], "candidateSourceCommit": sys.argv[2], "valuesPrinted": False}))
PY
  exit 1
fi

if [ -f ${shQuote(target.runtime.caddyfilePath)} ]; then
  cp ${shQuote(target.runtime.caddyfilePath)} "$current_caddy"
  current_caddy_source="managed"
elif [ -f ${shQuote(target.runtime.legacy.caddyfilePath)} ]; then
  cp ${shQuote(target.runtime.legacy.caddyfilePath)} "$current_caddy"
  current_caddy_source="legacy"
else
  : >"$current_caddy"
fi
python3 - "$current_caddy" "$desired_caddy" "$caddy_candidate" "$current_caddy_source" <<'PY'
import pathlib, re, sys
current = pathlib.Path(sys.argv[1]).read_text(encoding="utf-8")
desired = pathlib.Path(sys.argv[2]).read_text(encoding="utf-8")
pattern = re.compile(r"(?ms)^# BEGIN unidesk managed (?P<name>[^\\n]+)\\n(?P<body>.*?)\\n# END unidesk managed (?P=name)\\n*")
desired_blocks = [m.group(0).rstrip() for m in pattern.finditer(desired)]
is_public_edge = lambda name: re.fullmatch(r"public-edge(?:-global|-site:.+)", name) is not None
if not desired_blocks or any(not is_public_edge(m.group("name")) for m in pattern.finditer(desired)):
    raise SystemExit("desired public-edge managed blocks invalid")
if sys.argv[4] == "legacy":
    preserved = [m.group(0).rstrip() for m in pattern.finditer(current) if not is_public_edge(m.group("name"))]
    base = "\\n\\n".join(preserved)
else:
    base = pattern.sub(lambda m: "" if is_public_edge(m.group("name")) else m.group(0), current).rstrip()
merged = (base + "\\n\\n" if base else "") + "\\n\\n".join(desired_blocks) + "\\n"
pathlib.Path(sys.argv[3]).write_text(merged, encoding="utf-8")
PY

new_running=0; docker inspect -f '{{.State.Running}}' ${shQuote(target.runtime.containerName)} 2>/dev/null | grep -qx true && new_running=1
legacy_running=0; docker inspect -f '{{.State.Running}}' ${shQuote(target.runtime.legacy.containerName)} 2>/dev/null | grep -qx true && legacy_running=1
if [ "$new_running" -ne 1 ] && [ "$legacy_running" -ne 1 ]; then
  printf '%s\\n' '{"ok":false,"mutation":false,"error":"managed-edge-not-running","valuesPrinted":false}'
  exit 1
fi
listeners_rc=0
ss -ltn | grep -Eq '[:.]${target.listener.httpPort}[[:space:]]' || listeners_rc=1
ss -ltn | grep -Eq '[:.]${target.listener.httpsPort}[[:space:]]' || listeners_rc=1
udp_rc=0
${target.isolation.preservedUdpPorts.map((value) => `ss -lun | grep -Eq '[:.]${value}[[:space:]]' || udp_rc=1`).join("\n")}
dns_rc=0
dns_warnings="$tmp/dns-warnings.tsv"; : >"$dns_warnings"
for item in ${dnsItems}; do
  host="${"${item%%|*}"}"; expected="${"${item#*|}"}"
  if ! getent ahostsv4 "$host" | awk '{print $1}' | grep -Fxq "$expected"; then
    dns_rc=1
    printf '%s\t%s\\n' "$host" "$expected" >>"$dns_warnings"
  fi
done
compose_rc=0; docker compose -f "$compose_candidate" config >/dev/null 2>"$tmp/compose.err" || compose_rc=$?
adapt_rc=0; docker run --rm ${caddyEnvArgs} -v "$caddy_candidate:/etc/caddy/Caddyfile:ro" ${shQuote(target.runtime.image)} caddy adapt --validate --config /etc/caddy/Caddyfile >/dev/null 2>"$tmp/adapt.err" || adapt_rc=$?
validate_rc=0; docker run --rm ${caddyEnvArgs} -v "$caddy_candidate:/etc/caddy/Caddyfile:ro" ${shQuote(target.runtime.image)} caddy validate --config /etc/caddy/Caddyfile >/dev/null 2>"$tmp/validate.err" || validate_rc=$?
if [ "$listeners_rc" -ne 0 ] || [ "$udp_rc" -ne 0 ] || [ "$compose_rc" -ne 0 ] || [ "$adapt_rc" -ne 0 ] || [ "$validate_rc" -ne 0 ]; then
  python3 - "$listeners_rc" "$udp_rc" "$dns_rc" "$compose_rc" "$adapt_rc" "$validate_rc" <<'PY'
import json, sys
names = ["tcpListeners", "preservedUdpListeners", "dns", "compose", "caddyAdapt", "caddyValidate"]
checks = {name: {"exitCode": int(value)} for name, value in zip(names, sys.argv[1:])}
checks["dns"]["blocking"] = False
print(json.dumps({"ok": False, "mutation": False, "error": "candidate-validation-failed", "checks": checks, "valuesPrinted": False}))
PY
  exit 1
fi

current_managed_sha="$(python3 - "$current_caddy" <<'PY'
import hashlib, pathlib, re, sys
text = pathlib.Path(sys.argv[1]).read_text(encoding="utf-8")
pattern = re.compile(r"(?ms)^# BEGIN unidesk managed (?P<name>[^\\n]+)\\n(?P<body>.*?)\\n# END unidesk managed (?P=name)\\n*")
blocks = [m.group(0).rstrip() for m in pattern.finditer(text) if re.fullmatch(r"public-edge(?:-global|-site:.+)", m.group("name"))]
print("sha256:" + hashlib.sha256(("\\n\\n".join(blocks) + ("\\n" if blocks else "")).encode()).hexdigest() if blocks else "")
PY
)"
current_compose_sha=""
if [ -f ${shQuote(target.runtime.composePath)} ]; then current_compose_sha="sha256:$(sha256sum ${shQuote(target.runtime.composePath)} | awk '{print $1}')"; fi

write_candidate_state() {
  state_candidate="$tmp/reconcile-state.json"
  if ! python3 - "$state_candidate" ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} ${shQuote(desiredCaddyFingerprint)} ${shQuote(desiredComposeFingerprint)} ${sites.length} <<'PY'
import datetime, json, pathlib, sys
path = pathlib.Path(sys.argv[1])
path.write_text(json.dumps({
    "version": 1,
    "authorityId": sys.argv[2],
    "sourceCommit": sys.argv[3],
    "managedCaddyFingerprint": sys.argv[4],
    "composeFingerprint": sys.argv[5],
    "siteCount": int(sys.argv[6]),
    "updatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
}, separators=(",", ":")) + "\\n", encoding="utf-8")
PY
  then
    return 1
  fi
  chmod 0644 "$state_candidate" || return 1
  mv "$state_candidate" ${shQuote(target.runtime.statePath)}
}

if [ "$new_running" -eq 1 ] \
  && [ "$current_managed_sha" = ${shQuote(desiredCaddyFingerprint)} ] \
  && [ "$current_compose_sha" = ${shQuote(desiredComposeFingerprint)} ]; then
  provenance_updated=false
  if [ "$installed_commit" != ${shQuote(provenance.sourceCommit)} ] \
    || [ "$installed_caddy_sha" != ${shQuote(desiredCaddyFingerprint)} ] \
    || [ "$installed_compose_sha" != ${shQuote(desiredComposeFingerprint)} ]; then
    if ! write_candidate_state; then
      printf '%s\\n' '{"ok":false,"mutation":false,"error":"provenance-update-failed","valuesPrinted":false}'
      exit 1
    fi
    provenance_updated=true
  fi
  python3 - ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} "$dns_warnings" "$provenance_updated" <<'PY'
import json, sys
warnings = []
with open(sys.argv[3], encoding="utf-8") as handle:
    for line in handle:
        hostname, expected_a = line.rstrip("\\n").split("\\t", 1)
        warnings.append({"code": "public-edge-dns-mismatch", "level": "warning", "blocking": False, "hostname": hostname, "expectedA": expected_a})
print(json.dumps({"ok": True, "mutation": False, "mode": "already-current", "authorityId": sys.argv[1], "sourceCommit": sys.argv[2], "provenanceUpdated": sys.argv[4] == "true", "warnings": warnings, "valuesPrinted": False}))
PY
  exit 0
fi

had_compose=0; had_caddy=0; had_state=0
if [ -f ${shQuote(target.runtime.composePath)} ]; then cp ${shQuote(target.runtime.composePath)} "$tmp/compose.previous"; had_compose=1; fi
if [ -f ${shQuote(target.runtime.caddyfilePath)} ]; then cp ${shQuote(target.runtime.caddyfilePath)} "$tmp/Caddyfile.previous"; had_caddy=1; fi
if [ -f ${shQuote(target.runtime.statePath)} ]; then cp ${shQuote(target.runtime.statePath)} "$tmp/state.previous"; had_state=1; fi
chmod 0644 "$compose_candidate" "$caddy_candidate"
mv "$compose_candidate" ${shQuote(target.runtime.composePath)}
mv "$caddy_candidate" ${shQuote(target.runtime.caddyfilePath)}
if [ "$legacy_running" -eq 1 ]; then docker rm -f ${shQuote(target.runtime.legacy.containerName)} >/dev/null 2>"$tmp/legacy-stop.err"; fi
recreate_rc=0
docker compose -f ${shQuote(target.runtime.composePath)} up -d --no-build --no-deps --force-recreate caddy >/dev/null 2>"$tmp/recreate.err" || recreate_rc=$?
ready_rc=1
if [ "$recreate_rc" -eq 0 ]; then
  for attempt in $(seq 1 20); do
    if docker inspect -f '{{.State.Running}}' ${shQuote(target.runtime.containerName)} 2>/dev/null | grep -qx true && ss -ltn | grep -Eq '[:.]${target.listener.httpPort}[[:space:]]' && ss -ltn | grep -Eq '[:.]${target.listener.httpsPort}[[:space:]]'; then ready_rc=0; break; fi
    sleep 1
  done
fi
state_rc=1
if [ "$recreate_rc" -eq 0 ] && [ "$ready_rc" -eq 0 ]; then
  write_candidate_state && state_rc=0
fi

rollback_rc=-1
if [ "$recreate_rc" -ne 0 ] || [ "$ready_rc" -ne 0 ] || [ "$state_rc" -ne 0 ]; then
  docker rm -f ${shQuote(target.runtime.containerName)} >/dev/null 2>&1 || true
  if [ "$had_compose" -eq 1 ]; then cp "$tmp/compose.previous" ${shQuote(target.runtime.composePath)}; else rm -f ${shQuote(target.runtime.composePath)}; fi
  if [ "$had_caddy" -eq 1 ]; then cp "$tmp/Caddyfile.previous" ${shQuote(target.runtime.caddyfilePath)}; else rm -f ${shQuote(target.runtime.caddyfilePath)}; fi
  if [ "$had_state" -eq 1 ]; then cp "$tmp/state.previous" ${shQuote(target.runtime.statePath)}; else rm -f ${shQuote(target.runtime.statePath)}; fi
  rollback_rc=0
  if [ "$legacy_running" -eq 1 ]; then
    docker compose -f ${shQuote(target.runtime.legacy.composePath)} up -d --no-build --no-deps --force-recreate caddy >/dev/null 2>>"$tmp/rollback.err" || rollback_rc=$?
  elif [ "$new_running" -eq 1 ] && [ "$had_compose" -eq 1 ]; then
    docker compose -f ${shQuote(target.runtime.composePath)} up -d --no-build --no-deps --force-recreate caddy >/dev/null 2>>"$tmp/rollback.err" || rollback_rc=$?
  fi
  python3 - "$recreate_rc" "$ready_rc" "$state_rc" "$rollback_rc" <<'PY'
import json, sys
print(json.dumps({"ok": False, "mutation": False, "error": "reconcile-failed", "recreate": {"exitCode": int(sys.argv[1]), "readyExitCode": int(sys.argv[2])}, "provenance": {"exitCode": int(sys.argv[3])}, "rollback": {"exitCode": int(sys.argv[4])}, "valuesPrinted": False}))
PY
  exit 1
fi

probe_rc=0
probe_failures="$tmp/probe-failures.tsv"; : >"$probe_failures"
probe_index=0
for item in ${probeItems}; do
  probe_index=$((probe_index + 1))
  (
    host="${"${item%%|*}"}"; rest="${"${item#*|}"}"; path="${"${rest%%|*}"}"; expected="${"${rest#*|}"}"; path="/${"${path#/}"}"
    status="$(curl --noproxy '*' -sS -o /dev/null -w '%{http_code}' --connect-timeout 3 --max-time 10 --resolve "$host:${target.listener.httpsPort}:127.0.0.1" "https://$host$path" 2>"$tmp/probe-$probe_index.err" || true)"
    case "$expected" in
      2xx3xx) printf '%s' "$status" | grep -Eq '^[23][0-9][0-9]$' ;;
      *) printf ',%s,' "$expected" | grep -Fq ",$status," ;;
    esac || {
      printf '%s\t%s\\n' "$host" "$path" >"$tmp/probe-failure-$probe_index.tsv"
    }
  ) &
done
wait || true
for failure in "$tmp"/probe-failure-*.tsv; do
  [ -f "$failure" ] || continue
  probe_rc=1
  cat "$failure" >>"$probe_failures"
done
python3 - "$probe_rc" "$probe_failures" "$dns_warnings" ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} "$legacy_running" <<'PY'
import json, sys
warnings = []
with open(sys.argv[2], encoding="utf-8") as handle:
    for line in handle:
        hostname, path = line.rstrip("\\n").split("\\t", 1)
        warnings.append({"code": "site-probe-failed", "level": "warning", "blocking": False, "hostname": hostname, "path": path})
with open(sys.argv[3], encoding="utf-8") as handle:
    for line in handle:
        hostname, expected_a = line.rstrip("\\n").split("\\t", 1)
        warnings.append({"code": "public-edge-dns-mismatch", "level": "warning", "blocking": False, "hostname": hostname, "expectedA": expected_a})
print(json.dumps({
    "ok": True,
    "mutation": True,
    "authorityId": sys.argv[4],
    "sourceCommit": sys.argv[5],
    "legacyRetired": sys.argv[6] == "1",
    "probe": {"attempted": True, "exitCode": int(sys.argv[1]), "blocking": False},
    "warnings": warnings,
    "valuesPrinted": False,
}))
PY
`;
}

export function renderPublicEdgeStatusScript(
  target: PublicEdgeTarget,
  sites: ResolvedSite[],
  desiredCaddyfile: string | null,
  desiredCompose: string | null,
  desiredSourceCommit: string | null,
  authorityId: string,
): string {
  const probeCommands = sites.map((site, index) => {
    const failureFile = `${String(index).padStart(6, "0")}.json`;
    const dnsFailure = Buffer.from(JSON.stringify({
      code: "public-edge-dns-mismatch",
      siteId: site.id,
      hostname: site.hostname,
      expectedA: site.expectedA,
    }), "utf8").toString("base64");
    const siteFailure = Buffer.from(JSON.stringify({
      code: "public-edge-site-probe-failed",
      siteId: site.id,
      hostname: site.hostname,
      path: site.healthPath,
    }), "utf8").toString("base64");
    const expected = site.healthExpectedStatuses;
    const statusCheck = expected === undefined
      ? `printf '%s' "$status" | grep -Eq '^[23][0-9][0-9]$'`
      : `printf ',${expected.join(",")},' | grep -Fq ",$status,"`;
    return `(
  if ! getent ahostsv4 ${shQuote(site.hostname)} | awk '{print $1}' | grep -Fxq ${shQuote(site.expectedA)}; then
    printf '%s' ${shQuote(dnsFailure)} | base64 -d >"$dns_failures_dir/${failureFile}"
  fi
  status="$(curl --noproxy '*' -sS -o /dev/null -w '%{http_code}' --connect-timeout 3 --max-time 10 --resolve ${shQuote(`${site.hostname}:${target.listener.httpsPort}:127.0.0.1`)} ${shQuote(`https://${site.hostname}${site.healthPath}`)} || true)"
  if ! ${statusCheck}; then
    printf '%s' ${shQuote(siteFailure)} | base64 -d >"$site_failures_dir/${failureFile}"
  fi
) &`;
  }).join("\n");
  const desiredFingerprint = desiredCaddyfile === null ? "" : sha256Fingerprint(desiredCaddyfile);
  const desiredComposeFingerprint = desiredCompose === null ? "" : sha256Fingerprint(desiredCompose);
  return `set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
dns_failures_dir="$tmp/dns-failures"
site_failures_dir="$tmp/site-failures"
mkdir -p "$dns_failures_dir" "$site_failures_dir"
container_identity="$(docker inspect -f '{{.State.Running}}|{{.Id}}|{{.State.StartedAt}}' ${shQuote(target.runtime.containerName)} 2>/dev/null || true)"
container_rc=0; printf '%s' "$container_identity" | grep -q '^true|' || container_rc=1
legacy_rc=0; docker inspect -f '{{.State.Running}}' ${shQuote(target.runtime.legacy.containerName)} 2>/dev/null | grep -qx true || legacy_rc=1
listeners_rc=0; ss -ltn | grep -Eq '[:.]${target.listener.httpPort}[[:space:]]' || listeners_rc=1; ss -ltn | grep -Eq '[:.]${target.listener.httpsPort}[[:space:]]' || listeners_rc=1
udp_rc=0
${target.isolation.preservedUdpPorts.map((value) => `ss -lun | grep -Eq '[:.]${value}[[:space:]]' || udp_rc=1`).join("\n")}
validate_rc=0; docker exec ${shQuote(target.runtime.containerName)} caddy validate --config /etc/caddy/Caddyfile >/dev/null 2>/dev/null || validate_rc=1
sites_rc=0; dns_rc=0
${probeCommands}
wait || true
for failure in "$dns_failures_dir"/*.json; do [ -f "$failure" ] || continue; dns_rc=1; done
for failure in "$site_failures_dir"/*.json; do [ -f "$failure" ] || continue; sites_rc=1; done
current_sha=""
if [ -f ${shQuote(target.runtime.caddyfilePath)} ]; then
  current_sha="$(python3 - ${shQuote(target.runtime.caddyfilePath)} <<'PY'
import hashlib, pathlib, re, sys
text = pathlib.Path(sys.argv[1]).read_text(encoding="utf-8")
pattern = re.compile(r"(?ms)^# BEGIN unidesk managed (?P<name>[^\\n]+)\\n(?P<body>.*?)\\n# END unidesk managed (?P=name)\\n*")
blocks = [m.group(0).rstrip() for m in pattern.finditer(text) if re.fullmatch(r"public-edge(?:-global|-site:.+)", m.group("name"))]
print("sha256:" + hashlib.sha256(("\\n\\n".join(blocks) + ("\\n" if blocks else "")).encode()).hexdigest() if blocks else "")
PY
)"
fi
current_compose_sha=""
if [ -f ${shQuote(target.runtime.composePath)} ]; then current_compose_sha="sha256:$(sha256sum ${shQuote(target.runtime.composePath)} | awk '{print $1}')"; fi
python3 - "$container_rc" "$legacy_rc" "$listeners_rc" "$udp_rc" "$validate_rc" "$dns_rc" "$sites_rc" "$container_identity" "$current_sha" ${shQuote(desiredFingerprint)} "$current_compose_sha" ${shQuote(desiredComposeFingerprint)} ${shQuote(desiredSourceCommit ?? "")} ${shQuote(authorityId)} ${shQuote(target.runtime.statePath)} "$dns_failures_dir" "$site_failures_dir" <<'PY'
import json, pathlib, sys
container, legacy, listeners, udp, validate, dns, sites = [int(value) for value in sys.argv[1:8]]
container_identity, current, desired, current_compose, desired_compose, desired_commit, desired_authority, state_path, dns_failures_path, site_failures_path = sys.argv[8:18]
container_parts = container_identity.split("|", 2)
container_id = container_parts[1] if len(container_parts) == 3 and container_parts[1] else None
container_started_at = container_parts[2] if len(container_parts) == 3 and container_parts[2] else None
def read_failures(directory):
    return [json.loads(path.read_text(encoding="utf-8")) for path in sorted(pathlib.Path(directory).glob("*.json"))]
dns_failures = read_failures(dns_failures_path)
site_failures = read_failures(site_failures_path)
state = None
try:
    state = json.loads(pathlib.Path(state_path).read_text(encoding="utf-8"))
except FileNotFoundError:
    pass
except Exception as error:
    state = {"error": "installed-provenance-invalid", "detail": str(error)}
state_matches_runtime = (
    state is not None
    and "error" not in state
    and state.get("version") == 1
    and state.get("authorityId") == desired_authority
    and state.get("managedCaddyFingerprint") == current
    and state.get("composeFingerprint") == current_compose
)
config_matches_desired = bool(desired) and current == desired and bool(desired_compose) and current_compose == desired_compose
ok = all(value == 0 for value in [container, listeners, udp, validate, sites]) and legacy != 0 and state_matches_runtime and config_matches_desired
print(json.dumps({"ok": ok, "container": {"exitCode": container, "id": container_id, "startedAt": container_started_at}, "legacyContainer": {"exitCode": legacy, "retired": legacy != 0}, "tcpListeners": {"exitCode": listeners}, "preservedUdpListeners": {"exitCode": udp}, "validate": {"exitCode": validate}, "dns": {"exitCode": dns, "blocking": False, "failures": dns_failures}, "siteProbes": {"exitCode": sites, "failures": site_failures}, "provenance": {"installed": state, "desiredSourceCommit": desired_commit or None, "matchesRuntime": state_matches_runtime}, "config": {"currentManagedFingerprint": current or None, "desiredManagedFingerprint": desired or None, "currentComposeFingerprint": current_compose or None, "desiredComposeFingerprint": desired_compose or None, "matchesDesired": config_matches_desired}, "valuesPrinted": False}))
raise SystemExit(0 if ok else 1)
PY
`;
}

function targetSummary(target: PublicEdgeTarget): Record<string, unknown> {
  return {
    id: target.id,
    route: target.route,
    publicAddress: target.publicAddress,
    listeners: [target.listener.httpPort, target.listener.httpsPort],
    isolation: target.isolation,
    containerName: target.runtime.containerName,
    workDir: target.runtime.workDir,
    caddyfilePath: target.runtime.caddyfilePath,
    composePath: target.runtime.composePath,
    dataDir: target.runtime.dataDir,
    configDir: target.runtime.configDir,
    statePath: target.runtime.statePath,
    lockPath: target.runtime.lockPath,
    resourceProtection: target.runtime.resourceProtection,
    legacyContainerName: target.runtime.legacy.containerName,
    dnsServers: target.runtime.dnsServers,
  };
}

function readAncestry(path: string | null, sourceCommit: string | null): string[] {
  if (path === null || sourceCommit === null || !existsSync(path)) {
    throw inputError("reconcile ancestry file 不存在", "reconcile-ancestry-missing", "--ancestry-file");
  }
  const commits = readFileSync(path, "utf8").split(/\r?\n/u).filter((value) => value.length > 0);
  if (commits.length === 0 || commits.some((value) => !/^[0-9a-f]{40}$/u.test(value)) || !commits.includes(sourceCommit)) {
    throw inputError("reconcile ancestry file 无效或不包含 candidate commit", "reconcile-ancestry-invalid", "--ancestry-file");
  }
  return commits;
}

function checkoutSourceCommit(): string | null {
  const result = spawnSync("git", ["rev-parse", "HEAD"], { cwd: resolveRepoPath("."), encoding: "utf8" });
  const value = result.status === 0 ? result.stdout.trim() : "";
  return /^[0-9a-f]{40}$/u.test(value) ? value : null;
}

export type PublicEdgeSourceRelation =
  | "same"
  | "installed-ancestor"
  | "installed-descendant"
  | "diverged"
  | "unknown";

export function classifyPublicEdgeSourceRelation(
  installedSourceCommit: string | null,
  desiredSourceCommit: string | null,
): PublicEdgeSourceRelation {
  if (
    installedSourceCommit === null
    || desiredSourceCommit === null
    || !/^[0-9a-f]{40}$/u.test(installedSourceCommit)
    || !/^[0-9a-f]{40}$/u.test(desiredSourceCommit)
  ) return "unknown";
  if (installedSourceCommit === desiredSourceCommit) return "same";
  const cwd = resolveRepoPath(".");
  const installedAncestor = spawnSync(
    "git",
    ["merge-base", "--is-ancestor", installedSourceCommit, desiredSourceCommit],
    { cwd, encoding: "utf8" },
  );
  if (installedAncestor.status === 0) return "installed-ancestor";
  if (installedAncestor.status !== 1) return "unknown";
  const installedDescendant = spawnSync(
    "git",
    ["merge-base", "--is-ancestor", desiredSourceCommit, installedSourceCommit],
    { cwd, encoding: "utf8" },
  );
  if (installedDescendant.status === 0) return "installed-descendant";
  return installedDescendant.status === 1 ? "diverged" : "unknown";
}

function record(value: unknown, path: string): Record<string, unknown> {
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} 必须是对象`);
  return value as Record<string, unknown>;
}

function optionalRecord(value: unknown): Record<string, unknown> | null {
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
}

function boolean(value: unknown, path: string): boolean {
  if (typeof value !== "boolean") throw new Error(`${path} 必须是布尔值`);
  return value;
}

function array(value: unknown, path: string): unknown[] {
  if (!Array.isArray(value)) throw new Error(`${path} 必须是数组`);
  return value;
}

function string(value: unknown, path: string): string {
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path} 必须是非空字符串`);
  return value.trim();
}

function stringArray(value: unknown, path: string): string[] {
  if (!Array.isArray(value) || value.length === 0) throw new Error(`${path} 必须是非空字符串数组`);
  return value.map((item, index) => string(item, `${path}[${index}]`));
}

function portArray(value: unknown, path: string): number[] {
  if (!Array.isArray(value) || value.length === 0) throw new Error(`${path} 必须是非空端口数组`);
  return value.map((item, index) => port(item, `${path}[${index}]`));
}

function positiveInteger(value: unknown, path: string): number {
  if (!Number.isInteger(value) || (value as number) < 1) throw new Error(`${path} 必须是正整数`);
  return value as number;
}

function dockerMemory(value: unknown, path: string): string {
  const parsed = string(value, path);
  if (!/^[1-9]\d*(?:[bkmg])$/iu.test(parsed)) throw inputError(`${path} 必须是 Docker 内存值，例如 128m`, "invalid-docker-memory", path);
  return parsed;
}

function dockerMemoryBytes(value: string): number {
  const units: Record<string, number> = { b: 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3 };
  return Number(value.slice(0, -1)) * units[value.slice(-1).toLowerCase()];
}

function port(value: unknown, path: string): number {
  const result = positiveInteger(value, path);
  if (result > 65_535) throw new Error(`${path} 必须小于等于 65535`);
  return result;
}

function ipv4(value: unknown, path: string): string {
  const result = string(value, path);
  const parts = result.split(".");
  if (parts.length !== 4 || parts.some((part) => !/^\d{1,3}$/u.test(part) || Number(part) > 255)) throw new Error(`${path} 必须是 IPv4 地址`);
  return result;
}

function hostnameValue(value: unknown, path: string): string {
  const result = string(value, path).toLowerCase();
  if (!/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/u.test(result)) throw new Error(`${path} 不是合法 hostname`);
  return result;
}

function upstreamValue(value: unknown, path: string): string {
  const result = string(value, path);
  const match = /^(?:https?:\/\/)?(?:[A-Za-z0-9.-]+|\[[0-9a-fA-F:]+\]):([1-9][0-9]{0,4})$/u.exec(result);
  if (match === null) throw new Error(`${path} 必须是 host:port、http://host:port 或 https://host:port`);
  const parsedPort = Number(match[1]);
  if (parsedPort > 65_535) throw new Error(`${path} port 必须小于等于 65535`);
  return result;
}

function httpPath(value: unknown, path: string): string {
  const result = string(value, path);
  if (!result.startsWith("/")) throw new Error(`${path} 必须以 / 开头`);
  return result;
}

function absolutePath(value: unknown, path: string): string {
  const result = string(value, path);
  if (!result.startsWith("/")) throw new Error(`${path} 必须是绝对路径`);
  return result;
}

function envName(value: unknown, path: string): string {
  const parsed = string(value, path);
  if (!/^[A-Z_][A-Z0-9_]*$/u.test(parsed)) throw inputError(`${path} 必须是大写环境变量名`, "invalid-env-name", path);
  return parsed;
}

function yamlConfigPath(value: unknown, path: string): string {
  const result = string(value, path);
  if (result.includes("..") || !result.endsWith(".yaml")) throw new Error(`${path} 必须是 YAML 路径`);
  if (!result.startsWith("/") && result.startsWith(".")) throw new Error(`${path} 相对路径必须从仓库根目录开始`);
  return result;
}

function gitCommit(value: unknown, path: string): string {
  const result = string(value, path);
  if (!/^[0-9a-f]{40}$/u.test(result)) throw new Error(`${path} 必须是 40 位 Git commit`);
  return result;
}

function duration(value: unknown, path: string): string {
  const result = string(value, path);
  if (!/^[1-9][0-9]*(?:ms|s|m)$/u.test(result)) throw new Error(`${path} 必须是正整数加 ms、s 或 m`);
  return result;
}

function inputError(message: string, code: string, argument?: string): CliInputError {
  return new CliInputError(message, { code, argument, usage: "bun scripts/cli.ts platform-infra public-edge plan|apply|status --target NC01" });
}
