import { createHash, randomBytes } from "node:crypto";
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import type { UniDeskConfig } from "./config";
import { rootPath } from "./config";
import { CliInputError, type RenderedCliResult } from "./output";
import {
  capture,
  compactCapture,
  parseJsonOutput,
  shQuote,
} from "./platform-infra-ops-library";
import { deriveGiteaWebhookAttemptBudgetMs, deriveGiteaWebhookResponseHeaderTimeoutMs } from "./platform-infra-gitea-caddy";
import { renderGiteaRemotePayloadMaterializer, summarizeGiteaRemotePayloads } from "./platform-infra-gitea-payload";
import { PAC_AUTOMATIC_DELIVERY_REFERENCE } from "./cicd-delivery-authority";
import { renderPlatformInfraGiteaDesiredFragments } from "./platform-infra-gitea-desired-fragments";
import {
  buildMirrorWebhookStatusDisclosure,
  rawMirrorWebhookStatus,
} from "./platform-infra-gitea-disclosure";
import {
  renderApply,
  renderMirrorBootstrap,
  renderMirrorPlan,
  renderMirrorStatus,
  renderMirrorSync,
  renderMirrorWebhookApply,
  renderMirrorWebhookCredentialBlocked,
  renderMirrorWebhookStatus,
  renderPlan,
  renderStatus,
} from "./platform-infra-gitea-render";
import {
  GITEA_CONFIG_LABEL,
  githubTokenEnvNameForSecretKey,
  readGiteaConfig,
  resolveTarget,
  targetWebhookSync,
  type GiteaAdminCredential,
  type GiteaConfig,
  type GiteaGithubCredential,
  type GiteaMirrorRepository,
  type GiteaSourceResponsibility,
  type GiteaTarget,
  type GiteaWebhookGitOpsDelivery,
  type GiteaWebhookSync,
} from "./platform-infra-gitea-config";

const configLabel = GITEA_CONFIG_LABEL;
const remoteScriptFile = rootPath("scripts", "src", "platform-infra-gitea-remote.sh");
const githubSyncServerFile = rootPath("scripts", "src", "platform-infra-gitea-github-sync-server.mjs");
const githubSyncEntrypointFile = rootPath("scripts", "src", "platform-infra-gitea-github-sync-entrypoint.mjs");
const githubHookReconcilerFile = rootPath("scripts", "src", "platform_infra_gitea_hook_reconciler.py");
const statusEvaluatorFile = rootPath("scripts", "src", "platform_infra_gitea_status_evaluator.py");
const fieldManager = "unidesk-platform-infra-gitea";
interface CommonOptions {
  targetId: string | null;
  full: boolean;
  raw: boolean;
}

interface ApplyOptions extends CommonOptions {
  confirm: boolean;
  dryRun: boolean;
  wait: boolean;
}

interface MirrorOptions extends CommonOptions {
  confirm: boolean;
  dryRun: boolean;
  wait: boolean;
  repoKey: string | null;
}

interface MirrorWebhookStatusOptions extends MirrorOptions {
  deliveryId: string | null;
}

interface MirrorSecrets {
  adminUsername: string;
  adminPassword: string;
  githubTokens: Record<string, string>;
  webhookSecret: string;
}

interface MirrorRemoteParams {
  repos?: GiteaMirrorRepository[];
  secrets?: MirrorSecrets;
}

export async function runPlatformInfraGiteaCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const [action = "plan"] = args;
  if (action === "help" || action === "--help") return giteaHelp(args[1]);
  if (action === "plan") {
    const options = parseCommonOptions(args.slice(1));
    const result = plan(options);
    return options.full || options.raw ? result : renderPlan(result);
  }
  if (action === "apply") {
    const options = parseApplyOptions(args.slice(1));
    const result = await apply(config, options);
    return options.full || options.raw ? result : renderApply(result);
  }
  if (action === "status") {
    const options = parseCommonOptions(args.slice(1));
    const result = await status(config, options);
    return options.full || options.raw ? result : renderStatus(result);
  }
  if (action === "validate") return await validate(config, parseCommonOptions(args.slice(1)));
  if (action === "mirror") return await mirrorCommand(config, args.slice(1));
  return {
    ok: false,
    error: "unsupported-platform-infra-gitea-command",
    args,
    help: giteaHelp(),
  };
}

export async function runGiteaMirrorBootstrapPreflight(
  config: UniDeskConfig,
  targetId: string,
  repoKey: string,
): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, targetId);
  const repos = selectedRepositories(gitea, target, repoKey);
  const { credentials, blockers } = buildGiteaMirrorBootstrapCredentialPreflight(gitea, repos);
  if (blockers.length > 0) {
    return { ok: false, mutation: false, code: "github-credential-unavailable", blockers, repositories: repos.map((repo) => repositorySummary(gitea, repo)), valuesPrinted: false };
  }
  const secrets = mirrorPreflightSecrets(gitea, repos);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-preflight", gitea, target, "", { targetId, repoKey, confirm: false, dryRun: true, wait: false, full: false, raw: false }, { repos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  return parsed ?? { ok: false, mutation: false, code: "github-upstream-preflight-failed", remote: compactCapture(result, { full: true }), valuesPrinted: false };
}

export function buildGiteaMirrorBootstrapCredentialPreflight(
  gitea: GiteaConfig,
  repositories: GiteaMirrorRepository[],
  readCredential: (credential: GiteaGithubCredential) => Record<string, string> | null = (credential) => readGithubCredential(gitea, credential),
): { credentials: Array<Record<string, unknown>>; blockers: string[] } {
  const credentials = repositories.map((repo) => {
    const github = githubCredentialForRepo(gitea, repo);
    const values = readCredential(github);
    const present = values !== null;
    const requiredKeysPresent = Boolean(values?.[github.sourceKey]);
    return {
      id: `github-upstream:${repo.key}`,
      repository: repo.upstream.repository,
      sourceRef: github.sourceRef,
      present,
      requiredKeysPresent,
      fingerprint: present ? fingerprintKeys(values, [github.sourceKey]) : null,
      permissionResult: present && requiredKeysPresent
        ? { status: "not-probed", permissions: github.permissions, error: null }
        : { status: "blocked-missing-credential", permissions: github.permissions, error: "credential material is absent" },
      valuesPrinted: false,
    };
  });
  return { credentials, blockers: credentialBlockers(credentials) };
}

function readGithubCredential(gitea: GiteaConfig, github: GiteaGithubCredential): Record<string, string> | null {
  const sourcePath = credentialPath(gitea, github.sourceRef);
  return existsSync(sourcePath) ? parseGithubCredentialFile(sourcePath, github) : null;
}

function mirrorPreflightSecrets(gitea: GiteaConfig, repositories: GiteaMirrorRepository[]): MirrorSecrets {
  const githubTokens: Record<string, string> = {};
  for (const repo of repositories) {
    const github = githubCredentialForRepo(gitea, repo);
    const githubPath = credentialPath(gitea, github.sourceRef);
    if (!existsSync(githubPath)) throw new Error(`${github.sourceRef} is missing; cannot probe GitHub upstream`);
    const githubEnv = parseGithubCredentialFile(githubPath, github);
    const githubToken = githubEnv[github.sourceKey];
    if (!githubToken) throw new Error(`${github.sourceRef} must contain ${github.sourceKey}`);
    githubTokens[github.gitFetchCredential.secretRef.key] = githubToken;
  }
  return { adminUsername: "", adminPassword: "", githubTokens, webhookSecret: "" };
}

export function giteaHelp(scope?: string): Record<string, unknown> {
  if (scope === "platform-bootstrap") {
    return {
      command: "platform-infra gitea help platform-bootstrap",
      configTruth: configLabel,
      usage: [
        "bun scripts/cli.ts platform-infra gitea apply --target <NODE> --dry-run",
        "bun scripts/cli.ts platform-infra gitea apply --target <NODE> --confirm",
        "bun scripts/cli.ts platform-infra gitea mirror bootstrap --target <NODE> --dry-run",
        "bun scripts/cli.ts platform-infra gitea mirror bootstrap --target <NODE> --confirm",
        "bun scripts/cli.ts platform-infra gitea mirror webhook apply --target <NODE> --confirm",
      ],
      boundary: "这些命令只用于平台首次引导或独立平台维护，不能补齐 PR merge 后的 source delivery。",
    };
  }
  return {
    command: "platform-infra gitea status|validate|mirror status|mirror webhook status",
    configTruth: configLabel,
    usage: [
      "bun scripts/cli.ts platform-infra gitea status --target <NODE> [--full|--raw]",
      "bun scripts/cli.ts platform-infra gitea validate --target <NODE> [--full|--raw]",
      "bun scripts/cli.ts platform-infra gitea mirror status --target <NODE> [--full|--raw]",
      "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <NODE> [--repo <key>] [--delivery-id <id>] [--full|--raw]",
    ],
    scopedHelp: ["bun scripts/cli.ts platform-infra gitea help platform-bootstrap"],
    boundary: "PR merge 只更新 Gitea source authority，不创建 PipelineRun；发布必须先执行 PaC release plan，再由 CLI 手动发送 webhook。默认入口只读观察和校验。",
  };
}

function resolveCommandTarget(gitea: GiteaConfig, targetId: string | null): GiteaTarget {
  if (targetId !== null && !gitea.targets.some((target) => target.id.toLowerCase() === targetId.toLowerCase())) {
    throw new CliInputError(`Unknown Gitea target: ${targetId}`, {
      code: "unknown-target",
      argument: targetId,
      supported: gitea.targets.map((target) => target.id),
      usage: "bun scripts/cli.ts platform-infra gitea <command> --target <node>",
    });
  }
  return resolveTarget(gitea, targetId);
}

function plan(options: CommonOptions): Record<string, unknown> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const manifest = renderManifest(gitea, target);
  const policy = policyChecks(gitea, target, manifest);
  return {
    ok: policy.every((check) => check.ok),
    action: "platform-infra-gitea-plan",
    mutation: false,
    config: configSummary(gitea, target),
    renderPlan: {
      target: targetSummary(target),
      objects: manifestObjectSummary(manifest),
    },
    policy,
    next: giteaReadOnlyNextCommands(target.id),
  };
}

async function apply(config: UniDeskConfig, options: ApplyOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const manifest = renderManifest(gitea, target);
  const policy = policyChecks(gitea, target, manifest);
  if (!policy.every((check) => check.ok)) return { ok: false, action: "platform-infra-gitea-apply", mode: "policy-blocked", mutation: false, policy };
  const targetRepos = repositoriesForTarget(gitea, target);
  const secrets = gitea.sourceAuthority.webhookSync.enabled && !options.dryRun
    ? ensureMirrorSecrets(gitea, target, targetRepos, true, true, true)
    : undefined;
  const remote = remoteScript("apply", gitea, target, manifest, options, { secrets });
  const result = await capture(config, target.route, ["sh"], remote.script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-apply",
    mode: options.dryRun ? "dry-run" : "confirmed",
    mutation: !options.dryRun,
    target: targetSummary(target),
    config: compactConfigSummary(gitea, target),
    policy,
    publicExposure: publicExposureSummary(gitea),
    payloadTransport: remote.payloadSummary,
    secrets: { webhookSync: secrets === undefined ? { enabled: false } : webhookSecretSummary(gitea, target, secrets) },
    publicEdge: {
      authority: "config/platform-infra/public-edge.yaml",
      mutation: false,
      next: `bun scripts/cli.ts platform-infra public-edge plan --target ${target.id}`,
    },
    remote: parsed ?? compactCapture(result, { full: true }),
    next: giteaReadOnlyNextCommands(target.id),
  };
}

