import { describe, expect, test } from "bun:test";
import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { spawnSync } from "node:child_process";
import { parseKafkaReplayOptions, renderKafkaReplay } from "./platform-infra-kafka";
import { renderMachine } from "./agentrun/render";

describe("platform-infra Kafka replay", () => {
  test("accepts the bounded no-publish application replay contract", () => {
    expect(parseKafkaReplayOptions([
      "agentrun", "--node", "NC01", "--lane", "nc01-v02",
      "--session-id", "ses_example", "--trace-id", "trc_example",
      "--no-publish", "-o", "yaml",
    ])).toMatchObject({
      targetId: "NC01",
      lane: "nc01-v02",
      sessionId: "ses_example",
      traceId: "trc_example",
      output: "yaml",
    });
  });

  test("rejects replay without the explicit no-publish boundary", () => {
    expect(() => parseKafkaReplayOptions(["agentrun", "--session-id", "ses_example"])).toThrow("requires --no-publish");
  });

  test("renders matched replay counts and mutation disclosure", () => {
    const rendered = renderKafkaReplay({
      ok: true,
      diagnosis: {
        networkPlane: "k3s-application-pod",
        application: "agentrun",
        namespace: "agentrun-v02",
        workload: "deployment/agentrun-mgr",
        topic: "codex-stdio.raw.v1",
        scanned: 30,
        accepted: 12,
        produced: 8,
        rejected: { classification: "matched" },
        mutation: false,
        topicAppended: false,
        valuesPrinted: false,
        firstMismatchIdentity: null,
      },
    });
    expect(rendered.renderedText).toContain("k3s-application-pod");
    expect(rendered.renderedText).toContain("30");
    expect(rendered.renderedText).toContain("matched");
    expect(rendered.renderedText).toContain("no              no");
  });

  test("keeps JSON and YAML machine projections isomorphic", () => {
    const payload = {
      ok: true,
      diagnosis: {
        networkPlane: "k3s-application-pod",
        scanned: 30,
        accepted: 12,
        produced: 8,
        rejected: { classification: "matched", byReason: {} },
        mutation: false,
        topicAppended: false,
        valuesPrinted: false,
      },
    };
    const json = JSON.parse(renderMachine("replay", payload, "json").renderedText);
    const yaml = Bun.YAML.parse(renderMachine("replay", payload, "yaml").renderedText);
    expect(yaml).toEqual(json);
  });

  test("classifies a nonzero application replay as a runtime error", () => {
    const directory = mkdtempSync(join(tmpdir(), "unidesk-kafka-replay-"));
    const kubectl = join(directory, "kubectl");
    writeFileSync(kubectl, `#!/bin/sh
case "$*" in
  *"get pod"*) printf 'kafka-0' ;;
  *"--time -2"*) printf 'codex-stdio.raw.v1:0:0\\n' ;;
  *"--time -1"*) printf 'codex-stdio.raw.v1:0:4\\n' ;;
  *"deployment/agentrun-mgr"*) printf '%s\\n' 'KafkaJS error: timeout must not be negative: -1784589809970' >&2; exit 1 ;;
  *) exit 2 ;;
esac
`);
    chmodSync(kubectl, 0o755);
    try {
      const result = spawnSync("python3", ["scripts/native/platform-infra/kafka-replay-diagnostics.py"], {
        cwd: process.cwd(),
        encoding: "utf8",
        env: {
          ...process.env,
          PATH: `${directory}:${process.env.PATH ?? ""}`,
          KAFKA_NAMESPACE: "platform-infra",
          KAFKA_CLUSTER: "platform-kafka",
          KAFKA_BOOTSTRAP: "platform-kafka-kafka-bootstrap:9092",
          KAFKA_INPUT_TOPIC: "codex-stdio.raw.v1",
          KAFKA_REPLAY_SESSION_ID: "ses_example",
          KAFKA_REPLAY_TRACE_ID: "trc_example",
          KAFKA_REPLAY_LIMIT: "5000",
          KAFKA_REPLAY_TIMEOUT_MS: "10000",
          KAFKA_REPLAY_COMMAND_GRACE_MS: "35000",
          AGENTRUN_NAMESPACE: "agentrun-v02",
          AGENTRUN_MANAGER_DEPLOYMENT: "agentrun-mgr",
        },
      });
      expect(result.status).toBe(0);
      const payload = JSON.parse(result.stdout);
      expect(payload.ok).toBe(false);
      expect(payload.scanned).toBe(0);
      expect(payload.rejected.classification).toBe("network-or-runtime-error");
      expect(payload.execution.exitCode).toBe(1);
      expect(payload.execution.stderrTail).toContain("timeout must not be negative");
    } finally {
      rmSync(directory, { recursive: true, force: true });
    }
  });
});
