import { expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
import { resolve } from "node:path";

const evaluator = createRequire(import.meta.url)("../native/cicd/pac-status-evaluator.cjs") as {
  evaluatePacNodeStatusSnapshot: (input: Record<string, unknown>) => Record<string, any>;
};

const sourceCommit = "a".repeat(40);
const gitopsRevision = "b".repeat(40);
const digest = `sha256:${"c".repeat(64)}`;

function consumer(id: string, expectedSourceCommit?: string): Record<string, unknown> {
  return {
    id,
    node: "NC01",
    lane: "v03",
    namespace: "fixture-ci",
    pipeline: "fixture-pipeline",
    pipelineRunPrefix: `${id}-`,
    argoNamespace: "argocd",
    argoApplication: `${id}-app`,
    repo: "acme/fixture",
    repository: "fixture-repository",
    params: {},
    deliveryProvenance: null,
    ...(expectedSourceCommit === undefined ? {} : { expectedSourceCommit }),
  };
}

function snapshot(readErrors: unknown[] = []): Record<string, unknown> {
  return {
    consumers: [consumer("fixture")],
    pipelineRuns: {
      items: [{
        metadata: {
          namespace: "fixture-ci",
          name: "fixture-run",
          creationTimestamp: "2026-07-17T00:00:00Z",
          labels: {
            "app.kubernetes.io/managed-by": "pipelinesascode.tekton.dev",
            "pipelinesascode.tekton.dev/event-type": "push",
            "pipelinesascode.tekton.dev/repository": "fixture-repository",
            "pipelinesascode.tekton.dev/sha": sourceCommit,
          },
          annotations: { "pipelinesascode.tekton.dev/git-provider": "gitea" },
        },
        spec: { pipelineRef: { name: "fixture-pipeline" } },
        status: {
          startTime: "2026-07-17T00:00:01Z",
          completionTime: "2026-07-17T00:00:11Z",
          conditions: [{ type: "Succeeded", status: "True", reason: "Succeeded" }],
        },
      }],
    },
    applications: {
      items: [{
        metadata: { namespace: "argocd", name: "fixture-app" },
        spec: { source: { repoURL: "https://example.invalid/gitops.git", targetRevision: "main" } },
        status: {
          sync: { status: "Synced", revision: gitopsRevision },
          health: { status: "Healthy" },
          resources: [{ kind: "Deployment", namespace: "fixture-runtime", name: "fixture-api" }],
        },
      }],
    },
    deployments: {
      items: [{
        metadata: { namespace: "fixture-runtime", name: "fixture-api" },
        spec: { replicas: 1, template: { spec: { containers: [{ image: `registry.invalid/fixture@${digest}` }] } } },
        status: { readyReplicas: 1 },
      }],
    },
    readErrors,
  };
}

test("node snapshot projects multiple consumer layers from one target-side capture", () => {
  const result = evaluator.evaluatePacNodeStatusSnapshot(snapshot());
  expect(result).toMatchObject({ ok: true, mutation: false, readErrors: [] });
  expect(result.consumers).toHaveLength(1);
  expect(result.consumers[0]).toMatchObject({
    consumer: "fixture",
    ready: true,
    ciReady: true,
    argoReady: true,
    runtimeReady: true,
    pipelineStatus: "Succeeded",
    sourceCommit,
    gitopsCommit: gitopsRevision,
    digest,
    reason: "ready",
  });
});

test("node snapshot preserves typed read failure instead of deriving pipeline-missing", () => {
  const result = evaluator.evaluatePacNodeStatusSnapshot(snapshot([
    { stage: "pipeline-runs", code: "pac-node-pipeline-runs-read-failed", exitCode: 124, valuesPrinted: false },
  ]));
  expect(result.ok).toBe(false);
  expect(result.consumers[0]).toMatchObject({
    ready: false,
    ciReady: false,
    reason: "pipeline-read-failed",
    firstBreak: { code: "pipeline-read-failed" },
  });
  expect(JSON.stringify(result)).not.toContain("pipeline-missing");
});

test("native node snapshot uses one remote process with three bounded list operations", () => {
  const shell = readFileSync(resolve(import.meta.dir, "../native/cicd/pac-node-status-snapshot.sh"), "utf8");
  expect(shell.match(/^capture_pipeline_runs /gmu)).toHaveLength(1);
  expect(shell.match(/^capture_list /gmu)).toHaveLength(2);
  expect(shell).toContain("pipelinerun.tekton.dev");
  expect(shell).toContain("UNIDESK_PAC_PIPELINERUN_SELECTOR");
  expect(shell).toContain("UNIDESK_PAC_PIPELINERUN_NAMESPACES");
  expect(shell).toContain("application.argoproj.io");
  expect(shell).toContain("deployment.apps");
  expect(shell).not.toContain("kubectl apply");
  expect(shell.match(/pac-node-snapshot-progress/gmu)).toHaveLength(6);
});

test("node snapshot selects an exact source and expands only its runtime namespace", () => {
  const input = snapshot();
  input.consumers = [consumer("fixture", sourceCommit)];
  const applications = input.applications as Record<string, any>;
  applications.items[0].status.health.status = "Degraded";
  applications.items[0].status.resources = [{
    group: "apps",
    kind: "Deployment",
    namespace: "fixture-runtime",
    name: "fixture-api",
    status: "OutOfSync",
    health: { status: "Degraded" },
  }];
  applications.items[0].status.conditions = [{
    type: "ComparisonError",
    message: `token=sensitive-fixture ${"x".repeat(600)}`,
  }];
  const deployments = input.deployments as Record<string, any>;
  deployments.items[0].spec.template.metadata = {
    labels: { "unidesk.ai/source-commit": sourceCommit },
  };
  deployments.items.push({
    metadata: { namespace: "other-runtime", name: "ignored" },
    spec: { replicas: 1, template: { metadata: { labels: { "unidesk.ai/source-commit": sourceCommit } }, spec: { containers: [] } } },
    status: { readyReplicas: 1 },
  });

  const result = evaluator.evaluatePacNodeStatusSnapshot(input);
  expect(result.consumers[0]).toMatchObject({
    sourceCommit,
    latestPipelineRunSummary: { name: "fixture-run", sourceCommit },
    pipelineRuns: [{ name: "fixture-run", sourceCommit }],
    argo: {
      firstDegradedResource: { kind: "Deployment", name: "fixture-api" },
      firstCondition: { type: "ComparisonError" },
    },
    runtime: {
      workloads: [{ namespace: "fixture-runtime", deployment: "fixture-api", sourceCommit }],
    },
  });
  expect(result.consumers[0].argo.firstCondition.message).toContain("token=[REDACTED]");
  expect(result.consumers[0].argo.firstCondition.message.length).toBeLessThanOrEqual(480);
});