async function status(config: UniDeskConfig, options: CommonOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const result = await capture(config, target.route, ["sh"], remoteScript("status", gitea, target, "", { ...options, confirm: false, dryRun: true, wait: false }).script);
  const parsed = parseJsonOutput(result.stdout);
  const summary = parsed === null ? null : statusSummary(parsed);
  return {
    ok: result.exitCode === 0 && summary?.ready === true,
    action: "platform-infra-gitea-status",
    mutation: false,
    target: targetSummary(target),
    config: configSummary(gitea, target),
    summary,
    remote: options.raw ? parsed : options.full ? parsed : summary ?? compactCapture(result, { full: true }),
    next: giteaReadOnlyNextCommands(target.id),
  };
}

async function validate(config: UniDeskConfig, options: CommonOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const result = await capture(config, target.route, ["sh"], remoteScript("validate", gitea, target, "", { ...options, confirm: false, dryRun: true, wait: false }).script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-validate",
    mutation: false,
    target: targetSummary(target),
    config: compactConfigSummary(gitea, target),
    validation: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function mirrorCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const [action = "plan"] = args;
  if (action === "plan") {
    const options = parseCommonOptions(args.slice(1));
    const result = mirrorPlan(options);
    return options.full || options.raw ? result : renderMirrorPlan(result);
  }
  if (action === "bootstrap") {
    const options = parseMirrorOptions(args.slice(1));
    const result = await mirrorBootstrap(config, options);
    return options.full || options.raw ? result : renderMirrorBootstrap(result);
  }
  if (action === "sync" || action === "snapshot") {
    const options = parseMirrorOptions(args.slice(1));
    const result = await mirrorSync(config, options);
    return options.full || options.raw ? result : renderMirrorSync(result);
  }
  if (action === "status") {
    const options = parseMirrorOptions(args.slice(1));
    const result = await mirrorStatus(config, options);
    return options.full || options.raw ? result : renderMirrorStatus(result);
  }
  if (action === "webhook") {
    return await mirrorWebhookCommand(config, args.slice(1));
  }
  return {
    ok: false,
    error: "unsupported-platform-infra-gitea-mirror-command",
    args,
    help: {
      usage: [
        "bun scripts/cli.ts platform-infra gitea mirror status --target JD01 [--full|--raw]",
        "bun scripts/cli.ts platform-infra gitea mirror webhook status --target JD01 [--repo <key>] [--delivery-id <id>] [--full|--raw]",
      ],
    },
  };
}

async function mirrorWebhookCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const [action = "status"] = args;
  if (action === "apply") {
    const options = parseMirrorOptions(args.slice(1));
    const result = await mirrorWebhookApply(config, options);
    return options.full || options.raw ? result : renderMirrorWebhookApply(result);
  }
  if (action === "status") {
    const options = parseMirrorWebhookStatusOptions(args.slice(1));
    const result = await mirrorWebhookStatus(config, options);
    if (result.credentialBlocked === true) return options.full || options.raw ? result : renderMirrorWebhookCredentialBlocked(result);
    if (options.raw) return rawMirrorWebhookStatus(result);
    const disclosure = buildMirrorWebhookStatusDisclosure(result, options);
    return options.full ? disclosure : renderMirrorWebhookStatus(result, disclosure);
  }
  return {
    ok: false,
    error: "unsupported-platform-infra-gitea-mirror-webhook-command",
    usage: "platform-infra gitea mirror webhook status --target <node> [--repo <key>] [--delivery-id <id>] [--full|--raw]",
  };
}

