import { execFileSync } from "node:child_process";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";

function reviewRecord(savedAt: string, reason: string, ocr: Array<{ id: string; text: string }>, locked?: boolean) {
  return {
    savedAt,
    sample: {
      reason,
      capture: {
        width: 1920,
        height: 1080,
        ocr,
        locked,
      },
      parsed: {
        name: "Pristine Plume of the Blessed",
        slot: ocr.some((entry) => entry.id === "artifact-slot") ? "Plume of Death" : "Unknown Slot",
        level: 20,
        mainStat: "ATK",
        mainValue: "311",
        setName: "Silken Moon's Serenade",
        equipped: ocr.some((entry) => entry.id === "artifact-footer") ? "Aino" : "Not detected",
        substats: ["Energy Recharge+10.4%"],
        confidence: 0.9,
        notes: [],
      },
    },
  };
}

const completeOcr = [
  { id: "artifact-name", text: "Pristine Plume of the Blessed" },
  { id: "artifact-slot", text: "Plume of Death" },
  { id: "artifact-main-stat-label", text: "ATK" },
  { id: "artifact-level", text: "+20" },
  { id: "artifact-substats", text: "- Energy Recharge+10.4%" },
  { id: "artifact-footer", text: "Equipped: Aino" },
];

describe("review eval candidate exporter", () => {
  it("exports deduplicated candidates with stats and stale markers", () => {
    const dir = mkdtempSync(path.join(tmpdir(), "gaa-review-candidates-"));
    try {
      const inputPath = path.join(dir, "review-samples.jsonl");
      const outDir = path.join(dir, "out");
      const staleOcr = completeOcr.filter((entry) => entry.id !== "artifact-slot");
      writeFileSync(
        inputPath,
        [
          JSON.stringify(reviewRecord("2026-07-08T15:00:00.000Z", "automatic:missing-crops-or-ocr:p1:r0c0", completeOcr)),
          JSON.stringify(reviewRecord("2026-07-08T15:00:00.000Z", "automatic:missing-crops-or-ocr:p1:r0c0", completeOcr)),
          JSON.stringify(reviewRecord("2026-07-08T15:01:00.000Z", "automatic:capture-rejected:p1:r0c1", staleOcr, true)),
          "{not json",
        ].join("\n"),
        "utf8",
      );

      execFileSync("node", ["scripts/export-review-eval-candidates.cjs", `--input=${inputPath}`, `--out=${outDir}`, "--limit=10"], {
        cwd: process.cwd(),
        stdio: "pipe",
      });

      const payload = JSON.parse(readFileSync(path.join(outDir, "review-eval-candidates.json"), "utf8"));
      const markdown = readFileSync(path.join(outDir, "review-eval-candidates.md"), "utf8");

      expect(payload.summary.recordsRead).toBe(4);
      expect(payload.summary.invalidRecords).toBe(1);
      expect(payload.summary.uniqueCandidates).toBe(2);
      expect(payload.summary.exportedCandidates).toBe(2);
      expect(payload.summary.exportStats.completeFastFields).toBe(1);
      expect(payload.summary.exportStats.likelyStaleCaptures).toBe(1);
      expect(payload.summary.exportStats.equippedFooterCandidates).toBe(2);
      expect(payload.summary.exportStats.lockedTrueCandidates).toBe(1);
      expect(payload.candidates[0].missingFastFields).toEqual([]);
      expect(payload.candidates[0].parsed.equipped).toBe("Aino");
      expect(payload.candidates[0].reviewPrompt.expectedFields.equipped).toBe("Aino");
      expect(payload.candidates[1].likelyStaleCapture).toBe(true);
      expect(payload.candidates[1].locked).toBe(true);
      expect(markdown).toContain("## Export stats");
      expect(markdown).toContain("- artifact-slot: 1");
      expect(markdown).toContain("equipped=Aino");
      expect(markdown).toContain("Locked=true candidates: 1");
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });
});
