import { expect, test } from "bun:test";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { readGiteaWebhookGitOpsDelivery, renderGiteaWebhookSyncDesiredManifest } from "./platform-infra-gitea";
import { renderPlatformInfraGiteaApplication } from "../native/cicd/publish-platform-infra-gitea-gitops.mjs";

const root = resolve(import.meta.dir, "../..");

test("existing NC01 Repository can bootstrap the independent desired publisher without new RBAC", () => {
  const pipeline = Bun.YAML.parse(readFileSync(resolve(root, ".tekton/platform-infra-gitea-nc01-pac.yaml"), "utf8")) as any;
  expect(pipeline.metadata.annotations).toMatchObject({
    "pipelinesascode.tekton.dev/on-event": "[push]",
    "pipelinesascode.tekton.dev/on-target-branch": "[master]",
  });
  expect(pipeline.metadata.annotations["pipelinesascode.tekton.dev/on-cel-expression"]).toContain("node == 'NC01'");
  expect(pipeline.spec.taskRunTemplate.serviceAccountName).toBe("default");
  const script = pipeline.spec.pipelineSpec.tasks[0].taskSpec.steps[0].script as string;
  expect(script).toContain("$SOURCE_SNAPSHOT_PREFIX/$SOURCE_COMMIT");
  expect(script).toContain("publish-platform-infra-gitea-gitops.mjs");
  expect(script).not.toContain("build-unidesk-host-image");
  expect(script).not.toContain("todo-note");

  const pac = Bun.YAML.parse(readFileSync(resolve(root, "config/platform-infra/pipelines-as-code.yaml"), "utf8")) as any;
  const consumer = pac.consumers.find((item: any) => item.id === "platform-infra-gitea-nc01");
  expect(consumer).toMatchObject({
    repositoryRef: "sentinel-nc01-v03",
    node: "NC01",
    namespace: "devops-infra",
    pipeline: "platform-infra-gitea-nc01-pac",
    closeoutGitOpsMirrorFlush: false,
  });
  expect(consumer.argoBootstrap).toBeUndefined();
});