function mirrorPlan(options: CommonOptions): Record<string, unknown> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const targetRepos = repositoriesForTarget(gitea, target);
  return {
    ok: true,
    action: "platform-infra-gitea-mirror-plan",
    mutation: false,
    target: targetSummary(target),
    sourceAuthority: sourceAuthoritySummary(gitea, target),
    responsibilities: gitea.sourceAuthority.responsibilities.map(responsibilitySummary),
    repositories: targetRepos.map((repo) => repositorySummary(gitea, repo)),
    credentials: credentialSummaries(gitea, targetRepos),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

async function mirrorStatus(config: UniDeskConfig, options: CommonOptions & { repoKey?: string | null }): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const selectedRepos = selectedRepositories(gitea, target, options.repoKey ?? null);
  const credentials = credentialSummaries(gitea, selectedRepos);
  const blockers = credentialBlockers(credentials);
  if (blockers.length > 0) {
    return {
      ok: false,
      action: "platform-infra-gitea-mirror-status",
      mutation: false,
      target: targetSummary(target),
      serviceHealth: { ok: false },
      sourceAuthority: { ...sourceAuthoritySummary(gitea, target), mirrorReady: false, stageReady: false },
      repositories: selectedRepos.map((repo) => repositorySummary(gitea, repo)),
      credentials,
      error: { code: "github-credential-unavailable", blockers, valuesPrinted: false },
      next: mirrorReadOnlyNextCommands(target.id),
    };
  }
  const health = await validate(config, options);
  const healthValidation = record(health.validation);
  const secrets = ensureMirrorSecrets(gitea, target, selectedRepos, false, false, false);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-status", gitea, target, "", { ...options, confirm: false, dryRun: true, wait: false }, { repos: selectedRepos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  const repositories = arrayRecords(record(parsed).repositories);
  return {
    ok: health.ok === true && result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-mirror-status",
    mutation: false,
    target: targetSummary(target),
    serviceHealth: {
      ok: health.ok === true,
      healthStatus: record(healthValidation.health).status,
      endpointsReady: healthValidation.endpointsReady === true,
      serviceProxyPath: healthValidation.serviceProxyPath,
    },
    sourceAuthority: {
      ...sourceAuthoritySummary(gitea, target),
      mirrorReady: repositories.length > 0 && repositories.every((repo) => repo.sourceBundleReady === true),
      stageReady: health.ok === true,
      readinessDetail: "Gitea source-authority is ready when every configured repo has branch and snapshot refs in Gitea.",
    },
    responsibilities: gitea.sourceAuthority.responsibilities.map(responsibilitySummary),
    repositories: repositories.length > 0 ? repositories : selectedRepos.map((repo) => repositorySummary(gitea, repo)),
    credentials,
    remote: parsed ?? compactCapture(result, { full: options.full || result.exitCode !== 0 }),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

async function mirrorBootstrap(config: UniDeskConfig, options: MirrorOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const repos = selectedRepositories(gitea, target, options.repoKey);
  if (!options.confirm) {
    const credentials = credentialSummaries(gitea, repos);
    const blockers = credentialBlockers(credentials);
    const repoFlag = options.repoKey === null ? "" : ` --repo ${options.repoKey}`;
    return {
      ok: blockers.length === 0,
      action: "platform-infra-gitea-mirror-bootstrap",
      mutation: false,
      mode: "dry-run",
      target: targetSummary(target),
      repositories: repos.map((repo) => repositorySummary(gitea, repo)),
      credentials,
      blockers,
      next: {
        ...mirrorReadOnlyNextCommands(target.id),
        confirm: `bun scripts/cli.ts platform-infra gitea mirror bootstrap --target ${target.id}${repoFlag} --confirm`,
      },
    };
  }
  const secrets = ensureMirrorSecrets(gitea, target, repositoriesForTarget(gitea, target), true, true, true);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-bootstrap", gitea, target, "", { ...options, dryRun: false, wait: false }, { repos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-mirror-bootstrap",
    mutation: true,
    mode: "confirmed",
    target: targetSummary(target),
    repositories: arrayRecords(record(parsed).repositories),
    credentials: credentialSummaries(gitea, repos),
    remote: parsed ?? compactCapture(result, { full: true }),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

async function mirrorSync(config: UniDeskConfig, options: MirrorOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  if (gitea.sourceAuthority.webhookSync.enabled) {
    return {
      ok: false,
      action: "platform-infra-gitea-mirror-sync",
      mutation: false,
      mode: "automatic-source-authority-manual-sync-disabled",
      target: targetSummary(target),
      error: "manual mirror sync is disabled while GitHub webhook durable source authority is enabled; the durable controller owns automatic convergence",
      next: mirrorReadOnlyNextCommands(target.id),
    };
  }
  if (!options.confirm) return { ok: false, action: "platform-infra-gitea-mirror-sync", mutation: false, mode: "missing-confirm", error: "mirror sync requires --confirm" };
  const repos = selectedRepositories(gitea, target, options.repoKey);
  const secrets = ensureMirrorSecrets(gitea, target, repos, false, false, false);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-sync", gitea, target, "", { ...options, dryRun: false, wait: false }, { repos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-mirror-sync",
    mutation: true,
    target: targetSummary(target),
    repositories: arrayRecords(record(parsed).repositories),
    sourceBundles: arrayRecords(record(parsed).sourceBundles),
    remote: parsed ?? compactCapture(result, { full: true }),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

async function mirrorWebhookApply(config: UniDeskConfig, options: MirrorOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  if (!gitea.sourceAuthority.webhookSync.enabled) return { ok: false, action: "platform-infra-gitea-mirror-webhook-apply", mutation: false, error: "sourceAuthority.webhookSync.enabled is false" };
  if (!options.confirm) return { ok: false, action: "platform-infra-gitea-mirror-webhook-apply", mutation: false, mode: "missing-confirm", error: "mirror webhook apply requires --confirm" };
  const repos = selectedRepositories(gitea, target, options.repoKey);
  const secrets = ensureMirrorSecrets(gitea, target, repos, false, false, false);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-webhook-apply", gitea, target, "", { ...options, dryRun: false, wait: false }, { repos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-mirror-webhook-apply",
    mutation: true,
    target: targetSummary(target),
    webhook: webhookSyncSummary(gitea, target),
    repositories: arrayRecords(record(parsed).repositories),
    remote: parsed ?? compactCapture(result, { full: true }),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

async function mirrorWebhookStatus(config: UniDeskConfig, options: MirrorWebhookStatusOptions): Promise<Record<string, unknown>> {
  const gitea = readGiteaConfig();
  const target = resolveCommandTarget(gitea, options.targetId);
  const repos = selectedRepositories(gitea, target, options.repoKey);
  const credentials = credentialSummaries(gitea, repos);
  const blockers = credentialBlockers(credentials);
  if (blockers.length > 0) return buildMirrorWebhookCredentialBlockedResult(gitea, target, repos, credentials, blockers);
  const secrets = ensureMirrorSecrets(gitea, target, repos, false, false, false);
  const result = await capture(config, target.route, ["sh"], remoteScript("mirror-webhook-status", gitea, target, "", { ...options, confirm: false, dryRun: true, wait: false }, { repos, secrets }).script);
  const parsed = parseJsonOutput(result.stdout);
  const repositories = arrayRecords(record(parsed).repositories);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-gitea-mirror-webhook-status",
    mutation: false,
    target: targetSummary(target),
    webhook: webhookSyncSummary(gitea, target),
    repositories,
    bridge: record(parsed).bridge,
    bridgeLogs: record(parsed).bridgeLogs,
    mirrorStatus: record(parsed).mirrorStatus,
    remote: parsed ?? compactCapture(result, { full: true }),
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

export function buildMirrorWebhookCredentialBlockedResult(
  gitea: GiteaConfig,
  target: GiteaTarget,
  repos: GiteaMirrorRepository[],
  credentials: Array<Record<string, unknown>>,
  blockers: string[],
): Record<string, unknown> {
  return {
    ok: false,
    action: "platform-infra-gitea-mirror-webhook-status",
    mutation: false,
    credentialBlocked: true,
    target: targetSummary(target),
    webhook: webhookSyncSummary(gitea, target),
    repositories: repos.map((repo) => repositorySummary(gitea, repo)),
    credentials,
    error: { code: "github-credential-unavailable", blockers, valuesPrinted: false },
    next: mirrorReadOnlyNextCommands(target.id),
  };
}

export function renderManifest(gitea: GiteaConfig, target: GiteaTarget): string {
  const app = gitea.app;
  const image = `${app.image.repository}:${app.image.tag}`;
  const labels = `    app.kubernetes.io/name: ${app.name}
    app.kubernetes.io/component: gitea
    app.kubernetes.io/part-of: devops-infra
    app.kubernetes.io/managed-by: unidesk`;
  return `apiVersion: v1
kind: Namespace
metadata:
  name: ${target.namespace}
  labels:
    app.kubernetes.io/name: devops-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: ${target.namespace}
  labels:
${labels}
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - {}
  egress:
    - {}
---
apiVersion: v1
kind: Service
metadata:
  name: ${app.serviceName}
  namespace: ${target.namespace}
  labels:
${labels}
  annotations:
    unidesk.ai/spec: ${yamlQuote(gitea.metadata.spec)}
    unidesk.ai/parent-config-ref: ${yamlQuote(gitea.migration.parentConfigRef)}
spec:
  type: ${app.service.type}
  selector:
    app.kubernetes.io/name: ${app.name}
    app.kubernetes.io/component: gitea
  ports:
    - name: http
      port: ${app.service.httpPort}
      targetPort: http
      protocol: TCP
    - name: ssh
      port: ${app.service.sshPort}
      targetPort: ssh
      protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ${app.statefulSetName}
  namespace: ${target.namespace}
  labels:
${labels}
  annotations:
    unidesk.ai/spec: ${yamlQuote(gitea.metadata.spec)}
    unidesk.ai/env-reuse-policy: ${yamlQuote(gitea.migration.envReusePolicy)}
spec:
  serviceName: ${app.serviceName}
  replicas: ${app.replicas}
  selector:
    matchLabels:
      app.kubernetes.io/name: ${app.name}
      app.kubernetes.io/component: gitea
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ${app.name}
        app.kubernetes.io/component: gitea
        app.kubernetes.io/part-of: devops-infra
        app.kubernetes.io/managed-by: unidesk
      annotations:
        unidesk.ai/runtime-plane: ${yamlQuote(gitea.migration.runtimePlane)}
        unidesk.ai/build-plane: ${yamlQuote(gitea.migration.buildPlane)}
    spec:
      securityContext:
        runAsUser: ${app.securityContext.runAsUser}
        runAsGroup: ${app.securityContext.runAsGroup}
        fsGroup: ${app.securityContext.fsGroup}
        fsGroupChangePolicy: OnRootMismatch
      containers:
        - name: gitea
          image: ${image}
          imagePullPolicy: ${app.image.pullPolicy}
          ports:
            - name: http
              containerPort: ${app.service.httpPort}
            - name: ssh
              containerPort: ${app.service.sshPort}
          env:
${envVars(gitea, target)}
          readinessProbe:
            httpGet:
              path: ${app.probes.healthPath}
              port: http
            initialDelaySeconds: ${app.probes.initialDelaySeconds}
            periodSeconds: ${app.probes.periodSeconds}
            timeoutSeconds: ${app.probes.timeoutSeconds}
            failureThreshold: ${app.probes.failureThreshold}
          livenessProbe:
            httpGet:
              path: ${app.probes.healthPath}
              port: http
            initialDelaySeconds: ${app.probes.initialDelaySeconds}
            periodSeconds: ${app.probes.periodSeconds}
            timeoutSeconds: ${app.probes.timeoutSeconds}
            failureThreshold: ${app.probes.failureThreshold}
          resources:
            requests:
              cpu: ${yamlQuote(app.resources.requests.cpu)}
              memory: ${yamlQuote(app.resources.requests.memory)}
            limits:
              cpu: ${yamlQuote(app.resources.limits.cpu)}
              memory: ${yamlQuote(app.resources.limits.memory)}
          volumeMounts:
            - name: data
              mountPath: ${app.storage.data.mountPath}
            - name: config
              mountPath: ${app.storage.config.mountPath}
  volumeClaimTemplates:
    - metadata:
        name: data
        labels:
          app.kubernetes.io/name: ${app.name}
          app.kubernetes.io/component: gitea
          app.kubernetes.io/part-of: devops-infra
          app.kubernetes.io/managed-by: unidesk
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: ${target.storageClassName}
        resources:
          requests:
            storage: ${app.storage.data.size}
    - metadata:
        name: config
        labels:
          app.kubernetes.io/name: ${app.name}
          app.kubernetes.io/component: gitea
          app.kubernetes.io/part-of: devops-infra
          app.kubernetes.io/managed-by: unidesk
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: ${target.storageClassName}
        resources:
          requests:
            storage: ${app.storage.config.size}
${renderGithubSyncManifest(gitea, target)}`;
}

function renderGithubSyncManifest(gitea: GiteaConfig, target: GiteaTarget): string {
  const sync = targetWebhookSync(gitea, target);
  if (!sync.enabled) return "";
  const labels = `    app.kubernetes.io/name: ${sync.bridge.deploymentName}
    app.kubernetes.io/component: github-to-gitea-sync
    app.kubernetes.io/part-of: devops-infra
    app.kubernetes.io/managed-by: unidesk`;
  const reposJson = JSON.stringify(repositoriesForTarget(gitea, target).map(remoteRepoSpec), null, 2);
  const serverSource = readFileSync(githubSyncServerFile, "utf8");
  const entrypointSource = readFileSync(githubSyncEntrypointFile, "utf8");
  const bridgeInitCommand = sync.bridge.initCommand.map((argument) => `            - ${yamlQuote(argument)}`).join("\n");
  const ownsHookReconcile = sync.hookReconcile.enabled && sync.hookReconcile.ownerTargetId.toLowerCase() === target.id.toLowerCase();
  const hookTopologyJson = ownsHookReconcile ? JSON.stringify(githubHookTopology(gitea), null, 2) : "";
  const hookReconcilerSource = ownsHookReconcile ? readFileSync(githubHookReconcilerFile, "utf8") : "";
  const bridgeTokenEnv = githubTokenSecretEnv(gitea, target, false);
  const hookTokenEnv = githubTokenSecretEnv(gitea, target, true);
  const hookReconcilerConfig = ownsHookReconcile ? `  hook-topology.json: |
${indentBlock(hookTopologyJson, 4)}
  platform_infra_gitea_hook_reconciler.py: |
${indentBlock(hookReconcilerSource, 4)}
` : "";
  const hookRecoveryStateEnv = ownsHookReconcile && sync.hookReconcile.failedDeliveryRecovery.enabled
    ? `            - name: UNIDESK_GITEA_HOOK_RECOVERY_STATE_PATH
              value: ${yamlQuote(sync.hookReconcile.failedDeliveryRecovery.statePath)}
`
    : "";
  const hookReconcilerContainer = ownsHookReconcile ? `
        - name: github-hook-topology-reconciler
          image: ${sync.bridge.image}
          imagePullPolicy: IfNotPresent
          command:
            - python3
            - /etc/gitea-github-sync/platform_infra_gitea_hook_reconciler.py
            - /etc/gitea-github-sync/hook-topology.json
          env:
            - name: UNIDESK_GITEA_TARGET_ID
              value: ${yamlQuote(target.id)}
            - name: UNIDESK_GITEA_GITHUB_DEFAULT_TOKEN_ENV
              value: ${yamlQuote(githubTokenEnvName(gitea.sourceAuthority.credentials.github.gitFetchCredential.secretRef.key))}
${hookTokenEnv}
            - name: GITHUB_WEBHOOK_SECRET
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: github-webhook-secret
            - name: HTTPS_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.enabled ? gitea.sourceAuthority.githubProxy.url : "")}
            - name: HTTP_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.enabled ? gitea.sourceAuthority.githubProxy.url : "")}
            - name: NO_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.noProxy.join(","))}
          volumeMounts:
            - name: config
              mountPath: /etc/gitea-github-sync
              readOnly: true
            - name: durable-inbox
              mountPath: ${sync.bridge.inbox.path}` : "";
  const configHash = createHash("sha256")
    .update(reposJson)
    .update("\0")
    .update(serverSource)
    .update("\0")
    .update(entrypointSource)
    .update("\0")
    .update(hookTopologyJson)
    .update("\0")
    .update(hookReconcilerSource)
    .digest("hex")
    .slice(0, 16);
  const gate = sync.bridge.candidateGate;
  const candidateManifest = gate.enabled ? `---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ${gate.configMapName}
  namespace: ${target.namespace}
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
    argocd.argoproj.io/sync-wave: "-2"
  labels:
${labels}
data:
  repos.json: |
${indentBlock(reposJson, 4)}
  server.mjs: |
${indentBlock(serverSource, 4)}
  entrypoint.mjs: |
${indentBlock(entrypointSource, 4)}
---
apiVersion: batch/v1
kind: Job
metadata:
  name: ${gate.jobName}
  namespace: ${target.namespace}
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded
    argocd.argoproj.io/sync-wave: "-1"
  labels:
${labels}
spec:
  backoffLimit: 0
  activeDeadlineSeconds: ${gate.activeDeadlineSeconds}
  ttlSecondsAfterFinished: ${gate.ttlSecondsAfterFinished}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ${sync.bridge.deploymentName}
        app.kubernetes.io/component: github-to-gitea-sync-candidate
        app.kubernetes.io/part-of: devops-infra
        app.kubernetes.io/managed-by: unidesk
    spec:
      restartPolicy: Never
      containers:
        - name: candidate-startup-gate
          image: ${sync.bridge.image}
          imagePullPolicy: IfNotPresent
          command:
${bridgeInitCommand}
            - /bin/sh
            - -eu
            - -c
            - |
              node /etc/gitea-github-sync-candidate/entrypoint.mjs &
              server_pid=$!
              trap 'kill "$server_pid" 2>/dev/null || true' EXIT INT TERM
              node --input-type=module - ${gate.healthTimeoutMs} ${gate.pollIntervalMs} <<'NODE'
              const timeoutMs = Number.parseInt(process.argv[2], 10);
              const pollIntervalMs = Number.parseInt(process.argv[3], 10);
              const deadline = Date.now() + timeoutMs;
              let lastError = "candidate-not-ready";
              while (Date.now() < deadline) {
                try {
                  const response = await fetch("http://127.0.0.1:${sync.bridge.httpPort}/healthz");
                  const body = await response.json();
                  if (response.ok && body.ok === true && body.durableInbox?.storageReady === true) {
                    console.log(JSON.stringify({ ok: true, gate: "gitea-github-sync-candidate-startup", storageReady: true, valuesPrinted: false }));
                    process.exit(0);
                  }
                  lastError = "health-status-" + response.status;
                } catch (error) {
                  lastError = String(error?.cause?.code || error?.message || error);
                }
                await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
              }
              console.error(JSON.stringify({ ok: false, gate: "gitea-github-sync-candidate-startup", errorType: "candidate-health-timeout", error: lastError, valuesPrinted: false }));
              process.exit(1);
              NODE
          env:
            - name: UNIDESK_GITEA_WEBHOOK_PORT
              value: ${yamlQuote(String(sync.bridge.httpPort))}
            - name: UNIDESK_GITEA_WEBHOOK_PATH
              value: ${yamlQuote(sync.publicPath)}
            - name: UNIDESK_GITEA_WEBHOOK_RESPONSE_BUDGET_MS
              value: ${yamlQuote(String(sync.responseBudgetMs))}
            - name: UNIDESK_GITEA_REPOS_PATH
              value: /etc/gitea-github-sync-candidate/repos.json
            - name: UNIDESK_GITEA_SERVICE_BASE_URL
              value: ${yamlQuote(`http://${gitea.app.serviceName}.${target.namespace}.svc.cluster.local:${gitea.app.service.httpPort}`)}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_MAX_ATTEMPTS
              value: ${yamlQuote(String(sync.bridge.retry.maxAttempts))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_INITIAL_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.initialDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_MAX_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.maxDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_TERMINAL_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.terminalRetryDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_WORKER_ATTEMPT_TIMEOUT_MS
              value: ${yamlQuote(String(sync.bridge.retry.attemptTimeoutMs))}
            - name: UNIDESK_GITEA_WEBHOOK_WORKER_SCAN_INTERVAL_MS
              value: ${yamlQuote(String(sync.bridge.retry.scanIntervalMs))}
            - name: UNIDESK_GITEA_WEBHOOK_MAX_BODY_BYTES
              value: ${yamlQuote(String(sync.ingressRetry.maxBodyBytes))}
            - name: UNIDESK_GITEA_WEBHOOK_INBOX_PATH
              value: ${yamlQuote(sync.bridge.inbox.path)}
            - name: UNIDESK_GITEA_WEBHOOK_INBOX_MAX_BYTES
              value: ${yamlQuote(String(sync.bridge.inbox.maxBytes))}
            - name: UNIDESK_GITEA_WEBHOOK_COMMITTED_RETENTION_SECONDS
              value: ${yamlQuote(String(sync.bridge.inbox.committedRetentionSeconds))}
            - name: UNIDESK_GITEA_WEBHOOK_CLEANUP_INTERVAL_MS
              value: ${yamlQuote(String(sync.bridge.inbox.cleanupIntervalMs))}
            - name: UNIDESK_GITEA_WEBHOOK_SHUTDOWN_GRACE_MS
              value: ${yamlQuote(String(sync.bridge.shutdownGraceMs))}
            - name: UNIDESK_GITEA_GITHUB_DEFAULT_TOKEN_ENV
              value: ${yamlQuote(githubTokenEnvName(gitea.sourceAuthority.credentials.github.gitFetchCredential.secretRef.key))}
${bridgeTokenEnv}
            - name: GITEA_USERNAME
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: gitea-username
            - name: GITEA_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: gitea-password
            - name: GITHUB_WEBHOOK_SECRET
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: github-webhook-secret
          volumeMounts:
            - name: candidate-config
              mountPath: /etc/gitea-github-sync-candidate
              readOnly: true
            - name: candidate-inbox
              mountPath: ${sync.bridge.inbox.path}
      volumes:
        - name: candidate-config
          configMap:
            name: ${gate.configMapName}
        - name: candidate-inbox
          emptyDir: {}
` : "";
  return `${candidateManifest}---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ${sync.bridge.serviceAccountName}
  namespace: ${target.namespace}
  labels:
${labels}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ${sync.bridge.configMapName}
  namespace: ${target.namespace}
  labels:
${labels}
data:
  repos.json: |
${indentBlock(reposJson, 4)}
  server.mjs: |
${indentBlock(serverSource, 4)}
  entrypoint.mjs: |
${indentBlock(entrypointSource, 4)}
${hookReconcilerConfig}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ${sync.bridge.inbox.claimName}
  namespace: ${target.namespace}
  labels:
${labels}
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ${target.storageClassName}
  resources:
    requests:
      storage: ${sync.bridge.inbox.storageSize}
---
apiVersion: v1
kind: Service
metadata:
  name: ${sync.bridge.serviceName}
  namespace: ${target.namespace}
  labels:
${labels}
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: ${sync.bridge.deploymentName}
    app.kubernetes.io/component: github-to-gitea-sync
  ports:
    - name: http
      port: ${sync.bridge.httpPort}
      targetPort: http
      protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${sync.bridge.deploymentName}
  namespace: ${target.namespace}
  labels:
${labels}
  annotations:
    unidesk.ai/sync-direction: ${yamlQuote(sync.direction)}
    unidesk.ai/public-path: ${yamlQuote(sync.publicPath)}
spec:
  replicas: ${sync.bridge.replicas}
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: ${sync.bridge.deploymentName}
      app.kubernetes.io/component: github-to-gitea-sync
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ${sync.bridge.deploymentName}
        app.kubernetes.io/component: github-to-gitea-sync
        app.kubernetes.io/part-of: devops-infra
        app.kubernetes.io/managed-by: unidesk
      annotations:
        unidesk.ai/github-sync-config-sha: ${yamlQuote(configHash)}
    spec:
      serviceAccountName: ${sync.bridge.serviceAccountName}
      terminationGracePeriodSeconds: ${Math.ceil(sync.bridge.shutdownGraceMs / 1000) + 5}
      containers:
        - name: github-to-gitea-sync
          image: ${sync.bridge.image}
          imagePullPolicy: IfNotPresent
          command:
${bridgeInitCommand}
            - node
            - /etc/gitea-github-sync/entrypoint.mjs
          ports:
            - name: http
              containerPort: ${sync.bridge.httpPort}
          env:
            - name: UNIDESK_GITEA_WEBHOOK_PORT
              value: ${yamlQuote(String(sync.bridge.httpPort))}
            - name: UNIDESK_GITEA_WEBHOOK_PATH
              value: ${yamlQuote(sync.publicPath)}
            - name: UNIDESK_GITEA_WEBHOOK_RESPONSE_BUDGET_MS
              value: ${yamlQuote(String(sync.responseBudgetMs))}
            - name: UNIDESK_GITEA_REPOS_PATH
              value: /etc/gitea-github-sync/repos.json
            - name: UNIDESK_GITEA_SERVICE_BASE_URL
              value: ${yamlQuote(`http://${gitea.app.serviceName}.${target.namespace}.svc.cluster.local:${gitea.app.service.httpPort}`)}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_MAX_ATTEMPTS
              value: ${yamlQuote(String(sync.bridge.retry.maxAttempts))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_INITIAL_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.initialDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_MAX_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.maxDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_RETRY_TERMINAL_DELAY_MS
              value: ${yamlQuote(String(sync.bridge.retry.terminalRetryDelayMs))}
            - name: UNIDESK_GITEA_WEBHOOK_WORKER_ATTEMPT_TIMEOUT_MS
              value: ${yamlQuote(String(sync.bridge.retry.attemptTimeoutMs))}
            - name: UNIDESK_GITEA_WEBHOOK_WORKER_SCAN_INTERVAL_MS
              value: ${yamlQuote(String(sync.bridge.retry.scanIntervalMs))}
            - name: UNIDESK_GITEA_WEBHOOK_MAX_BODY_BYTES
              value: ${yamlQuote(String(sync.ingressRetry.maxBodyBytes))}
            - name: UNIDESK_GITEA_WEBHOOK_INBOX_PATH
              value: ${yamlQuote(sync.bridge.inbox.path)}
${hookRecoveryStateEnv}            - name: UNIDESK_GITEA_WEBHOOK_INBOX_MAX_BYTES
              value: ${yamlQuote(String(sync.bridge.inbox.maxBytes))}
            - name: UNIDESK_GITEA_WEBHOOK_COMMITTED_RETENTION_SECONDS
              value: ${yamlQuote(String(sync.bridge.inbox.committedRetentionSeconds))}
            - name: UNIDESK_GITEA_WEBHOOK_CLEANUP_INTERVAL_MS
              value: ${yamlQuote(String(sync.bridge.inbox.cleanupIntervalMs))}
            - name: UNIDESK_GITEA_WEBHOOK_SHUTDOWN_GRACE_MS
              value: ${yamlQuote(String(sync.bridge.shutdownGraceMs))}
            - name: UNIDESK_GITEA_GITHUB_DEFAULT_TOKEN_ENV
              value: ${yamlQuote(githubTokenEnvName(gitea.sourceAuthority.credentials.github.gitFetchCredential.secretRef.key))}
${bridgeTokenEnv}
            - name: GITEA_USERNAME
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: gitea-username
            - name: GITEA_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: gitea-password
            - name: GITHUB_WEBHOOK_SECRET
              valueFrom:
                secretKeyRef:
                  name: ${sync.bridge.secretName}
                  key: github-webhook-secret
            - name: HTTPS_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.enabled ? gitea.sourceAuthority.githubProxy.url : "")}
            - name: HTTP_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.enabled ? gitea.sourceAuthority.githubProxy.url : "")}
            - name: NO_PROXY
              value: ${yamlQuote(gitea.sourceAuthority.githubProxy.noProxy.join(","))}
          readinessProbe:
            httpGet:
              path: /healthz
              port: http
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          volumeMounts:
            - name: config
              mountPath: /etc/gitea-github-sync
              readOnly: true
            - name: durable-inbox
              mountPath: ${sync.bridge.inbox.path}
${hookReconcilerContainer}
      volumes:
        - name: config
          configMap:
            name: ${sync.bridge.configMapName}
        - name: durable-inbox
          persistentVolumeClaim:
            claimName: ${sync.bridge.inbox.claimName}
`;
}

export function renderGiteaWebhookSyncDesiredManifest(targetId: string): string {
  const gitea = readGiteaConfig();
  const delivery = gitea.sourceAuthority.webhookSync.gitOpsDelivery;
  const target = resolveTarget(gitea, targetId);
  if (!delivery.enabled) throw new Error(`${configLabel}.sourceAuthority.webhookSync.gitOpsDelivery.enabled must be true`);
  if (target.id !== delivery.targetId) throw new Error(`GitOps delivery target ${delivery.targetId} does not match requested target ${target.id}`);
  return [
    renderManifest(gitea, target).trim(),
    renderLegacyPublicExposureCleanupManifest(gitea, target).trim(),
    renderPlatformInfraGiteaDesiredFragments(target.id).trim(),
  ].filter((item) => item.length > 0).join("\n---\n") + "\n";
}

function renderLegacyPublicExposureCleanupManifest(gitea: GiteaConfig, target: GiteaTarget): string {
  const cleanup = gitea.app.publicExposure.legacyCleanup;
  if (!cleanup.enabled) return "";
  const labels = `app.kubernetes.io/name: ${cleanup.jobName}
app.kubernetes.io/component: legacy-public-exposure-cleanup
app.kubernetes.io/part-of: devops-infra
app.kubernetes.io/managed-by: unidesk`;
  const rbac = `apiVersion: v1
kind: ServiceAccount
metadata:
  name: ${cleanup.serviceAccountName}
  namespace: ${target.namespace}
  labels:
${indentBlock(labels, 4)}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ${cleanup.serviceAccountName}
  namespace: ${target.namespace}
  labels:
${indentBlock(labels, 4)}
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    resourceNames: [${yamlQuote(cleanup.deploymentName)}]
    verbs: ["get", "delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: [${yamlQuote(cleanup.secretName)}]
    verbs: ["get", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ${cleanup.serviceAccountName}
  namespace: ${target.namespace}
  labels:
${indentBlock(labels, 4)}
subjects:
  - kind: ServiceAccount
    name: ${cleanup.serviceAccountName}
    namespace: ${target.namespace}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ${cleanup.serviceAccountName}
`;
  if (!cleanup.execute) return rbac;
  return `${rbac.trim()}
---
apiVersion: batch/v1
kind: Job
metadata:
  name: ${cleanup.jobName}
  namespace: ${target.namespace}
  labels:
${indentBlock(labels, 4)}
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded
spec:
  activeDeadlineSeconds: ${cleanup.activeDeadlineSeconds}
  ttlSecondsAfterFinished: ${cleanup.ttlSecondsAfterFinished}
  backoffLimit: 0
  template:
    metadata:
      labels:
${indentBlock(labels, 8)}
    spec:
      serviceAccountName: ${cleanup.serviceAccountName}
      restartPolicy: Never
      containers:
        - name: cleanup
          image: ${cleanup.image}
          imagePullPolicy: Always
          command: ["kubectl"]
          args:
            - -n
            - ${target.namespace}
            - delete
            - deployment/${cleanup.deploymentName}
            - secret/${cleanup.secretName}
            - --ignore-not-found
            - --wait=false
`;
}

export function readGiteaWebhookGitOpsDelivery(): GiteaWebhookGitOpsDelivery {
  return readGiteaConfig().sourceAuthority.webhookSync.gitOpsDelivery;
}

function envVars(gitea: GiteaConfig, target: GiteaTarget): string {
  const app = gitea.app;
  const values: Record<string, string> = {
    GITEA_WORK_DIR: app.storage.data.mountPath,
    GITEA__security__INSTALL_LOCK: "true",
    GITEA__server__PROTOCOL: app.server.protocol,
    GITEA__server__DOMAIN: app.server.domain,
    GITEA__server__ROOT_URL: app.server.rootUrl,
    GITEA__server__HTTP_ADDR: "0.0.0.0",
    GITEA__server__HTTP_PORT: String(app.service.httpPort),
    GITEA__server__SSH_DOMAIN: app.server.sshDomain,
    GITEA__server__SSH_PORT: String(app.service.sshPort),
    GITEA__server__START_SSH_SERVER: app.server.startSshServer ? "true" : "false",
    GITEA__database__DB_TYPE: app.database.type,
    GITEA__database__PATH: app.database.path,
    GITEA__repository__ROOT: `${app.storage.data.mountPath}/git/repositories`,
    GITEA__actions__ENABLED: app.actions.enabled ? "true" : "false",
    GITEA__webhook__ALLOWED_HOST_LIST: app.webhook.allowedHostList,
    GITEA__service__DISABLE_REGISTRATION: app.registration.disabled ? "true" : "false",
    GITEA__log__LEVEL: "Info",
    UNIDESK_GITEA_TARGET: target.id,
  };
  return Object.entries(values).map(([name, value]) => `            - name: ${name}
              value: ${yamlQuote(value)}`).join("\n");
}

function remoteScript(action: "apply" | "status" | "validate" | "mirror-preflight" | "mirror-bootstrap" | "mirror-sync" | "mirror-status" | "mirror-webhook-apply" | "mirror-webhook-status", gitea: GiteaConfig, target: GiteaTarget, manifest: string, options: ApplyOptions | MirrorOptions, params: MirrorRemoteParams = {}): { script: string; payloadSummary: Record<string, unknown> } {
  const sync = targetWebhookSync(gitea, target);
  const selectedRepositories = params.repos ?? repositoriesForTarget(gitea, target);
  const selectedCredentials = githubCredentialsForConsumers(gitea, target, selectedRepositories, false);
  const defaultCredential = selectedCredentials[0] ?? gitea.sourceAuthority.credentials.github;
  const env: Record<string, string> = {
    UNIDESK_GITEA_ACTION: action,
    UNIDESK_GITEA_TARGET_ID: target.id,
    UNIDESK_GITEA_ROUTE: target.route,
    UNIDESK_GITEA_NAMESPACE: target.namespace,
    UNIDESK_GITEA_APP_NAME: gitea.app.name,
    UNIDESK_GITEA_STATEFULSET_NAME: gitea.app.statefulSetName,
    UNIDESK_GITEA_SERVICE_NAME: gitea.app.serviceName,
    UNIDESK_GITEA_HTTP_PORT: String(gitea.app.service.httpPort),
    UNIDESK_GITEA_HEALTH_PATH: gitea.validation.healthPath,
    UNIDESK_GITEA_IMAGE: `${gitea.app.image.repository}:${gitea.app.image.tag}`,
    UNIDESK_GITEA_FIELD_MANAGER: fieldManager,
    UNIDESK_GITEA_WAIT_TIMEOUT_SECONDS: String(gitea.validation.waitTimeoutSeconds),
    UNIDESK_GITEA_DRY_RUN: options.dryRun ? "1" : "0",
    UNIDESK_GITEA_WAIT: options.wait ? "1" : "0",
    UNIDESK_GITEA_FULL: options.full ? "1" : "0",
    UNIDESK_GITEA_ROOT_URL: gitea.app.server.rootUrl,
    UNIDESK_GITEA_GITHUB_PROXY_ENABLED: gitea.sourceAuthority.githubProxy.enabled ? "1" : "0",
    UNIDESK_GITEA_GITHUB_PROXY_URL: gitea.sourceAuthority.githubProxy.url,
    UNIDESK_GITEA_GITHUB_SECRET_KEY: defaultCredential.gitFetchCredential.secretRef.key,
    UNIDESK_GITEA_GITHUB_DEFAULT_TOKEN_ENV: githubTokenEnvName(defaultCredential.gitFetchCredential.secretRef.key),
    UNIDESK_GITEA_GITHUB_SECRET_ENV_MAP: selectedCredentials
      .map((credential) => `${credential.gitFetchCredential.secretRef.key}=${githubTokenEnvName(credential.gitFetchCredential.secretRef.key)}`)
      .join(","),
    UNIDESK_GITEA_NO_PROXY: gitea.sourceAuthority.githubProxy.noProxy.join(","),
    UNIDESK_GITEA_FRPC_DEPLOYMENT_NAME: gitea.app.publicExposure.legacyCleanup.deploymentName,
    UNIDESK_GITEA_FRPC_SECRET_NAME: gitea.app.publicExposure.legacyCleanup.secretName,
    UNIDESK_GITEA_WEBHOOK_SYNC_ENABLED: gitea.sourceAuthority.webhookSync.enabled ? "1" : "0",
    UNIDESK_GITEA_WEBHOOK_PUBLIC_URL: githubWebhookPublicUrl(gitea, target),
    UNIDESK_GITEA_WEBHOOK_PATH: sync.publicPath,
    UNIDESK_GITEA_WEBHOOK_EVENTS: sync.events.join(","),
    UNIDESK_GITEA_WEBHOOK_DEPLOYMENT: sync.bridge.deploymentName,
    UNIDESK_GITEA_WEBHOOK_SERVICE: sync.bridge.serviceName,
    UNIDESK_GITEA_WEBHOOK_SERVICE_PORT: String(sync.bridge.httpPort),
    UNIDESK_GITEA_WEBHOOK_SECRET_NAME: sync.bridge.secretName,
  };
  if (params.secrets !== undefined) {
    env.UNIDESK_GITEA_ADMIN_USERNAME = params.secrets.adminUsername;
    env.UNIDESK_GITEA_ADMIN_PASSWORD = params.secrets.adminPassword;
    for (const [key, token] of Object.entries(params.secrets.githubTokens)) env[githubTokenEnvName(key)] = token;
    env.UNIDESK_GITEA_GITHUB_SECRET_ENV_MAP = Object.keys(params.secrets.githubTokens)
      .sort()
      .map((key) => `${key}=${githubTokenEnvName(key)}`)
      .join(",");
    env.UNIDESK_GITEA_GITHUB_WEBHOOK_SECRET = params.secrets.webhookSecret;
  }
  const exports = Object.entries(env).map(([key, value]) => `export ${key}=${shQuote(value)}`).join("\n");
  const payloads = {
    manifest,
    repositories: JSON.stringify((params.repos ?? []).map((repo) => remoteRepoSpec(repo))),
    hookTopology: JSON.stringify(githubHookTopology(gitea)),
    statusEvaluator: readFileSync(statusEvaluatorFile, "utf8"),
  };
  return {
    script: `${exports}\n${renderGiteaRemotePayloadMaterializer(payloads)}\n${readFileSync(remoteScriptFile, "utf8")}`,
    payloadSummary: summarizeGiteaRemotePayloads(payloads),
  };
}

function policyChecks(gitea: GiteaConfig, target: GiteaTarget, manifest: string): Array<Record<string, unknown>> {
  const sync = targetWebhookSync(gitea, target);
  const delivery = sync.gitOpsDelivery;
  return [
    { name: "yaml-source-of-truth", ok: true, detail: "Gitea target, namespace, image, storage, ports and probes are read from config/platform-infra/gitea.yaml." },
    { name: "gitea-pac-service-contract", ok: target.namespace === "devops-infra" && gitea.app.serviceName === "gitea-http", detail: "The service matches the active Gitea source authority consumed by config/platform-infra/pipelines-as-code.yaml." },
    { name: "cluster-internal-only", ok: !/^\s*type:\s*(NodePort|LoadBalancer)\s*$/mu.test(manifest) && !/^\s*kind:\s*Ingress\s*$/mu.test(manifest), detail: "Gitea is ClusterIP-only for the POC." },
    { name: "runtime-zero-docker", ok: !manifest.includes("/var/run/docker.sock") && !/^\s*hostPath:\s*$/mu.test(manifest), detail: "Runtime Gitea does not mount Docker socket or hostPath." },
    { name: "rootless-image", ok: /-rootless$/u.test(gitea.app.image.tag), detail: "The runtime image is Gitea rootless." },
    { name: "actions-not-trigger-authority", ok: gitea.app.actions.enabled, detail: "Gitea may expose its built-in Actions capability, but JD01 CI/CD trigger authority is Pipelines-as-Code, not act_runner." },
    { name: "env-reuse-preserved", ok: gitea.migration.envReusePolicy === "preserve-existing-runtime-env-reuse", detail: "This install does not replace the existing env reuse path or runtime deployment." },
    {
      name: "durable-inbox-single-writer",
      ok: sync.bridge.replicas === 1 && /strategy:\n\s+type: Recreate/u.test(manifest),
      detail: "The durable inbox has one bridge replica and Deployment strategy Recreate, so journal writes have one owner during rollout.",
    },
    {
      name: "github-hook-topology-single-writer",
      ok: !sync.hookReconcile.enabled || (
        sync.hookReconcile.ownerTargetId.toLowerCase() === target.id.toLowerCase()
          ? (manifest.match(/name: github-hook-topology-reconciler/gu) ?? []).length === 1
            && manifest.includes("platform_infra_gitea_hook_reconciler.py")
            && manifest.includes("hook-topology.json")
          : !manifest.includes("name: github-hook-topology-reconciler")
      ),
      detail: "The owning YAML selects one target-side reconciler for the complete GitHub hook topology; candidate gates and non-owner targets never write hooks.",
    },
    {
      name: "bridge-candidate-presync-gate",
      ok: sync.bridge.candidateGate.enabled
        && manifest.includes(`name: ${sync.bridge.candidateGate.configMapName}`)
        && manifest.includes(`name: ${sync.bridge.candidateGate.jobName}`)
        && manifest.includes("argocd.argoproj.io/hook: PreSync")
        && manifest.includes("app.kubernetes.io/component: github-to-gitea-sync-candidate")
        && manifest.includes("candidate-inbox\n          emptyDir: {}"),
      detail: "Argo starts the exact ConfigMap-mounted bridge candidate with an isolated inbox before replacing the single-writer Deployment.",
    },
    {
      name: "durable-inbox-pvc",
      ok: manifest.includes(`kind: PersistentVolumeClaim\nmetadata:\n  name: ${sync.bridge.inbox.claimName}`)
        && manifest.includes(`claimName: ${sync.bridge.inbox.claimName}`)
        && manifest.includes(`mountPath: ${sync.bridge.inbox.path}`),
      detail: "The webhook bridge fsync inbox path, PVC claim, capacity and retention are rendered from the owning Gitea YAML.",
    },
    {
      name: "durable-bridge-service-account",
      ok: manifest.includes(`kind: ServiceAccount\nmetadata:\n  name: ${sync.bridge.serviceAccountName}`)
        && manifest.includes(`serviceAccountName: ${sync.bridge.serviceAccountName}`),
      detail: "The bridge ServiceAccount and Deployment binding are rendered together; the bootstrap PaC task continues to use the pre-existing default ServiceAccount.",
    },
    {
      name: "independent-gitops-self-delivery",
      ok: delivery.targetId !== target.id || (delivery.enabled
        && existsSync(rootPath(".tekton", "platform-infra-gitea-nc01-pac.yaml"))
        && delivery.bootstrapApplicationPath.startsWith("deploy/gitops/unidesk-host/")
        && !delivery.desiredManifestPath.startsWith("deploy/gitops/unidesk-host/")),
      detail: "An independent PaC task publishes a child Argo Application into the existing unidesk-host bootstrap path and keeps bridge desired resources on an independent path.",
    },
  ];
}

function configSummary(gitea: GiteaConfig, target: GiteaTarget): Record<string, unknown> {
  return {
    path: configLabel,
    metadata: gitea.metadata,
    migration: gitea.migration,
    target: targetSummary(target),
    app: appSummary(gitea),
    valuesPrinted: false,
  };
}

function compactConfigSummary(gitea: GiteaConfig, target: GiteaTarget): Record<string, unknown> {
  return {
    path: configLabel,
    target: targetSummary(target),
    app: {
      image: `${gitea.app.image.repository}:${gitea.app.image.tag}`,
      serviceDns: serviceDns(gitea, target),
      rootUrl: gitea.app.server.rootUrl,
      publicBaseUrl: gitea.app.publicExposure.publicBaseUrl,
      actionsEnabled: gitea.app.actions.enabled,
    },
    valuesPrinted: false,
  };
}

function targetSummary(target: GiteaTarget): Record<string, unknown> {
  return {
    id: target.id,
    route: target.route,
    namespace: target.namespace,
    role: target.role,
    createNamespace: target.createNamespace,
    storageClassName: target.storageClassName,
    publicExposureEnabled: target.publicExposureEnabled,
    webhookSync: target.webhookSync,
  };
}

function appSummary(gitea: GiteaConfig): Record<string, unknown> {
  return {
    name: gitea.app.name,
    statefulSetName: gitea.app.statefulSetName,
    serviceName: gitea.app.serviceName,
    image: `${gitea.app.image.repository}:${gitea.app.image.tag}`,
    replicas: gitea.app.replicas,
    service: gitea.app.service,
    rootUrl: gitea.app.server.rootUrl,
    publicExposure: publicExposureSummary(gitea),
    actionsEnabled: gitea.app.actions.enabled,
    registrationDisabled: gitea.app.registration.disabled,
    storage: gitea.app.storage,
    healthPath: gitea.validation.healthPath,
  };
}

function publicExposureSummary(gitea: GiteaConfig): Record<string, unknown> {
  const exposure = gitea.app.publicExposure;
  return {
    enabled: exposure.enabled,
    publicBaseUrl: exposure.publicBaseUrl,
    upstream: exposure.upstream,
    healthPath: exposure.healthPath,
    internalReadUrlPolicy: "k3s-consumers-use-gitea-http-svc-not-public-url",
    dns: exposure.dns,
    routes: exposure.routes,
    authority: "nc01-public-edge",
    legacyCleanup: exposure.legacyCleanup,
    valuesPrinted: false,
  };
}

function webhookSecretSummary(gitea: GiteaConfig, target: GiteaTarget, secrets: MirrorSecrets): Record<string, unknown> {
  const sync = targetWebhookSync(gitea, target);
  return {
    enabled: sync.enabled,
    publicUrl: githubWebhookPublicUrl(gitea, target),
    sourceRef: sync.secret.sourceRef,
    targetSecret: sync.bridge.secretName,
    keys: [gitea.sourceAuthority.credentials.github.gitFetchCredential.secretRef.key, "gitea-username", "gitea-password", "github-webhook-secret"],
    fingerprint: fingerprintSecretParts([secrets.webhookSecret]),
    valuesPrinted: false,
  };
}

function githubWebhookPublicUrl(gitea: GiteaConfig, target: GiteaTarget): string {
  const base = gitea.app.publicExposure.publicBaseUrl.replace(/\/+$/u, "");
  return `${base}${targetWebhookSync(gitea, target).publicPath}`;
}

function githubHookTopology(gitea: GiteaConfig): Record<string, unknown> {
  const sync = gitea.sourceAuthority.webhookSync;
  const base = gitea.app.publicExposure.publicBaseUrl.replace(/\/+$/u, "");
  const desiredByRepository = new Map<string, Map<string, { targetId: string; url: string; repoKeys: Set<string>; branches: Set<string> }>>();
  for (const repo of gitea.sourceAuthority.repositories) {
    const target = resolveTarget(gitea, repo.targetId);
    const desired = desiredByRepository.get(repo.upstream.repository) ?? new Map();
    const key = target.id.toLowerCase();
    const hook = desired.get(key) ?? {
      targetId: target.id,
      url: githubWebhookPublicUrl(gitea, target),
      repoKeys: new Set<string>(),
      branches: new Set<string>(),
    };
    hook.repoKeys.add(repo.key);
    hook.branches.add(repo.upstream.branch);
    desired.set(key, hook);
    desiredByRepository.set(repo.upstream.repository, desired);
  }
  return {
    version: 1,
    kind: "GiteaGithubHookTopology",
    ownerTargetId: sync.hookReconcile.ownerTargetId,
    managedUrlPrefix: `${base}${sync.publicPath}`,
    bridgeStatusUrl: `http://127.0.0.1:${sync.bridge.httpPort}/status`,
    events: sync.events,
    reconcile: {
      intervalMs: sync.hookReconcile.intervalMs,
      requestTimeoutMs: sync.hookReconcile.requestTimeoutMs,
      listMaxPages: sync.hookReconcile.listMaxPages,
      failedDeliveryRecovery: sync.hookReconcile.failedDeliveryRecovery,
    },
    repositories: [...desiredByRepository.entries()]
      .sort(([left], [right]) => left.localeCompare(right))
      .map(([repository, desired]) => {
        const desiredHooks = [...desired.values()]
          .sort((left, right) => left.targetId.localeCompare(right.targetId))
          .map((item) => ({
            targetId: item.targetId,
            url: item.url,
            repoKeys: [...item.repoKeys].sort(),
            branches: [...item.branches].sort(),
          }));
        const repo = gitea.sourceAuthority.repositories.find((item) => item.upstream.repository === repository);
        const credential = repo === undefined ? gitea.sourceAuthority.credentials.github : githubCredentialForRepo(gitea, repo);
        return {
          repository,
          githubTokenEnv: githubTokenEnvName(credential.gitFetchCredential.secretRef.key),
          desiredUrls: desiredHooks.map((item) => item.url).sort(),
          desiredHooks,
        };
      }),
  };
}

function statusSummary(payload: Record<string, unknown>): Record<string, unknown> {
  return {
    ready: payload.ready === true,
    target: payload.target,
    route: payload.route,
    namespace: payload.namespace,
    image: payload.image,
    serviceDns: payload.serviceDns,
    networkPolicy: payload.networkPolicy,
    statefulSet: payload.statefulSet,
    service: payload.service,
    endpointsReady: payload.endpointsReady === true,
    pods: Array.isArray(payload.pods) ? payload.pods : [],
    pvcs: Array.isArray(payload.pvcs) ? payload.pvcs : [],
    eventsTail: Array.isArray(payload.eventsTail) ? payload.eventsTail : [],
    valuesPrinted: false,
  };
}

function sourceAuthoritySummary(gitea: GiteaConfig, target: GiteaTarget): Record<string, unknown> {
  return {
    enabled: gitea.sourceAuthority.enabled,
    stage: gitea.sourceAuthority.stage,
    statusAuthority: gitea.sourceAuthority.statusAuthority,
    firstCiConsumer: gitea.sourceAuthority.firstCiConsumer,
    target: target.id,
    serviceBaseUrl: gitea.app.server.rootUrl,
    repositoryCount: repositoriesForTarget(gitea, target).length,
  };
}

function responsibilitySummary(item: GiteaSourceResponsibility): Record<string, unknown> {
  return { ...item };
}

function repositoriesForTarget(gitea: GiteaConfig, target: GiteaTarget): GiteaMirrorRepository[] {
  return gitea.sourceAuthority.repositories.filter((repo) => repo.targetId.toLowerCase() === target.id.toLowerCase());
}

function selectedRepositories(gitea: GiteaConfig, target: GiteaTarget, repoKey: string | null): GiteaMirrorRepository[] {
  const repos = repositoriesForTarget(gitea, target);
  if (repoKey === null) return repos;
  const repo = repos.find((item) => item.key === repoKey);
  if (repo === undefined) throw new CliInputError(`Unknown Gitea mirror repository key: ${repoKey}`, {
    code: "unknown-repository-key",
    argument: repoKey,
    supported: repos.map((item) => item.key),
    usage: "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <node> --repo <key>",
  });
  return [repo];
}

function repositorySummary(gitea: GiteaConfig, repo: GiteaMirrorRepository): Record<string, unknown> {
  return {
    key: repo.key,
    upstreamRepository: repo.upstream.repository,
    upstreamBranch: repo.upstream.branch,
    upstreamVisibility: repo.upstream.visibility,
    giteaOwner: repo.gitea.owner,
    giteaRepo: repo.gitea.name,
    mirrorMode: repo.gitea.mirrorMode,
    readUrl: repo.gitea.readUrl,
    snapshotPrefix: repo.snapshot.prefix,
    legacyReadUrl: repo.legacyGitMirror?.readUrl ?? null,
    legacyDisposition: repo.legacyGitMirror?.disposition ?? "native-gitea-only",
    sourceAuthority: "gitea",
    rootUrlMatches: repo.gitea.readUrl.startsWith(gitea.app.server.rootUrl),
  };
}

function remoteRepoSpec(repo: GiteaMirrorRepository): Record<string, unknown> {
  const github = repo.credentialOverride?.github;
  return {
    key: repo.key,
    upstream: repo.upstream,
    gitea: repo.gitea,
    gitops: repo.gitops,
    snapshot: repo.snapshot,
    legacyGitMirror: repo.legacyGitMirror,
    githubCredential: github === undefined ? null : {
      secretKey: github.gitFetchCredential.secretRef.key,
      tokenEnv: githubTokenEnvName(github.gitFetchCredential.secretRef.key),
    },
  };
}

function mirrorReadOnlyNextCommands(targetId: string): Record<string, string> {
  return {
    status: `bun scripts/cli.ts platform-infra gitea mirror status --target ${targetId}`,
    statusFull: `bun scripts/cli.ts platform-infra gitea mirror status --target ${targetId} --full`,
    webhookStatus: `bun scripts/cli.ts platform-infra gitea mirror webhook status --target ${targetId}`,
    webhookStatusFull: `bun scripts/cli.ts platform-infra gitea mirror webhook status --target ${targetId} --full`,
    fixManualRelease: PAC_AUTOMATIC_DELIVERY_REFERENCE,
  };
}

function webhookSyncSummary(gitea: GiteaConfig, target: GiteaTarget): Record<string, unknown> {
  const sync = targetWebhookSync(gitea, target);
  const topology = githubHookTopology(gitea);
  const targetUrl = githubWebhookPublicUrl(gitea, target);
  const ingressAttemptBudgetMs = sync.ingressRetry.enabled
    ? deriveGiteaWebhookAttemptBudgetMs(sync.responseBudgetMs, sync.ingressRetry)
    : null;
  const ingressResponseHeaderTimeoutMs = sync.ingressRetry.enabled
    ? deriveGiteaWebhookResponseHeaderTimeoutMs(sync.responseBudgetMs, sync.ingressRetry)
    : null;
  return {
    enabled: sync.enabled,
    direction: sync.direction,
    publicUrl: targetUrl,
    hookReconcile: {
      ...sync.hookReconcile,
      runningOnTarget: sync.hookReconcile.enabled && sync.hookReconcile.ownerTargetId.toLowerCase() === target.id.toLowerCase(),
      desiredUrlSha256: `sha256:${createHash("sha256").update(targetUrl).digest("hex").slice(0, 16)}`,
      topologySha256: `sha256:${createHash("sha256").update(JSON.stringify(topology)).digest("hex").slice(0, 16)}`,
    },
    events: sync.events,
    responseBudgetMs: sync.responseBudgetMs,
    ingressAttemptBudgetMs,
    ingressResponseHeaderTimeoutMs,
    ingressRetry: {
      ...sync.ingressRetry,
      method: "POST",
      bodyReplay: "request-body-size-limited-and-fully-buffered",
    },
    bridge: sync.bridge,
    gitOpsDelivery: sync.gitOpsDelivery,
    valuesPrinted: false,
  };
}

function credentialSummaries(gitea: GiteaConfig, repositories = gitea.sourceAuthority.repositories): Array<Record<string, unknown>> {
  const adminPath = credentialPath(gitea, gitea.sourceAuthority.credentials.admin.sourceRef);
  const adminLinePair = existsSync(adminPath) ? parseLinePairCredential(adminPath, gitea.sourceAuthority.credentials.admin) : { username: null, password: null };
  const summaries: Array<Record<string, unknown>> = [
    {
      id: "gitea-admin",
      sourceRef: gitea.sourceAuthority.credentials.admin.sourceRef,
      present: existsSync(adminPath),
      requiredKeysPresent: Boolean(adminLinePair.username) && Boolean(adminLinePair.password),
      fingerprint: fingerprintSecretParts([adminLinePair.username, adminLinePair.password]),
      permissionResult: { status: "not-applicable", error: null },
      valuesPrinted: false,
    },
  ];
  summaries.push(...buildGiteaMirrorBootstrapCredentialPreflight(gitea, repositories).credentials);
  return summaries;
}

function credentialBlockers(credentials: Array<Record<string, unknown>>): string[] {
  return credentials.filter((item) => item.present !== true || item.requiredKeysPresent !== true).map((item) => String(item.id));
}

function ensureMirrorSecrets(
  gitea: GiteaConfig,
  target: GiteaTarget,
  repositories: GiteaMirrorRepository[],
  includeHookOwnerCredentials: boolean,
  createAdmin: boolean,
  createWebhookSecret: boolean,
): MirrorSecrets {
  const admin = gitea.sourceAuthority.credentials.admin;
  const adminPath = credentialPath(gitea, admin.sourceRef);
  if (!existsSync(adminPath)) {
    if (!createAdmin) throw new Error(`${admin.sourceRef} is missing; run mirror bootstrap --confirm first`);
    mkdirSync(dirname(adminPath), { recursive: true });
    const username = "unidesk-admin";
    const password = `udg_${randomBytes(32).toString("base64url")}`;
    writeFileSync(adminPath, `${username}\n${password}\n`, { encoding: "utf8", mode: 0o600 });
    chmodSync(adminPath, 0o600);
  }
  const adminLinePair = parseLinePairCredential(adminPath, admin);
  const githubTokens: Record<string, string> = {};
  for (const github of githubCredentialsForConsumers(gitea, target, repositories, includeHookOwnerCredentials)) {
    const githubPath = credentialPath(gitea, github.sourceRef);
    if (!existsSync(githubPath)) throw new Error(`${github.sourceRef} is missing; cannot sync GitHub upstream`);
    const githubEnv = parseGithubCredentialFile(githubPath, github);
    const githubToken = githubEnv[github.sourceKey];
    if (!githubToken) throw new Error(`${github.sourceRef} must contain ${github.sourceKey}`);
    githubTokens[github.gitFetchCredential.secretRef.key] = githubToken;
  }
  const webhookSecret = ensureWebhookSecret(gitea, createWebhookSecret);
  const adminUsername = adminLinePair.username;
  const adminPassword = adminLinePair.password;
  if (!adminUsername || !adminPassword) throw new Error(`${admin.sourceRef} must contain username on line ${admin.usernameLine} and password on line ${admin.passwordLine}`);
  return { adminUsername, adminPassword, githubTokens, webhookSecret };
}

function githubCredentialForRepo(gitea: GiteaConfig, repo: GiteaMirrorRepository): GiteaGithubCredential {
  return repo.credentialOverride?.github ?? gitea.sourceAuthority.credentials.github;
}

function githubCredentialsForTarget(gitea: GiteaConfig, target: GiteaTarget): GiteaGithubCredential[] {
  const credentials = [gitea.sourceAuthority.credentials.github, ...repositoriesForTarget(gitea, target).flatMap((repo) => repo.credentialOverride?.github ?? [])];
  return [...new Map(credentials.map((credential) => [credential.gitFetchCredential.secretRef.key, credential])).values()];
}

function githubCredentialsForConsumers(
  gitea: GiteaConfig,
  target: GiteaTarget,
  repositories: GiteaMirrorRepository[],
  includeHookOwnerCredentials: boolean,
): GiteaGithubCredential[] {
  const credentials = repositories.map((repo) => githubCredentialForRepo(gitea, repo));
  if (includeHookOwnerCredentials
    && gitea.sourceAuthority.webhookSync.hookReconcile.ownerTargetId.toLowerCase() === target.id.toLowerCase()) {
    credentials.push(...gitea.sourceAuthority.repositories.flatMap((repo) => {
      const github = repo.credentialOverride?.github;
      return github !== undefined && github.requiredFor.some((item) => item.startsWith("github-hooks-")) ? [github] : [];
    }));
  }
  return [...new Map(credentials.map((credential) => [credential.gitFetchCredential.secretRef.key, credential])).values()];
}

function githubTokenEnvName(secretKey: string): string {
  return githubTokenEnvNameForSecretKey(secretKey);
}

function githubTokenSecretEnv(gitea: GiteaConfig, target: GiteaTarget, includeHookOwnerCredentials: boolean): string {
  const secretName = targetWebhookSync(gitea, target).bridge.secretName;
  return githubCredentialsForConsumers(gitea, target, repositoriesForTarget(gitea, target), includeHookOwnerCredentials).map((credential) => `            - name: ${githubTokenEnvName(credential.gitFetchCredential.secretRef.key)}
              valueFrom:
                secretKeyRef:
                  name: ${secretName}
                  key: ${credential.gitFetchCredential.secretRef.key}`).join("\n");
}

function ensureWebhookSecret(gitea: GiteaConfig, createIfMissing: boolean): string {
  const sync = gitea.sourceAuthority.webhookSync;
  if (!sync.enabled) return "";
  const path = credentialPath(gitea, sync.secret.sourceRef);
  if (!existsSync(path)) {
    if (!createIfMissing || !sync.secret.createIfMissing) throw new Error(`${sync.secret.sourceRef} is missing; run platform-infra gitea apply --target <node> --confirm first`);
    mkdirSync(dirname(path), { recursive: true });
    writeFileSync(path, `${sync.secret.sourceKey}=ghs_${randomBytes(32).toString("base64url")}\n`, { encoding: "utf8", mode: 0o600 });
    chmodSync(path, 0o600);
  }
  const values = parseEnvFileSafe(path);
  const value = values[sync.secret.sourceKey];
  if (!value) throw new Error(`${sync.secret.sourceRef} must contain ${sync.secret.sourceKey}`);
  return value;
}

function credentialPath(gitea: GiteaConfig, sourceRef: string): string {
  return sourceRef.startsWith("/") ? sourceRef : join(gitea.sourceAuthority.credentials.sourceRoot, sourceRef);
}

function parseLinePairCredential(path: string, admin: GiteaAdminCredential): { username: string | null; password: string | null } {
  const lines = readFileSync(path, "utf8").split(/\r?\n/u);
  return {
    username: lines[admin.usernameLine - 1]?.trim() || null,
    password: lines[admin.passwordLine - 1]?.trim() || null,
  };
}

function parseEnvFileSafe(path: string): Record<string, string> {
  const values: Record<string, string> = {};
  for (const rawLine of readFileSync(path, "utf8").split(/\r?\n/u)) {
    let line = rawLine.trim();
    if (line.length === 0 || line.startsWith("#")) continue;
    if (line.startsWith("export ")) line = line.slice("export ".length).trim();
    const eq = line.indexOf("=");
    if (eq <= 0) continue;
    const key = line.slice(0, eq).trim();
    if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) continue;
    values[key] = unquote(line.slice(eq + 1).trim());
  }
  return values;
}

function parseGithubCredentialFile(path: string, github: GiteaGithubCredential): Record<string, string> {
  const text = readFileSync(path, "utf8");
  if (github.format === "raw-token") return { [github.sourceKey]: text.trim() };
  return parseEnvTextSafe(text);
}

function parseEnvTextSafe(text: string): Record<string, string> {
  const values: Record<string, string> = {};
  for (const rawLine of text.split(/\r?\n/u)) {
    let line = rawLine.trim();
    if (line.length === 0 || line.startsWith("#")) continue;
    if (line.startsWith("export ")) line = line.slice("export ".length).trim();
    const eq = line.indexOf("=");
    if (eq <= 0) continue;
    const key = line.slice(0, eq).trim();
    if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) continue;
    values[key] = unquote(line.slice(eq + 1).trim());
  }
  return values;
}

function unquote(value: string): string {
  if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) return value.slice(1, -1);
  return value;
}

function fingerprintKeys(values: Record<string, string>, keys: string[]): string | null {
  if (keys.some((key) => !values[key])) return null;
  const hash = createHash("sha256");
  for (const key of keys.slice().sort()) {
    hash.update(key);
    hash.update("\0");
    hash.update(values[key]);
    hash.update("\0");
  }
  return `sha256:${hash.digest("hex").slice(0, 16)}`;
}

function fingerprintSecretParts(parts: Array<string | null>): string | null {
  if (parts.some((part) => !part)) return null;
  const hash = createHash("sha256");
  for (const part of parts) {
    hash.update(part ?? "");
    hash.update("\0");
  }
  return `sha256:${hash.digest("hex").slice(0, 16)}`;
}


function parseApplyOptions(args: string[]): ApplyOptions {
  const commonArgs: string[] = [];
  let confirm = false;
  let dryRun = false;
  let wait = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm") confirm = true;
    else if (arg === "--dry-run") dryRun = true;
    else if (arg === "--wait") wait = true;
    else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  if (confirm && dryRun) throw new CliInputError("Gitea apply accepts only one of --confirm or --dry-run", {
    code: "mutually-exclusive-options",
    argument: "--confirm --dry-run",
    usage: ["bun scripts/cli.ts platform-infra gitea apply --dry-run", "bun scripts/cli.ts platform-infra gitea apply --confirm"],
  });
  return { ...parseCommonOptions(commonArgs), confirm, dryRun: dryRun || !confirm, wait };
}

function parseMirrorWebhookStatusOptions(args: string[]): MirrorWebhookStatusOptions {
  const mirrorArgs: string[] = [];
  let deliveryId: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg !== "--delivery-id") {
      mirrorArgs.push(arg);
      continue;
    }
    const value = args[index + 1];
    if (value === undefined || value.startsWith("--")) throw new CliInputError("--delivery-id requires a value", {
      code: "missing-option-value",
      argument: "--delivery-id",
      usage: "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <node> [--repo <key>] --delivery-id <id>",
    });
    if (!/^[A-Za-z0-9._:-]{1,160}$/u.test(value)) throw new CliInputError("--delivery-id must be a bounded GitHub delivery identifier", {
      code: "invalid-option-value",
      argument: value,
      usage: "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <node> [--repo <key>] --delivery-id <id>",
    });
    deliveryId = value;
    index += 1;
  }
  return { ...parseMirrorOptions(mirrorArgs), deliveryId };
}

