import { describe, it, expect } from "vitest";
import type { MediaItem } from "$lib/api/types";
import { buildHeroMix, shuffle } from "./heroMix";

/** Minimal MediaItem for hero tests; `art: false` strips the image tags. */
function item(id: string, art = true): MediaItem {
  return {
    id,
    name: `Item ${id}`,
    type: "Movie",
    primaryImageTag: art ? `tag-${id}` : undefined,
  } as MediaItem;
}

const hasArt = (i: MediaItem) => !!i.primaryImageTag;

describe("shuffle", () => {
  it("returns a permutation without mutating the input", () => {
    const input = [1, 2, 3, 4, 5];
    const copy = [...input];
    const result = shuffle(input);
    expect(input).toEqual(copy);
    expect([...result].sort()).toEqual([...input].sort());
  });
});

describe("buildHeroMix", () => {
  it("returns empty for empty pools", () => {
    expect(buildHeroMix([[], []], hasArt)).toEqual([]);
  });

  it("caps the rotation at count", () => {
    const pool = Array.from({ length: 20 }, (_, i) => item(`a${i}`));
    expect(buildHeroMix([pool], hasArt, 6)).toHaveLength(6);
  });

  it("filters items without artwork", () => {
    const result = buildHeroMix([[item("a", false), item("b")]], hasArt);
    expect(result.map(i => i.id)).toEqual(["b"]);
  });

  it("de-duplicates across pools", () => {
    const a = item("a");
    const result = buildHeroMix([[a], [a, item("b")]], hasArt);
    const ids = result.map(i => i.id);
    expect(ids).toHaveLength(new Set(ids).size);
    expect(ids).toContain("a");
    expect(ids).toContain("b");
  });

  it("leads with an item from the first non-empty pool", () => {
    const personal = [item("p1"), item("p2"), item("p3")];
    const rest = [item("r1"), item("r2"), item("r3")];
    for (let run = 0; run < 20; run++) {
      const result = buildHeroMix([personal, rest], hasArt);
      expect(["p1", "p2", "p3"]).toContain(result[0].id);
    }
  });

  it("takes at most perPool items per pool before backfilling", () => {
    const a = [item("a1"), item("a2"), item("a3"), item("a4")];
    const b = [item("b1"), item("b2"), item("b3"), item("b4")];
    // count 4 with perPool 2: exactly 2 from each pool, no backfill needed.
    for (let run = 0; run < 20; run++) {
      const result = buildHeroMix([a, b], hasArt, 4, 2);
      const fromA = result.filter(i => i.id.startsWith("a")).length;
      const fromB = result.filter(i => i.id.startsWith("b")).length;
      expect(fromA).toBe(2);
      expect(fromB).toBe(2);
    }
  });

  it("backfills from leftovers when samples fall short of count", () => {
    const a = [item("a1"), item("a2"), item("a3"), item("a4"), item("a5"), item("a6")];
    const result = buildHeroMix([a], hasArt, 6, 2);
    expect(result).toHaveLength(6);
  });
});
