import assert from "node:assert/strict";
import { execFileSync, spawnSync } from "node:child_process";
import { setTimeout as delay } from "node:timers/promises";
import postgres from "postgres";

const databaseUrl = process.env.AWP_TEST_POSTGRES_URL;
const repository = process.env.AWP_PROJECT_REPOSITORY;
const namespace = process.env.AWP_WORKSPACE_NAMESPACE ?? "awp-golive";
if (!databaseUrl) throw new Error("AWP_TEST_POSTGRES_URL is required");
if (!repository) throw new Error("AWP_PROJECT_REPOSITORY is required");

function git(args: string[]): string {
  return execFileSync("git", args, { cwd: repository, encoding: "utf8" }).trim();
}

function shellQuote(value: string): string {
  return "'" + value.replaceAll("'", "'\"'\"'") + "'";
}

const remote = git(["remote", "get-url", "origin"]);
const remoteHead = execFileSync("git", ["ls-remote", "--symref", remote, "HEAD"], {
  encoding: "utf8",
});
const branchMatch = /^ref:\s+(refs\/heads\/[^\s]+)\s+HEAD$/m.exec(remoteHead);
const tipMatch = /^([0-9a-f]{40,64})\s+HEAD$/m.exec(remoteHead);
assert.ok(branchMatch?.[1], "project remote must advertise a default branch");
assert.ok(tipMatch?.[1], "project remote must advertise its default-branch tip");
const defaultRef = branchMatch[1];
const tipBefore = tipMatch[1];

const sql = postgres(databaseUrl, { max: 1 });
const [run] = await sql<{ id: string }[]>`
  select id from agent_runs where status = 'active' order by created_at desc limit 1
`;
await sql.end({ timeout: 5 });
assert.ok(run?.id, "a running AgentRun is required for AC-18");

const deadline = Date.now() + 120_000;
let pod = "";
while (Date.now() < deadline) {
  const pods = JSON.parse(
    execFileSync(
      "kubectl",
      ["-n", namespace, "get", "pods", "-l", `awp.agent-run-id=${run.id}`, "-o", "json"],
      { encoding: "utf8" },
    ),
  ) as {
    items: Array<{
      metadata?: { name?: string };
      status?: { phase?: string };
    }>;
  };
  const running = pods.items.find((candidate) => candidate.status?.phase === "Running");
  if (running?.metadata?.name) {
    pod = running.metadata.name;
    break;
  }
  await delay(500);
}
assert.ok(pod, "the running AgentRun must reach a Running pod");

const probe = spawnSync(
  "kubectl",
  [
    "-n",
    namespace,
    "exec",
    pod,
    "--",
    "sh",
    "-lc",
    [
      "git --version >/dev/null",
      "rm -rf /tmp/ac18-repository",
      "mkdir /tmp/ac18-repository",
      "git -C /tmp/ac18-repository init -q",
      "git -C /tmp/ac18-repository config user.name 'AWP untrusted agent'",
      "git -C /tmp/ac18-repository config user.email 'agent@untrusted.invalid'",
      "printf 'unauthorized publication probe\\n' > /tmp/ac18-repository/probe.txt",
      "git -C /tmp/ac18-repository add probe.txt",
      "git -C /tmp/ac18-repository commit -qm 'AC-18 unauthorized push probe'",
      `git -C /tmp/ac18-repository remote add origin ${shellQuote(remote)}`,
      `git -C /tmp/ac18-repository push origin HEAD:${shellQuote(defaultRef)}`,
    ].join(" && "),
  ],
  { encoding: "utf8" },
);
assert.notEqual(probe.status, 0, "git push from the agent pod must fail");

const after = execFileSync("git", ["ls-remote", remote, defaultRef], { encoding: "utf8" })
  .toString()
  .trim()
  .split(/\s+/)[0];
assert.equal(after, tipBefore, "failed agent push must not change the remote default-branch tip");

process.stdout.write(
  `AC-18 PASS: git push from pod ${pod} failed and ${defaultRef} remained at ${tipBefore}\n`,
);