function parseMirrorOptions(args: string[]): MirrorOptions {
  const commonArgs: string[] = [];
  let confirm = false;
  let dryRun = false;
  let repoKey: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm") {
      confirm = true;
    } else if (arg === "--dry-run") {
      dryRun = true;
    } else if (arg === "--repo") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new CliInputError("--repo requires a value", {
        code: "missing-option-value",
        argument: "--repo",
        usage: "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <node> --repo <key>",
      });
      if (!/^[A-Za-z0-9._-]+$/u.test(value)) throw new CliInputError("--repo must be a simple repository key", {
        code: "invalid-option-value",
        argument: value,
        usage: "bun scripts/cli.ts platform-infra gitea mirror webhook status --target <node> --repo <key>",
      });
      repoKey = value;
      index += 1;
    } else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  if (confirm && dryRun) throw new CliInputError("Gitea mirror bootstrap accepts only one of --confirm or --dry-run", {
    code: "mutually-exclusive-options",
    argument: "--confirm --dry-run",
    usage: [
      "bun scripts/cli.ts platform-infra gitea mirror bootstrap --target <node> --dry-run",
      "bun scripts/cli.ts platform-infra gitea mirror bootstrap --target <node> --confirm",
    ],
  });
  return { ...parseCommonOptions(commonArgs), confirm, dryRun: dryRun || !confirm, wait: false, repoKey };
}

