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";
import { approvedJourneyEnvironment, requiredEnvironment } from "./exact-journey.js";
import { authoritativeRemoteHead } from "./repository-identity.js";

const databaseUrl = requiredEnvironment(process.env, "AWP_TEST_POSTGRES_URL");
const repository = requiredEnvironment(process.env, "AWP_REPOSITORY_CHECKOUT_PATH");
const kubeconfig = requiredEnvironment(process.env, "AWP_KUBECONFIG");
const namespace = process.env.AWP_WORKSPACE_NAMESPACE ?? "awp-workspaces";
const { factoryRunId, firstTaskId } = approvedJourneyEnvironment();

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

function kubectl(args: string[]): string {
  return execFileSync("kubectl", ["--kubeconfig", kubeconfig, ...args], {
    encoding: "utf8",
  }).trim();
}

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

const remote = git(["remote", "get-url", "origin"]);
const remoteHead = authoritativeRemoteHead(
  execFileSync("git", ["ls-remote", "--symref", remote, "HEAD"], { encoding: "utf8" }),
);
const defaultRef = remoteHead.branchRef;
const tipBefore = remoteHead.oid;

const sql = postgres(databaseUrl, { max: 1 });
const runs = await sql<{ id: string }[]>`
  select ar.id
  from factory_runs fr
  join agent_runs ar
    on ar.factory_run_id = fr.id
   and ar.task_id = fr.task_id
  where fr.id = ${factoryRunId}
    and fr.task_id = ${firstTaskId}
  order by ar.created_at, ar.id
`;
await sql.end({ timeout: 5 });
assert.equal(runs.length, 1, "AC-18 requires the exact first-Task AgentRun");
const agentRunId = runs[0]!.id;

const deadline = Date.now() + 120_000;
let pod = "";
while (Date.now() < deadline) {
  const pods = JSON.parse(
    kubectl(["-n", namespace, "get", "pods", "-l", `awp.agent-run-id=${agentRunId}`, "-o", "json"]),
  ) 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 exact first-Task AgentRun must reach a Running pod");

const probe = spawnSync(
  "kubectl",
  [
    "--kubeconfig",
    kubeconfig,
    "-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 canonical 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: exact FactoryRun ${factoryRunId} AgentRun ${agentRunId} pod ${pod} could not push and ${defaultRef} remained at ${tipBefore}\n`,
);
