import { describe, expect, test } from "bun:test";
import { adapt } from "./shape-timeline-cv";
import type { ViewRow } from "./types";

// t-paliad-177 Slice 4 — adapter contract tests for ViewRow →
// TimelineEvent + LaneInfo. Pure function, no DOM access.
// The actual chart-render math is pinned by shape-timeline-chart.test.ts;
// this file pins the adapter's lossy translation rules from §13.4.

const baseRow = (overrides: Partial<ViewRow> = {}): ViewRow => ({
  kind: "deadline",
  id: "d1",
  title: "Test",
  event_date: "2026-06-15",
  detail: {},
  ...overrides,
});

describe("adapt — kind mapping", () => {
  test("deadline → kind='deadline' + deadline_id", () => {
    const out = adapt([baseRow({ kind: "deadline", id: "abc" })]);
    expect(out.events).toHaveLength(1);
    expect(out.events[0].kind).toBe("deadline");
    expect(out.events[0].deadline_id).toBe("abc");
    expect(out.events[0].appointment_id).toBeUndefined();
    expect(out.events[0].project_event_id).toBeUndefined();
  });

  test("appointment → kind='appointment' + appointment_id", () => {
    const out = adapt([baseRow({ kind: "appointment", id: "x" })]);
    expect(out.events[0].kind).toBe("appointment");
    expect(out.events[0].appointment_id).toBe("x");
  });

  test("project_event → kind='milestone' + project_event_id", () => {
    const out = adapt([baseRow({ kind: "project_event", id: "y" })]);
    expect(out.events[0].kind).toBe("milestone");
    expect(out.events[0].project_event_id).toBe("y");
  });

  test("approval_request is skipped", () => {
    const out = adapt([
      baseRow({ kind: "deadline" }),
      baseRow({ kind: "approval_request" }),
      baseRow({ kind: "appointment" }),
    ]);
    expect(out.events).toHaveLength(2);
    expect(out.events.map((e) => e.kind)).toEqual(["deadline", "appointment"]);
  });
});

describe("adapt — lane bucketing by project_id (cross-project chart)", () => {
  test("one lane per unique project_id, first-seen order", () => {
    const out = adapt([
      baseRow({ project_id: "p1", project_title: "Project 1" }),
      baseRow({ project_id: "p2", project_title: "Project 2" }),
      baseRow({ project_id: "p1", project_title: "Project 1" }),
    ]);
    expect(out.lanes).toHaveLength(2);
    expect(out.lanes[0].id).toBe("p1");
    expect(out.lanes[0].label).toBe("Project 1");
    expect(out.lanes[1].id).toBe("p2");
  });

  test("project_title preferred over project_reference for the label", () => {
    const out = adapt([
      baseRow({ project_id: "p1", project_title: "Nice Name", project_reference: "REF-1" }),
    ]);
    expect(out.lanes[0].label).toBe("Nice Name");
  });

  test("falls back to project_reference when title missing", () => {
    const out = adapt([
      baseRow({ project_id: "p1", project_reference: "REF-1" }),
    ]);
    expect(out.lanes[0].label).toBe("REF-1");
  });

  test("missing project_id collapses to synthetic 'self' lane", () => {
    const out = adapt([baseRow({ project_id: undefined })]);
    expect(out.lanes).toHaveLength(1);
    expect(out.lanes[0].id).toBe("self");
    expect(out.events[0].lane_id).toBe("self");
    expect(out.events[0].track).toBe("parent");
  });

  test("event lane_id matches its lane row id", () => {
    const out = adapt([
      baseRow({ project_id: "p1", project_title: "A" }),
      baseRow({ project_id: "p2", project_title: "B" }),
    ]);
    expect(out.events[0].lane_id).toBe("p1");
    expect(out.events[1].lane_id).toBe("p2");
  });
});

describe("adapt — status extraction", () => {
  test("deadline status 'done' comes through from detail", () => {
    const out = adapt([
      baseRow({ kind: "deadline", detail: { status: "done" } }),
    ]);
    expect(out.events[0].status).toBe("done");
  });

  test("deadline status 'overdue' comes through", () => {
    const out = adapt([
      baseRow({ kind: "deadline", detail: { status: "overdue" } }),
    ]);
    expect(out.events[0].status).toBe("overdue");
  });

  test("unknown / missing detail.status defaults to 'open'", () => {
    const out = adapt([
      baseRow({ kind: "deadline", detail: { status: "weird-value" } }),
      baseRow({ kind: "appointment" }),
      baseRow({ kind: "project_event" }),
    ]);
    expect(out.events.map((e) => e.status)).toEqual(["open", "open", "open"]);
  });
});

describe("adapt — date passthrough", () => {
  test("event_date is forwarded to TimelineEvent.date", () => {
    const out = adapt([baseRow({ event_date: "2026-08-15T00:00:00Z" })]);
    expect(out.events[0].date).toBe("2026-08-15T00:00:00Z");
  });

  test("empty event_date becomes null (undated)", () => {
    const out = adapt([baseRow({ event_date: "" })]);
    expect(out.events[0].date).toBeNull();
  });
});

describe("adapt — empty input", () => {
  test("empty rows array returns empty events + empty lanes", () => {
    const out = adapt([]);
    expect(out.events).toHaveLength(0);
    expect(out.lanes).toHaveLength(0);
  });
});