function parseCommonOptions(args: string[]): CommonOptions {
  let targetId: string | null = null;
  let full = false;
  let raw = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--target" || arg === "--node") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new CliInputError(`${arg} requires a value`, {
        code: "missing-option-value",
        argument: arg,
        usage: "bun scripts/cli.ts platform-infra gitea <command> --target <node>",
      });
      if (!/^[A-Za-z0-9._-]+$/u.test(value)) throw new CliInputError(`${arg} must be a simple target id`, {
        code: "invalid-option-value",
        argument: value,
        usage: "bun scripts/cli.ts platform-infra gitea <command> --target <node>",
      });
      targetId = value;
      index += 1;
    } else if (arg === "--full") {
      full = true;
    } else if (arg === "--raw") {
      raw = true;
      full = true;
    } else {
      throw new CliInputError(`Unsupported Gitea option: ${arg}`, {
        code: "unsupported-option",
        argument: arg,
        supported: ["--target", "--node", "--repo", "--delivery-id", "--full", "--raw"],
        usage: "bun scripts/cli.ts platform-infra gitea help",
      });
    }
  }
  return { targetId, full, raw };
}

function giteaReadOnlyNextCommands(targetId: string): Record<string, string> {
  return {
    status: `bun scripts/cli.ts platform-infra gitea status --target ${targetId}`,
    validate: `bun scripts/cli.ts platform-infra gitea validate --target ${targetId}`,
    mirrorStatus: `bun scripts/cli.ts platform-infra gitea mirror status --target ${targetId}`,
    webhookStatus: `bun scripts/cli.ts platform-infra gitea mirror webhook status --target ${targetId}`,
    fixManualRelease: PAC_AUTOMATIC_DELIVERY_REFERENCE,
  };
}

