import { describe, expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { resolve } from "node:path";

import { renderPikaoaDesiredPipeline } from "./pikaoa-delivery-renderer";

function pacDocument(): Record<string, unknown> {
  return Bun.YAML.parse(readFileSync(resolve(import.meta.dir, "../../config/platform-infra/pipelines-as-code.yaml"), "utf8")) as Record<string, unknown>;
}

function rendererBinding(id = "pikaoa-dev-nc01"): Parameters<typeof renderPikaoaDesiredPipeline>[0] {
  const document = pacDocument();
  const repositories = document.repositories as Array<Record<string, unknown>>;
  const consumers = document.consumers as Array<Record<string, unknown>>;
  const consumer = consumers.find((item) => item.id === id);
  const repository = repositories.find((item) => item.id === consumer?.repositoryRef);
  if (repository === undefined || consumer === undefined) throw new Error(`PikaOA PaC fixture is required: ${id}`);
  return {
    consumer,
    repository: {
      ...repository,
      params: {
        ...(repository.params as Record<string, unknown>),
        ...((consumer.params as Record<string, unknown> | undefined) ?? {}),
      },
    },
  } as Parameters<typeof renderPikaoaDesiredPipeline>[0];
}

function sourceFixture(): string {
  const root = mkdtempSync(resolve(tmpdir(), "pikaoa-development-renderer-"));
  mkdirSync(resolve(root, "deploy"), { recursive: true });
  for (const file of ["api.Dockerfile", "worker.Dockerfile", "web.Dockerfile"]) writeFileSync(resolve(root, "deploy", file), "FROM scratch\n");
  return root;
}

describe("PikaOA development PaC renderer", () => {
  test("shares one PaC repository while isolating master and release consumers", () => {
    const document = pacDocument();
    const repositories = document.repositories as Array<Record<string, unknown>>;
    const consumers = document.consumers as Array<Record<string, unknown>>;
    const repository = repositories.find((item) => item.id === "pikaoa-dev-nc01");
    const developmentConsumer = consumers.find((item) => item.id === "pikaoa-dev-nc01");
    const productionConsumer = consumers.find((item) => item.id === "pikaoa-nc01");
    const duplicateProductionRepository = repositories.find((item) => item.id === "pikaoa-nc01");
    expect((repository?.params as Record<string, unknown>).source_branch).toBe("master");
    expect((developmentConsumer?.sourceArtifact as Record<string, unknown>).pipelineRunPath).toBe(".tekton/pikaoa-dev-nc01-pac.yaml");
    expect((developmentConsumer?.sourceArtifact as Record<string, unknown>).renderer).toBe("pikaoa-development-runtime");
    expect((productionConsumer?.params as Record<string, unknown>).source_branch).toBe("release");
    expect((productionConsumer?.params as Record<string, unknown>).source_snapshot_prefix).toBe("refs/unidesk/snapshots/gitea-actions/pikaoa-release-nc01");
    expect(productionConsumer?.repositoryRef).toBe("pikaoa-dev-nc01");
    expect(duplicateProductionRepository).toBeUndefined();
    expect((productionConsumer?.sourceArtifact as Record<string, unknown>).renderer).toBe("pikaoa-release-runtime");
    expect((productionConsumer?.sourceArtifact as Record<string, unknown>).configRef).toBe("config/pikaoa.yaml#releaseRuntime.targets.NC01");
  });

  test("renders release runtime from its isolated owning selector", () => {
    const source = sourceFixture();
    try {
      const rendered = renderPikaoaDesiredPipeline(rendererBinding("pikaoa-nc01"), source);
      expect(rendered.configRef).toBe("config/pikaoa.yaml#releaseRuntime.targets.NC01");
      const serialized = JSON.stringify(rendered.pipeline);
      expect(serialized).toContain("pikaoa-nc01-pac");
      expect(serialized).toContain("refs/unidesk/snapshots/gitea-actions/pikaoa-release-nc01");
      expect(serialized).toContain("pac-gitea-pikaoa-nc01");
      for (const component of ["api", "worker", "web"]) {
        expect(serialized).toContain(`--import-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:release'`);
        expect(serialized).toContain(`--export-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:release,mode=max,ignore-error=true'`);
      }
      expect(serialized).not.toContain(":development'");
      expect(serialized).not.toContain("pikaoa-dev-nc01-pac");
    } finally {
      rmSync(source, { recursive: true, force: true });
    }
  });

  test("renders parallel digest builds and a PreSync fresh database initializer", () => {
    const source = sourceFixture();
    try {
      const rendered = renderPikaoaDesiredPipeline(rendererBinding(), source);
      const spec = rendered.pipeline.spec as Record<string, unknown>;
      const tasks = spec.tasks as Array<Record<string, unknown>>;
      for (const task of tasks) {
        const taskSpec = task.taskSpec as Record<string, unknown>;
        expect(taskSpec.workspaces).toEqual([{ name: "workspace", mountPath: "/workspace" }]);
        const steps = taskSpec.steps as Array<Record<string, unknown>>;
        for (const step of steps) {
          const mounts = (step.volumeMounts ?? []) as Array<Record<string, unknown>>;
          expect(mounts.some((mount) => mount.name === "workspace")).toBe(false);
        }
      }
      for (const name of ["build-api", "build-worker", "build-web"]) {
        const task = tasks.find((item) => item.name === name);
        const component = name.replace("build-", "");
        expect(task?.runAfter).toEqual(["source"]);
        expect(JSON.stringify(task)).toContain("buildctl-daemonless.sh build");
        expect(JSON.stringify(task)).toContain("$(params.revision)");
        expect(JSON.stringify(task)).not.toContain("source-token");
        const buildScript = (((task?.taskSpec as Record<string, unknown>).steps as Array<Record<string, unknown>>)[0]?.script) as string;
        expect(buildScript).toContain('"containerimage.digest"[[:space:]]*:[[:space:]]*"\\(sha256:[0-9a-f]\\{64\\}\\)"');
        expect(buildScript).toContain(".*/\\1/p");
        expect(buildScript).not.toContain("\u0001");
        expect(buildScript).toContain("Docker-Content-Digest:");
        expect(buildScript).toContain("build_status=$?");
        expect(buildScript).toContain(`--import-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:development'`);
        expect(buildScript).toContain(`--export-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:development,mode=max,ignore-error=true'`);
        expect(buildScript).not.toContain(`cache-${component}:$revision`);
        expect(buildScript).toContain('if [ -f "$metadata" ]');
        expect(buildScript).toContain("grep -Eq '^sha256:[0-9a-f]{64}$'");
        expect(buildScript).toContain('"code":"buildctl-nonzero-artifact-verified"');
        expect(buildScript).toContain('"artifactVerified":true');
        expect(buildScript).toContain('"blocking":false');
        expect(buildScript.indexOf('"code":"buildctl-nonzero-artifact-verified"')).toBeGreaterThan(buildScript.indexOf("build digest missing from metadata and registry manifest"));
      }
      const digest = "sha256:" + "a".repeat(64);
      const metadata = JSON.stringify({ "containerimage.digest": digest }, null, 2);
      const parsedDigest = /"containerimage\.digest"\s*:\s*"(sha256:[0-9a-f]{64})"/u.exec(metadata)?.[1];
      expect(parsedDigest).toBe(digest);
      const sourceTask = tasks.find((item) => item.name === "source");
      expect(JSON.stringify(sourceTask)).toContain("source-token");
      expect(JSON.stringify(sourceTask)).toContain("GIT_ASKPASS");
      expect(JSON.stringify(sourceTask)).toContain("$(params.gitops-secret-name)");
      for (const task of tasks) {
        const taskSpec = task.taskSpec as Record<string, unknown> | undefined;
        if (taskSpec === undefined) continue;
        expect(taskSpec.workspaces).toEqual([{ name: "workspace", mountPath: "/workspace" }]);
        const steps = taskSpec.steps as Array<Record<string, unknown>>;
        for (const step of steps) {
          expect((step.volumeMounts as Array<Record<string, unknown>> | undefined)?.some((mount) => mount.name === "workspace") ?? false).toBe(false);
        }
      }
      const publish = tasks.find((item) => item.name === "gitops-publish");
      expect(publish?.runAfter).toEqual(["build-api", "build-worker", "build-web"]);
      const script = ((((publish?.taskSpec as Record<string, unknown>).steps as Array<Record<string, unknown>>)[0]?.script) as string);
      for (const evidence of [
        '"status":"published"',
        '"registryVerified":true',
        '"publishedCount":3',
        '"requiredServiceCount":3',
        '"gitopsCommit"',
        '"service":"api"',
        '"service":"worker"',
        '"service":"web"',
      ]) expect(script).toContain(evidence);
      const encoded = /printf '%s' '([A-Za-z0-9+/=]+)' \| base64 -d/u.exec(script)?.[1];
      if (encoded === undefined) throw new Error("embedded GitOps manifest is required");
      const manifest = Buffer.from(encoded, "base64").toString("utf8");
      expect(manifest).toContain("argocd.argoproj.io/hook: PreSync");
      expect(manifest).toContain("name: pikaoa-init");
      expect(manifest).toContain("name: initializer");
      expect(manifest).not.toContain("kind: Secret");
      expect(manifest).toContain("kind: ConfigMap");
      expect(manifest).toContain("name: pikaoa-runtime-config");
      const runtimeConfig = manifest.split(/^---$/mu).find((document) => document.includes("kind: ConfigMap") && document.includes("name: pikaoa-runtime-config"));
      expect(runtimeConfig).toContain("argocd.argoproj.io/hook: PreSync");
      expect(runtimeConfig).toContain("argocd.argoproj.io/hook-delete-policy: BeforeHookCreation");
      expect(runtimeConfig).toContain('argocd.argoproj.io/sync-wave: "-2"');
      expect(runtimeConfig).not.toContain("HookSucceeded");
      expect(runtimeConfig).toContain("address: temporal-frontend.temporal.svc.cluster.local:7233");
      expect(runtimeConfig).toContain("namespace: unidesk");
      expect(runtimeConfig).toContain("taskQueue: pikaoa-dev-outbox");
      expect(runtimeConfig).toContain("workflowId: pikaoa-dev-outbox-drain");
      expect(runtimeConfig).toContain("activityTimeout: 1m");
      expect(runtimeConfig).toContain("retryMaximumAttempts: 8");
      expect(runtimeConfig).toContain("continueAsNewEvery: 1000");
      expect(runtimeConfig).toContain('apiCommand: \\"pikaoa-api\\"');
      expect(runtimeConfig).toContain('workerCommand: \\"pikaoa-worker\\"');
      expect(runtimeConfig).not.toContain("interval: 2s");
      expect(runtimeConfig).not.toContain("workerInterval");
      const initializer = manifest.split(/^---$/mu).find((document) => document.includes("kind: Job") && document.includes("name: pikaoa-init"));
      expect(initializer).toContain("argocd.argoproj.io/hook: PreSync");
      expect(initializer).toContain('argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation,HookSucceeded"');
      expect(initializer).toContain('argocd.argoproj.io/sync-wave: "-1"');
      expect(manifest).toContain("configMap:");
      expect(manifest).toContain("secretKeyRef:");
      expect(manifest.match(/name: pikaoa-dev-runtime/gu)).toHaveLength(11);
      expect(manifest).not.toContain("secretName:");
      expect(manifest.match(/name: DATABASE_URL/gu)).toHaveLength(3);
      expect(manifest.match(/key: DATABASE_URL/gu)).toHaveLength(3);
      expect(manifest.match(/name: PIKAOA_SESSION_SECRET/gu)).toHaveLength(2);
      expect(manifest.match(/key: PIKAOA_SESSION_SECRET/gu)).toHaveLength(2);
      expect(manifest.match(/name: OA_ADMIN_TOKEN/gu)).toHaveLength(2);
      expect(manifest.match(/key: OA_ADMIN_TOKEN/gu)).toHaveLength(2);
      expect(manifest.match(/name: PIKAOA_BOOTSTRAP_ADMIN_PASSWORD/gu)).toHaveLength(2);
      expect(manifest.match(/key: PIKAOA_BOOTSTRAP_ADMIN_PASSWORD/gu)).toHaveLength(2);
      expect(manifest.match(/name: PIKAOA_BOOTSTRAP_EMPLOYEE_PASSWORD/gu)).toHaveLength(2);
      expect(manifest.match(/key: PIKAOA_BOOTSTRAP_EMPLOYEE_PASSWORD/gu)).toHaveLength(2);
      expect(manifest.match(/fsGroup: 65532/gu)).toHaveLength(2);
      expect(manifest.match(/mountPath: \/var\/lib\/pikaoa\/attachments/gu)).toHaveLength(2);
      expect(manifest.match(/claimName: pikaoa-attachments/gu)).toHaveLength(2);
      expect(manifest).toContain("name: PIKAOA_MAX_UPLOAD_BYTES");
      expect(manifest).toContain('value: "104857600"');
      expect(script).toContain("grep -Eq '@sha256:[0-9a-f]{64}$'");
      expect(manifest).toContain("image: __PIKAOA_API_IMAGE__");
      expect(manifest).toContain("pikaoa.unidesk.io/source-commit: __PIKAOA_SOURCE_COMMIT__");
      expect(script).toContain('s|__PIKAOA_SOURCE_COMMIT__|$SOURCE_COMMIT|g');
      expect(script).toContain("GitOps manifest contains unresolved provenance or image placeholders");
      expect(script).not.toContain("grep -Eq '$(params.revision)");
      expect(script).toContain("grep -Eq '__PIKAOA_SOURCE_COMMIT__|__PIKAOA_(API|WORKER|WEB)_IMAGE__'");
      expect(script).toContain("git ls-remote --exit-code --heads");
      expect(script).toContain("git -C /workspace/gitops checkout --orphan");
    } finally {
      rmSync(source, { recursive: true, force: true });
    }
  });
});
