import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { readReaperSource } from "./reaper";

const FIXTURE_PATH = join(import.meta.dir, "../../../test/fixtures/activity/reaper.jsonl");

describe("readReaperSource", () => {
  test("maps known actions, unknown actions, and root/session mapping", () => {
    const fixture = readFileSync(FIXTURE_PATH, "utf8");
    const { coverage, events } = readReaperSource({
      path: FIXTURE_PATH,
      readFileImpl: () => fixture,
    });

    expect(coverage).toEqual({
      id: "reaper",
      label: "agent reaper",
      category: "guard",
      path: FIXTURE_PATH,
      status: "ok",
      records: 5,
      totalRecords: 5,
      skipped: 1,
      earliest: new Date(1754000000.5 * 1000).toISOString(),
      latest: new Date(1754000400 * 1000).toISOString(),
    });

    expect(events).toHaveLength(5);
    const autoUnblock = events.at(0);
    const sidecarReap = events.at(1);
    const runtimeReap = events.at(2);
    const reapSigterm = events.at(3);
    const unknown = events.at(4);

    expect(autoUnblock).toMatchObject({
      id: "reaper:1",
      severity: "notice",
      title: expect.stringContaining("stuck"),
    });
    expect(sidecarReap).toMatchObject({
      id: "reaper:2",
      severity: "notice",
      title: expect.not.stringContaining("sidecar_reap"),
    });
    expect(runtimeReap).toMatchObject({
      id: "reaper:3",
      severity: "notice",
      title: expect.not.stringContaining("runtime_reap"),
    });
    expect(reapSigterm).toMatchObject({
      id: "reaper:4",
      severity: "warn",
      title: "enforcement kill ladder — SIGTERM",
    });
    expect(unknown).toMatchObject({
      id: "reaper:6",
      severity: "info",
      title: "unknown_reaper_event",
      dedupeKey: "unknown_reaper_event",
    });

    const floatEvent = events.at(0);
    expect(floatEvent?.ts).toBe(new Date(1754000000.5 * 1000).toISOString());

    expect(autoUnblock).toMatchObject({ session: "runA" });
    expect(runtimeReap).not.toHaveProperty("session");
    expect(unknown).toMatchObject({ session: "runZ" });
  });

  test("reports absent for missing file and keeps malformed lines accounted", () => {
    const fixture = readFileSync(FIXTURE_PATH, "utf8");
    const result = readReaperSource({
      path: FIXTURE_PATH,
      readFileImpl: () => {
        throw new Error("boom");
      },
    });

    expect(result.events).toEqual([]);
    expect(result.coverage).toEqual({
      id: "reaper",
      label: "agent reaper",
      category: "guard",
      path: FIXTURE_PATH,
      status: "error",
      records: 0,
      totalRecords: 0,
      skipped: 0,
      error: "boom",
    });

    const absent = readReaperSource({
      path: "/tmp/no-such-reaper.log",
      existsSyncImpl: () => false,
    });
    expect(absent.coverage).toEqual({
      id: "reaper",
      label: "agent reaper",
      category: "guard",
      path: "/tmp/no-such-reaper.log",
      status: "absent",
      records: 0,
      totalRecords: 0,
      skipped: 0,
    });
  });
});
