/**
 * Persisted search result group order.
 *
 * TRACES: UR-050 | DR-066 | UT-*
 */

import { describe, it, expect, beforeEach, beforeAll, afterAll, vi } from "vitest";
import { get } from "svelte/store";
import { DEFAULT_GROUP_ORDER } from "$lib/utils/searchScope";

const STORAGE_KEY = "jellytau-search-group-order";

// This jsdom setup doesn't expose localStorage, so stand in a minimal
// implementation — the store only uses getItem/setItem.
const store = new Map<string, string>();
const localStorage = {
  getItem: (key: string) => store.get(key) ?? null,
  setItem: (key: string, value: string) => void store.set(key, value),
  removeItem: (key: string) => void store.delete(key),
  clear: () => store.clear(),
};

beforeAll(() => {
  vi.stubGlobal("localStorage", localStorage);
});

afterAll(() => {
  vi.unstubAllGlobals();
});

describe("searchGroupOrder", () => {
  beforeEach(() => {
    vi.resetModules();
    localStorage.clear();
  });

  it("starts at the shipped default with nothing stored", async () => {
    const { searchGroupOrder } = await import("./searchGroupOrder");
    expect(get(searchGroupOrder)).toEqual([...DEFAULT_GROUP_ORDER]);
  });

  it("loads a stored order", async () => {
    localStorage.setItem(
      STORAGE_KEY,
      JSON.stringify(["tvShows", "movies", "songs", "albums", "artists"])
    );
    const { searchGroupOrder } = await import("./searchGroupOrder");
    expect(get(searchGroupOrder)).toEqual([
      "tvShows",
      "movies",
      "songs",
      "albums",
      "artists",
    ]);
  });

  it("appends groups a partial stored order does not mention", async () => {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(["movies"]));
    const { searchGroupOrder } = await import("./searchGroupOrder");
    expect(get(searchGroupOrder)).toEqual([
      "movies",
      "songs",
      "albums",
      "artists",
      "tvShows",
    ]);
  });

  it("falls back to the default on corrupt stored JSON", async () => {
    localStorage.setItem(STORAGE_KEY, "{not json");
    const { searchGroupOrder } = await import("./searchGroupOrder");
    expect(get(searchGroupOrder)).toEqual([...DEFAULT_GROUP_ORDER]);
  });

  it("persists a move so the order survives a restart", async () => {
    const { searchGroupOrder } = await import("./searchGroupOrder");
    searchGroupOrder.move("movies", -1);

    expect(get(searchGroupOrder)).toEqual([
      "songs",
      "albums",
      "movies",
      "artists",
      "tvShows",
    ]);
    expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual([
      "songs",
      "albums",
      "movies",
      "artists",
      "tvShows",
    ]);

    // Simulate a fresh app start reading the same storage.
    vi.resetModules();
    const reloaded = await import("./searchGroupOrder");
    expect(get(reloaded.searchGroupOrder)).toEqual([
      "songs",
      "albums",
      "movies",
      "artists",
      "tvShows",
    ]);
  });

  it("persists a drag reorder", async () => {
    const { searchGroupOrder } = await import("./searchGroupOrder");
    searchGroupOrder.reorder(4, 0);
    expect(get(searchGroupOrder)).toEqual([
      "tvShows",
      "songs",
      "albums",
      "artists",
      "movies",
    ]);
  });

  it("resets to the shipped default", async () => {
    const { searchGroupOrder } = await import("./searchGroupOrder");
    searchGroupOrder.move("tvShows", -1);
    searchGroupOrder.reset();
    expect(get(searchGroupOrder)).toEqual([...DEFAULT_GROUP_ORDER]);
  });

  it("normalizes an explicitly set order", async () => {
    const { searchGroupOrder } = await import("./searchGroupOrder");
    searchGroupOrder.set(["movies", "podcasts"] as never);
    expect(get(searchGroupOrder)).toEqual([
      "movies",
      "songs",
      "albums",
      "artists",
      "tvShows",
    ]);
  });
});