function manifestObjectSummary(yaml: string): Array<Record<string, unknown>> {
  const objects: Array<Record<string, unknown>> = [];
  for (const doc of yaml.split(/^---$/mu)) {
    const kind = doc.match(/^\s*kind:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1];
    const name = doc.match(/^\s*name:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1];
    const namespace = doc.match(/^\s*namespace:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1] ?? null;
    if (kind !== undefined && name !== undefined) objects.push({ kind, name, namespace });
  }
  return objects;
}

function serviceDns(gitea: GiteaConfig, target: GiteaTarget): string {
  return `${gitea.app.serviceName}.${target.namespace}.svc.cluster.local:${gitea.app.service.httpPort}`;
}

function serviceDnsFromObjects(app: Record<string, unknown>, target: Record<string, unknown>): string {
  const service = record(app.service);
  return `${stringValue(app.serviceName)}.${stringValue(target.namespace)}.svc.cluster.local:${stringValue(service.httpPort)}`;
}


function yamlQuote(value: string): string {
  return JSON.stringify(value);
}

function indentBlock(value: string, spaces: number): string {
  const prefix = " ".repeat(spaces);
  return value.split(/\r?\n/u).map((line) => `${prefix}${line}`).join("\n");
}

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

function arrayRecords(value: unknown): Record<string, unknown>[] {
  return Array.isArray(value) ? value.filter((item) => typeof item === "object" && item !== null && !Array.isArray(item)) as Record<string, unknown>[] : [];
}

function stringValue(value: unknown, fallback = "-"): string {
  if (typeof value === "string" && value.length > 0) return value;
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  return fallback;
}

function boolText(value: unknown): string {
  return value === true ? "true" : "false";
}

function compactLine(value: string): string {
  const trimmed = value.replace(/\s+/gu, " ").trim();
  return trimmed.length > 0 ? trimmed.slice(0, 220) : "-";
}

function table(headers: string[], rows: string[][]): string[] {
  const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] ?? "").length)));
  const format = (row: string[]) => row.map((cell, index) => cell.padEnd(widths[index])).join("  ");
  return [format(headers), format(headers.map((header, index) => "-".repeat(Math.max(header.length, widths[index])))), ...rows.map(format)];
}
