import { describe, expect, it } from "vitest";

import type {
  ForeshadowWindowView,
  OutlineChapterView,
} from "@/lib/api/types";
import {
  distinctVolumes,
  filterByViewVolume,
  groupByVolume,
  isCloseWindow,
  windowBadgeLabel,
} from "./outline";

const ch = (over: Partial<OutlineChapterView>): OutlineChapterView => ({
  no: 1,
  volume: 1,
  beats: [],
  foreshadow_windows: [],
  ...over,
});

const win = (
  over: Partial<ForeshadowWindowView>,
): ForeshadowWindowView => ({ code: "F-012", ...over });

describe("groupByVolume", () => {
  it("groups by volume and sorts volumes and chapters ascending", () => {
    const groups = groupByVolume([
      ch({ no: 127, volume: 3 }),
      ch({ no: 12, volume: 1 }),
      ch({ no: 126, volume: 3 }),
    ]);
    expect(groups.map((g) => g.volume)).toEqual([1, 3]);
    expect(groups[1]?.chapters.map((c) => c.no)).toEqual([126, 127]);
  });

  it("handles undefined", () => {
    expect(groupByVolume(undefined)).toEqual([]);
  });
});

describe("distinctVolumes", () => {
  it("returns sorted unique volume numbers", () => {
    expect(
      distinctVolumes([
        ch({ no: 1, volume: 2 }),
        ch({ no: 2, volume: 1 }),
        ch({ no: 3, volume: 2 }),
      ]),
    ).toEqual([1, 2]);
  });

  it("handles undefined", () => {
    expect(distinctVolumes(undefined)).toEqual([]);
  });
});

describe("filterByViewVolume", () => {
  const chapters = [
    ch({ no: 1, volume: 1 }),
    ch({ no: 2, volume: 1 }),
    ch({ no: 3, volume: 2 }),
  ];

  it("returns all chapters when view is 'all'", () => {
    expect(filterByViewVolume(chapters, "all").map((c) => c.no)).toEqual([
      1, 2, 3,
    ]);
  });

  it("keeps only the selected volume", () => {
    expect(filterByViewVolume(chapters, 2).map((c) => c.no)).toEqual([3]);
  });

  it("returns empty for a volume with no chapters", () => {
    expect(filterByViewVolume(chapters, 9)).toEqual([]);
  });

  it("handles undefined", () => {
    expect(filterByViewVolume(undefined, "all")).toEqual([]);
  });
});

describe("windowBadgeLabel", () => {
  it("renders a range, half-open, or bare badge without any glyph", () => {
    expect(
      windowBadgeLabel(win({ expected_close_from: 40, expected_close_to: 60 })),
    ).toBe("F-012 (40-60)");
    expect(windowBadgeLabel(win({ expected_close_to: 60 }))).toBe("F-012 (≤60)");
    expect(windowBadgeLabel(win({ expected_close_from: 40 }))).toBe(
      "F-012 (≥40)",
    );
    expect(windowBadgeLabel(win({}))).toBe("F-012");
  });

  it("never embeds the raw ⚑ glyph (icon comes from the render layer)", () => {
    expect(
      windowBadgeLabel(win({ expected_close_from: 40, expected_close_to: 60 })),
    ).not.toContain("⚑");
  });
});

describe("isCloseWindow", () => {
  it("is true when chapter no is inside the recovery window", () => {
    const w = win({ expected_close_from: 40, expected_close_to: 60 });
    expect(isCloseWindow(ch({ no: 50 }), w)).toBe(true);
    expect(isCloseWindow(ch({ no: 61 }), w)).toBe(false);
    expect(isCloseWindow(ch({ no: 50 }), win({}))).toBe(false);
  });
});
