import { describe, it } from "node:test";
import assert from "node:assert/strict";

import {
  formatPmToAdminReconcileSummary,
  isAutoGeneratedReciprocalReport,
  parseReportFile,
  selectCanonicalPmToAdminReports,
  taskStageSkipReason,
} from "../reportSubmitEligibility.ts";

describe("reportSubmitEligibility", () => {
  it("detects ReportGate auto-generated reciprocal reports", () => {
    const raw = [
      "---",
      "sender: DEV",
      "status: blocked",
      "---",
      "## Runtime 自动补写 / Auto-generated reciprocal report",
      "本报告由 CodeFlow runtime **ReportGate** 在 worker 会话结束时自动写入，",
    ].join("\n");
    assert.equal(isAutoGeneratedReciprocalReport(raw), true);
  });

  it("selectCanonicalPmToAdminReports prefers manual over auto final_summary", () => {
    const autoBody = [
      "---",
      "sender: PM",
      "recipient: ADMIN",
      "status: done",
      "task_id: TASK-20260610-220",
      "report_type: final_summary",
      "auto_final_summary: true",
      "---",
      "无自动 blocked 噪声（Runtime 总线自动汇总）",
    ].join("\n");
    const manualBody = [
      "---",
      "sender: PM",
      "recipient: ADMIN",
      "status: done",
      "task_id: TASK-20260610-220",
      "---",
      "## 执行结果\nPM 手写最终报告",
    ].join("\n");
    const { canonical, duplicatePaths } = selectCanonicalPmToAdminReports([
      parseReportFile(
        "/tmp/REPORT-20260610-004-PM-to-ADMIN.md",
        "REPORT-20260610-004-PM-to-ADMIN.md",
        autoBody,
      ),
      parseReportFile(
        "/tmp/REPORT-20260610-111-PM-to-ADMIN.md",
        "REPORT-20260610-111-PM-to-ADMIN.md",
        manualBody,
      ),
    ]);
    assert.equal(canonical.length, 1);
    assert.equal(canonical[0]!.filename, "REPORT-20260610-111-PM-to-ADMIN.md");
    assert.ok(duplicatePaths.has("/tmp/REPORT-20260610-004-PM-to-ADMIN.md"));
  });

  it("selectCanonicalPmToAdminReports keeps latest done per task", () => {
    const mk = (name: string, taskId: string, status: string) =>
      parseReportFile(
        `/tmp/${name}`,
        name,
        `---\nsender: PM\nrecipient: ADMIN\nstatus: ${status}\ntask_id: ${taskId}\n---\n# ok\n`,
      );
    const { canonical, duplicatePaths } = selectCanonicalPmToAdminReports([
      mk("REPORT-20260604-010-PM-to-ADMIN.md", "TASK-20260604-024", "done"),
      mk("REPORT-20260604-020-PM-to-ADMIN.md", "TASK-20260604-024", "done"),
      mk("REPORT-20260604-005-PM-to-ADMIN.md", "TASK-20260604-005", "blocked"),
    ]);
    assert.equal(canonical.length, 1);
    assert.equal(canonical[0]!.filename, "REPORT-20260604-020-PM-to-ADMIN.md");
    assert.ok(duplicatePaths.has("/tmp/REPORT-20260604-010-PM-to-ADMIN.md"));
  });

  it("superseded or invalid reports are not completion evidence", () => {
    const superseded = parseReportFile(
      "/tmp/REPORT-20260712-001-QA-to-PM.md",
      "REPORT-20260712-001-QA-to-PM.md",
      "---\nsender: QA\nstatus: done\ntask_id: TASK-20260712-003\nsuperseded_by: REPORT-NEW\n---\n",
    );
    const invalid = parseReportFile(
      "/tmp/REPORT-20260712-002-QA-to-PM.md",
      "REPORT-20260712-002-QA-to-PM.md",
      "---\nsender: QA\nstatus: done\ntask_id: TASK-20260712-003\nvalid: false\n---\n",
    );
    const { canonical } = selectCanonicalPmToAdminReports([superseded, invalid]);
    assert.deepEqual(canonical, []);
  });

  it("taskStageSkipReason maps archive/done/review to skipped_archived", () => {
    assert.equal(taskStageSkipReason("archive"), "skipped_archived");
    assert.equal(taskStageSkipReason("done"), "skipped_archived");
    assert.equal(taskStageSkipReason("review"), "skipped_archived");
    assert.equal(taskStageSkipReason("active"), null);
  });

  it("formatPmToAdminReconcileSummary matches required shape", () => {
    const line = formatPmToAdminReconcileSummary({
      scanned: 47,
      eligible: 2,
      reconciled: 2,
      skipped_archived: 40,
      skipped_not_active: 0,
      skipped_not_done: 5,
      skipped_auto: 0,
      skipped_duplicate: 0,
      skipped_sender: 0,
      skipped_no_task: 0,
      skipped_rework: 0,
      skipped_late_intake: 0,
      admin_attention: 0,
      skipped_other: 0,
    });
    assert.match(
      line,
      /PM→ADMIN reconcile summary: scanned=47 eligible=2 reconciled=2 skipped_archived=40 skipped_not_done=5 skipped_auto=0 skipped_duplicate=0/,
    );
  });
});
