import { describe, it, expect } from "vitest";
import type { Library } from "$lib/api/types";
import { buildLibraryMosaic, assumedLibraryRatio } from "./libraryMosaic";

function lib(
  id: string,
  name: string,
  collectionType: string,
  favoritesScope?: Library["favoritesScope"],
): Library {
  return { id, name, collectionType, favoritesScope } as Library;
}

const MOVIES = lib("1", "Movies", "movies", "movies");
const SHOWS = lib("2", "Shows", "tvshows", "tv");
const MUSIC = lib("3", "Music", "music", "music");
const LIVETV = lib("4", "Live TV", "livetv");

describe("buildLibraryMosaic", () => {
  it("leads with the cross-library favourites entry", () => {
    const entries = buildLibraryMosaic([MOVIES]);
    expect(entries[0]).toMatchObject({
      kind: "favorites",
      scope: "all",
      label: "Favourites",
      href: "/library/favorites",
    });
  });

  it("puts each library's own favourites tile right after it", () => {
    const entries = buildLibraryMosaic([MOVIES, MUSIC]);

    expect(entries.map((e) => e.label)).toEqual([
      "Favourites",
      "Movies",
      "Favourite Movies",
      "Music",
      "Favourite Music",
    ]);
  });

  it("links a category tile to that category's favourites tab", () => {
    const entries = buildLibraryMosaic([SHOWS]);
    const tile = entries.find((e) => e.label === "Favourite Shows");
    expect(tile).toMatchObject({ kind: "favorites", scope: "tv", href: "/library/favorites?scope=tv" });
  });

  it("offers a category's favourites once, however many libraries share it", () => {
    const entries = buildLibraryMosaic([MOVIES, lib("5", "Kids Films", "movies", "movies")]);

    expect(entries.filter((e) => e.kind === "favorites" && e.scope === "movies")).toHaveLength(1);
    expect(entries.map((e) => e.label)).toEqual([
      "Favourites",
      "Movies",
      "Favourite Movies",
      "Kids Films",
    ]);
  });

  it("gives no favourites tile to a library kind favourites do not carve up", () => {
    const entries = buildLibraryMosaic([LIVETV]);
    expect(entries.map((e) => e.label)).toEqual(["Favourites", "Live TV"]);
  });

  it("ignores a scope the favourites page does not offer as a tab", () => {
    const odd = lib("6", "Books", "books", "books" as Library["favoritesScope"]);
    const entries = buildLibraryMosaic([odd]);
    expect(entries.map((e) => e.label)).toEqual(["Favourites", "Books"]);
  });

  it("keeps every library, and keys tiles uniquely", () => {
    const entries = buildLibraryMosaic([MOVIES, SHOWS, MUSIC, LIVETV]);

    expect(entries.filter((e) => e.kind === "library")).toHaveLength(4);
    expect(new Set(entries.map((e) => e.key)).size).toBe(entries.length);
  });

  it("has nothing but the favourites entry when there are no libraries", () => {
    expect(buildLibraryMosaic([]).map((e) => e.key)).toEqual(["favorites:all"]);
  });

  it("gives a category tile the shape of the library it follows", () => {
    const entries = buildLibraryMosaic([MUSIC, MOVIES]);
    const musicFavorites = entries.find((e) => e.label === "Favourite Music")!;
    const movieFavorites = entries.find((e) => e.label === "Favourite Movies")!;

    expect(musicFavorites.ratio).toBe(assumedLibraryRatio(MUSIC));
    expect(movieFavorites.ratio).toBe(assumedLibraryRatio(MOVIES));
  });
});

describe("assumedLibraryRatio", () => {
  it("assumes a square cover for music and a wide backdrop otherwise", () => {
    expect(assumedLibraryRatio(MUSIC)).toBe(1);
    expect(assumedLibraryRatio(MOVIES)).toBeCloseTo(16 / 9);
    expect(assumedLibraryRatio(LIVETV)).toBeCloseTo(16 / 9);
  });
});
