import assert from "node:assert/strict";
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test } from "bun:test";

import { prepareCaseRun } from "./src/hwlab-caserun-lib.ts";

const NOW = "2026-06-06T00:00:00.000Z";
const SUBJECT_COMMIT = "df7a4e6e551fa90d64bde5537cc000f89d63dd20";

test("CaseRun records source root baseline so pre-existing dirty files are not attributed to the run", async () => {
  const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-caserun-source-root-"));
  try {
    const caseRepo = path.join(root, "case-registry");
    const caseDir = path.join(caseRepo, "cases", "dirty-source-root");
    await mkdir(path.join(caseRepo, ".git"), { recursive: true });
    await mkdir(caseDir, { recursive: true });
    await writeFile(path.join(caseRepo, ".git", "HEAD"), "ref: refs/heads/main\n", "utf8");
    await writeFile(path.join(caseDir, "case.json"), JSON.stringify({
      contractVersion: "hwpod-case-v1",
      caseId: "dirty-source-root",
      hwpodSpec: "hwpod-spec.yaml",
      subject: {
        repoLocalPath: "F:\\Work\\HWLAB-CASE-F103",
        commitId: SUBJECT_COMMIT,
        subdir: "projects/01_baseline"
      },
      runtime: { apiUrl: "http://hwlab.test" },
      agentTask: { workspace: "subjectWorktree", prompt: "record source root baseline", constraints: [] }
    }, null, 2), "utf8");
    await writeFile(path.join(caseDir, "hwpod-spec.yaml"), [
      "apiVersion: hwlab.dev/v0alpha1",
      "kind: Hwpod",
      "metadata:",
      "  name: d601-f103-v2",
      "spec:",
      "  targetDevice:",
      "    board: D601-F103-V2",
      "    mcu: STM32F103",
      "  workspace:",
      "    path: \"F:\\\\Work\\\\HWLAB-CASE-F103\"",
      "    toolchain: keil-mdk",
      "    keilProject: projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx",
      "  debugProbe:",
      "    type: daplink",
      "    adapter: keil",
      "  ioProbe:",
      "    uart:",
      "      id: uart/1",
      "      port: COM9",
      "  nodeBinding:",
      "    nodeId: node-d601-f103-v2",
      ""
    ].join("\n"), "utf8");

    const dirtyStatus = " M projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx\n";
    const dirtyDiff = "diff --git a/projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx b/projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx\n+<PackID>Keil.STM32F1xx_DFP.2.4.1</PackID>\n";
    const fetchImpl = async (_url: string, init: RequestInit) => {
      const plan = JSON.parse(String(init.body));
      const results = plan.ops.map((op: any) => ({ opId: op.opId, op: op.op, ok: true, status: "completed", output: outputForGit(op.args.argv, dirtyStatus, dirtyDiff) }));
      return new Response(JSON.stringify({ ok: true, status: "completed", body: { results } }), { status: 200, headers: { "content-type": "application/json" } });
    };

    const result = await prepareCaseRun({
      parsed: { _: [], caseRepo, runId: "source-root-baseline" },
      env: {},
      fetchImpl: fetchImpl as typeof fetch,
      cwd: root,
      now: () => NOW,
      sleep: async () => {},
      rest: ["prepare", "dirty-source-root"]
    });

    assert.equal(result.status, "succeeded");
    assert.equal(result.summary.status, "prepared");
    assert.equal(result.run.subject.sourceRootBaseline.statusShort, dirtyStatus.trim());
    assert.equal(result.run.subject.sourceRootAfterPrepare.statusShort, dirtyStatus.trim());
    assert.equal(result.run.subject.sourceRootBaseline.diffSha256, result.run.subject.sourceRootAfterPrepare.diffSha256);
    assert.match(await readFile(result.specPath, "utf8"), /caserun-source-root-baseline/u);
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

function outputForGit(argv: string[], dirtyStatus: string, dirtyDiff: string) {
  const command = argv.join(" ");
  if (command.includes("cat-file -e")) return { exitCode: 0, stdout: "", stderr: "" };
  if (command.includes("worktree add")) return { exitCode: 0, stdout: "Preparing worktree\n", stderr: "" };
  if (command.includes("rev-parse HEAD")) return { exitCode: 0, stdout: `${SUBJECT_COMMIT}\n`, stderr: "" };
  if (command.endsWith("status --short")) return { exitCode: 0, stdout: dirtyStatus, stderr: "" };
  if (command.endsWith("diff --stat")) return { exitCode: 0, stdout: " projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx | 8 ++++----\n", stderr: "" };
  if (command.endsWith("diff --binary")) return { exitCode: 0, stdout: dirtyDiff, stderr: "" };
  return { exitCode: 0, stdout: "", stderr: "" };
}