test("owning YAML renders one child Application and the complete durable bridge desired state", () => {
  const delivery = readGiteaWebhookGitOpsDelivery();
  expect(delivery.enabled).toBe(true);
  expect(delivery.bootstrapApplicationPath).toStartWith("deploy/gitops/unidesk-host/");
  expect(delivery.desiredManifestPath).toStartWith("deploy/gitops/platform-infra/gitea-nc01/");
  const application = renderPlatformInfraGiteaApplication(delivery);
  expect(application).toContain("kind: Application");
  expect(application).toContain("name: platform-infra-gitea-nc01");
  expect(application).toContain("path: deploy/gitops/platform-infra/gitea-nc01");
  expect(application).toContain("prune: true");
  expect(application).toContain("selfHeal: true");

  const manifest = renderGiteaWebhookSyncDesiredManifest("NC01");
  expect(manifest).toContain("kind: ServiceAccount");
  expect(manifest).toContain("kind: PersistentVolumeClaim");
  expect(manifest).toContain("strategy:\n    type: Recreate");
  expect(manifest).toContain("serviceAccountName: gitea-github-sync");
  expect(manifest).toContain("name: UNIDESK_GITEA_WEBHOOK_RESPONSE_BUDGET_MS\n              value: \"6500\"");
  expect(manifest).toContain("name: UNIDESK_GITEA_WEBHOOK_WORKER_ATTEMPT_TIMEOUT_MS\n              value: \"120000\"");
  const candidateConfig = manifest.indexOf("name: gitea-github-sync-candidate\n  namespace: devops-infra\n  annotations:");
  const candidateJob = manifest.indexOf("kind: Job\nmetadata:\n  name: gitea-github-sync-candidate");
  const deployment = manifest.indexOf("kind: Deployment\nmetadata:\n  name: gitea-github-sync");
  expect(candidateConfig).toBeGreaterThanOrEqual(0);
  expect(candidateJob).toBeGreaterThan(candidateConfig);
  expect(deployment).toBeGreaterThan(candidateJob);
  expect(manifest).toContain("argocd.argoproj.io/hook: PreSync");
  expect(manifest).toContain('argocd.argoproj.io/sync-wave: "-2"');
  expect(manifest).toContain('argocd.argoproj.io/sync-wave: "-1"');
  expect(manifest).toContain("node /etc/gitea-github-sync-candidate/entrypoint.mjs &");
  expect(manifest).toContain('import { startServer } from "./server.mjs";');
  expect(manifest).toContain("- /etc/gitea-github-sync/entrypoint.mjs");
  expect(manifest).toContain("mountPath: /etc/gitea-github-sync-candidate");
  expect(manifest).toContain("name: candidate-inbox\n          emptyDir: {}");
  expect(manifest).toContain('gate: "gitea-github-sync-candidate-startup"');
  const documents = manifest.split(/^---\s*$/mu).map((item) => item.trim()).filter(Boolean).map((item) => Bun.YAML.parse(item) as any);
  const resource = (kind: string, name: string) =>
    documents.find((item) => item.kind === kind && item.metadata?.name === name);
  expect(resource("Service", "gitea-http")).toBeDefined();
  expect(resource("PersistentVolumeClaim", "gitea-github-sync-inbox")).toBeDefined();
  const giteaStatefulSet = resource("StatefulSet", "gitea");
  expect(giteaStatefulSet).toBeDefined();
  expect(giteaStatefulSet.spec.volumeClaimTemplates.map((item: any) => item.metadata.name)).toEqual([
    "data",
    "config",
  ]);
  expect(giteaStatefulSet.spec.template.spec.containers[0].env).toContainEqual({
    name: "GITEA__server__ROOT_URL",
    value: "https://gitea.hwpod.com/",
  });
  expect(resource("Deployment", "gitea-github-sync")).toBeDefined();
  expect(resource("ServiceAccount", "gitea-legacy-public-exposure-cleanup")).toBeDefined();
  expect(resource("Role", "gitea-legacy-public-exposure-cleanup")).toBeDefined();
  expect(resource("RoleBinding", "gitea-legacy-public-exposure-cleanup")).toBeDefined();
  const cleanupJob = resource("Job", "gitea-legacy-public-exposure-cleanup");
  expect(cleanupJob).toBeDefined();
  expect(cleanupJob.metadata.annotations["argocd.argoproj.io/hook"]).toBe("PreSync");
  expect(cleanupJob.spec.template.spec.containers[0].args).toContain("deployment/gitea-frpc");
  expect(cleanupJob.spec.template.spec.containers[0].args).toContain("secret/gitea-frpc-secrets");
  const pacReadOnlyNamespaces = documents
    .filter((item) => item.kind === "Role" && item.metadata?.name === "unidesk-pac-consumer-runner")
    .map((item) => item.metadata.namespace)
    .sort();
  expect(pacReadOnlyNamespaces).toEqual(["agentrun-ci", "devops-infra", "pikaoa-ci", "selfmedia-ci"]);
  const candidate = documents.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "gitea-github-sync-candidate");
  const activeConfig = documents.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "gitea-github-sync-config");
  const bridge = documents.find((item) => item.kind === "Deployment" && item.metadata?.name === "gitea-github-sync");
  expect(candidate.data["hook-topology.json"]).toBeUndefined();
  expect(candidate.data["platform_infra_gitea_hook_reconciler.py"]).toBeUndefined();
  expect(activeConfig.data["hook-topology.json"]).toContain('"ownerTargetId": "NC01"');
  expect(activeConfig.data["hook-topology.json"]).toContain('"targetId": "NC01"');
  expect(activeConfig.data["hook-topology.json"]).toContain('"lookbackSeconds": 259200');
  expect(activeConfig.data["hook-topology.json"]).toContain('"desiredHooks"');
  expect(activeConfig.data["platform_infra_gitea_hook_reconciler.py"]).toContain("github-hook-topology-reconciled");
  expect(bridge.spec.template.spec.containers.map((item: any) => item.name)).toEqual([
    "github-to-gitea-sync",
    "github-hook-topology-reconciler",
  ]);
  const candidateContainer = documents.find((item) => item.kind === "Job" && item.metadata?.name === "gitea-github-sync-candidate").spec.template.spec.containers[0];
  expect(candidateContainer.env.map((item: any) => item.name)).not.toContain("UNIDESK_GITEA_HOOK_RECOVERY_STATE_PATH");
  const stableBridge = bridge.spec.template.spec.containers[0];
  expect(stableBridge.env.filter((item: any) => item.name === "UNIDESK_GITEA_HOOK_RECOVERY_STATE_PATH")).toHaveLength(1);
  const reconciler = bridge.spec.template.spec.containers[1];
  expect(reconciler.volumeMounts).toContainEqual({ name: "durable-inbox", mountPath: "/var/lib/gitea-github-sync" });
  const sourcePath = resolve(root, "scripts/src/platform_infra_gitea_hook_reconciler.py");
  const syntax = spawnSync("python3", ["-c", "import pathlib,sys; compile(pathlib.Path(sys.argv[1]).read_text(), sys.argv[1], 'exec')", sourcePath], { encoding: "utf8" });
  expect(syntax.status).toBe(0);
  expect(syntax.stderr).toBe("");
  const recoveryTests = spawnSync("python3", [resolve(root, "scripts/src/platform_infra_gitea_hook_reconciler.test.py")], { encoding: "utf8" });
  expect(recoveryTests.status).toBe(0);
  expect(recoveryTests.stderr).toContain("OK");
});
