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

import { eventDedupeRegistry } from "../../_internal/EventDedupeRegistry.ts";
import { ReportWatcher } from "../ReportWatcher.ts";
import { ReportWatcherSeenStore } from "../ReportWatcherSeenStore.ts";

const delay = (ms: number): Promise<void> =>
  new Promise((resolve) => setTimeout(resolve, ms));

async function waitFor(predicate: () => boolean, timeoutMs = 3_000): Promise<void> {
  const deadline = Date.now() + timeoutMs;
  while (!predicate() && Date.now() < deadline) await delay(25);
  assert.equal(predicate(), true, "timed out waiting for watcher event");
}

test("ReportWatcher treats immediate frontmatter enrichment as one add event", async () => {
  const root = await mkdtemp(join(tmpdir(), "codeflowmu-report-watcher-"));
  const dir = join(root, "fcop", "reports");
  await mkdir(dir, { recursive: true });
  const filename = "REPORT-20260713-101-QA-to-PM.md";
  const path = join(dir, filename);
  let reports = 0;
  let violations = 0;
  const watcher = new ReportWatcher({
    dir,
    onReport: () => {
      reports += 1;
    },
    onIntegrityViolation: () => {
      violations += 1;
    },
  });

  try {
    await watcher.start();
    await writeFile(path, "---\nstatus: done\n", "utf-8");
    await delay(100);
    await appendFile(path, "---\n\n# QA report\n", "utf-8");

    await waitFor(() => reports === 1);
    assert.equal(violations, 0);

    await appendFile(path, "\nlate mutation\n", "utf-8");
    await waitFor(() => violations === 1);
  } finally {
    await watcher.stop();
    await rm(root, { recursive: true, force: true });
  }
});

test("ReportWatcher restart does not hand the same persisted report to PM twice", async () => {
  const root = await mkdtemp(join(tmpdir(), "codeflowmu-report-restart-"));
  const reportsDir = join(root, "fcop", "reports");
  const filename = "REPORT-20260802-901-PM-to-ADMIN.md";
  await writeFile(join(root, ".keep"), "", "utf8");
  await mkdir(reportsDir, { recursive: true });
  await writeFile(
    join(reportsDir, filename),
    "---\nstatus: done\n---\n\n# PM report\n",
    "utf8",
  );
  let handoffs = 0;
  const first = new ReportWatcher({
    dir: reportsDir,
    seenStore: new ReportWatcherSeenStore(root),
    onReport: () => { handoffs += 1; },
  });
  const second = new ReportWatcher({
    dir: reportsDir,
    seenStore: new ReportWatcherSeenStore(root),
    onReport: () => { handoffs += 1; },
  });
  try {
    await first.start();
    assert.equal(handoffs, 1);
    await first.stop();
    eventDedupeRegistry.clear();
    await second.start();
    await delay(100);
    assert.equal(handoffs, 1);
  } finally {
    await first.stop();
    await second.stop();
    eventDedupeRegistry.clear();
    await rm(root, { recursive: true, force: true });
  }
});
