import { describe, expect, test } from "bun:test";
import { readActivitySourceEntries } from "./entries";

const ACTIONS_LOG = [
  '{"ts":"2026-08-01T10:00:00.000Z","verb":"reap","result":"ok","rc":0}',
  "not json at all",
  '["array","record"]',
  '{"ts":"2026-08-01T10:05:00.000Z"}',
  '{"ts":"not-a-date","verb":"steer"}',
  '{"ts":"2026-08-01T10:10:00.000Z","verb":"steer","result":"failed","rc":3}',
  '{"ts":"2026-08-01T10:15:00.000Z","verb":"snooze","result":"ok","token":"hunter2"}',
].join("\n");

function readActions(overrides: Record<string, unknown> = {}) {
  return readActivitySourceEntries({
    sourceId: "actions",
    sources: {
      actions: {
        path: "/fixture/actions.jsonl",
        existsSyncImpl: () => true,
        readFileImpl: () => ACTIONS_LOG,
      },
    },
    ...overrides,
  });
}

describe("readActivitySourceEntries", () => {
  test("returns undefined for a source id this collector does not know", () => {
    expect(readActivitySourceEntries({ sourceId: "nope" })).toBeUndefined();
  });

  test("serves one source's entries newest-first with its coverage", () => {
    const response = readActions();
    expect(response).toBeDefined();
    expect(response!.source.id).toBe("actions");
    expect(response!.source.path).toBe("/fixture/actions.jsonl");
    expect(response!.total).toBe(3);
    expect(response!.events.map((event) => event.title)).toEqual([
      "snooze — ok",
      "steer — failed",
      "reap — ok",
    ]);
  });

  test("explains every skipped record instead of dropping it", () => {
    const response = readActions();
    expect(response!.skippedTotal).toBe(4);
    expect(response!.skipped).toHaveLength(4);
    expect(response!.skippedTruncated).toBe(false);
    expect(response!.skipped.map((entry) => entry.reason)).toEqual([
      "unparseable-json",
      "not-an-object",
      "missing-fields",
      "invalid-timestamp",
    ]);
    expect(response!.skipped.map((entry) => entry.line)).toEqual([2, 3, 4, 5]);
    expect(response!.skipped.every((entry) => entry.path === "/fixture/actions.jsonl")).toBe(true);
    expect(response!.skipped[0]!.excerpt).toBe("not json at all");
    expect(response!.skipped[2]!.explanation).toContain("verb is absent or blank");
  });

  test("pages with offset and limit while total counts every match", () => {
    const page = readActions({ offset: 1, limit: 1 });
    expect(page!.total).toBe(3);
    expect(page!.offset).toBe(1);
    expect(page!.limit).toBe(1);
    expect(page!.events.map((event) => event.title)).toEqual(["steer — failed"]);
  });

  test("clamps a limit above the maximum and a negative offset", () => {
    const page = readActions({ offset: -5, limit: 10_000 });
    expect(page!.limit).toBe(500);
    expect(page!.offset).toBe(0);
  });

  test("selects an exact record regardless of paging", () => {
    const response = readActions({ recordId: "actions:1", offset: 2, limit: 1 });
    expect(response!.total).toBe(1);
    expect(response!.offset).toBe(0);
    expect(response!.events.map((event) => event.id)).toEqual(["actions:1"]);
  });

  test("searches record detail, not only the title", () => {
    const byDetail = readActions({ q: "hunter2" });
    expect(byDetail!.total).toBe(0);

    const byDetailOnlyField = readActions({ q: "redacted" });
    expect(byDetailOnlyField!.events.map((event) => event.title)).toEqual(["snooze — ok"]);

    const byTitle = readActions({ q: "steer" });
    expect(byTitle!.events.map((event) => event.title)).toEqual(["steer — failed"]);
  });

  test("filters by severity floor and by window", () => {
    const errorsOnly = readActions({ severityFloor: "error" });
    expect(errorsOnly!.events.map((event) => event.title)).toEqual(["steer — failed"]);

    const windowed = readActions({ from: "2026-08-01T10:12:00.000Z" });
    expect(windowed!.events.map((event) => event.title)).toEqual(["snooze — ok"]);
  });

  test("redacts credential-named values in a skipped record's excerpt", () => {
    const response = readActivitySourceEntries({
      sourceId: "actions",
      sources: {
        actions: {
          path: "/fixture/actions.jsonl",
          existsSyncImpl: () => true,
          readFileImpl: () => '{"verb":"reap","token":"hunter2"',
        },
      },
    });
    expect(response!.skipped).toHaveLength(1);
    expect(response!.skipped[0]!.excerpt).toContain("[REDACTED]");
    expect(response!.skipped[0]!.excerpt).not.toContain("hunter2");
  });

  test("reports an absent source honestly rather than as an empty ok source", () => {
    const response = readActivitySourceEntries({
      sourceId: "actions",
      sources: { actions: { path: "/fixture/missing.jsonl", existsSyncImpl: () => false } },
    });
    expect(response!.source.status).toBe("absent");
    expect(response!.total).toBe(0);
    expect(response!.skippedTotal).toBe(0);
  });
});
