// Movies library landing page data store.
// Powers the focused movies landing: hero + horizontal sliders.
// TRACES: UR-007, UR-023, UR-034 | DR-007, DR-038, DR-039
import { writable, derived } from "svelte/store";
import type { MediaItem } from "$lib/api/types";
import { auth } from "./auth";
import { buildHeroMix } from "$lib/utils/heroMix";

/** A single "by genre" row: the genre name plus the movies in it. */
export interface GenreRow {
  id: string;
  name: string;
  items: MediaItem[];
}

interface MoviesState {
  // Movies the user can resume (continue watching).
  continueWatching: MediaItem[];
  // Recently added movies in the library.
  recentlyAdded: MediaItem[];
  // One slider per genre (top genres by movie count).
  genreRows: GenreRow[];
  // Mix used for the hero banner.
  heroItems: MediaItem[];
  isLoading: boolean;
  error: string | null;
}

const SECTION_LIMIT = 16;
// How many genre sliders to show, and how many genres to probe to find them.
const MAX_GENRE_ROWS = 8;
const MAX_GENRES_PROBED = 20;

function createMoviesStore() {
  const initialState: MoviesState = {
    continueWatching: [],
    recentlyAdded: [],
    genreRows: [],
    heroItems: [],
    isLoading: false,
    error: null,
  };

  const { subscribe, set, update } = writable<MoviesState>(initialState);

  /** Artwork check for hero candidates: needs a backdrop or a primary image. */
  const hasArt = (i: MediaItem) =>
    !!(i.backdropImageTags && i.backdropImageTags.length > 0) || !!i.primaryImageTag;

  async function loadSections(libraryId: string) {
    update(s => ({
      ...s,
      isLoading: s.continueWatching.length === 0 && s.recentlyAdded.length === 0,
      error: null,
    }));

    try {
      const repo = auth.getRepository();

      const [resume, latest, surprise] = await Promise.all([
        repo.getResumeMovies(SECTION_LIMIT),
        repo.getLatestItems(libraryId, SECTION_LIMIT),
        // Random pool so the hero rotation changes between visits (SortBy=Random
        // shuffles server-side online, and via SQLite RANDOM() offline).
        repo
          .getItems(libraryId, {
            includeItemTypes: ["Movie"],
            sortBy: "Random",
            recursive: true,
            limit: SECTION_LIMIT,
          })
          .then(r => r.items)
          .catch(() => [] as MediaItem[]),
      ]);

      // Mix the hero: in-progress movies first (most personal), then recent
      // additions, then random picks from across the library.
      const heroItems = buildHeroMix([resume, latest, surprise], hasArt);

      update(s => ({
        ...s,
        continueWatching: resume,
        recentlyAdded: latest,
        heroItems,
        isLoading: false,
      }));

      // Genre rows are secondary — load them after the main sections paint so
      // the page isn't blocked on N per-genre queries.
      loadGenreRows(libraryId);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to load movie sections";
      update(s => ({ ...s, isLoading: false, error: message }));
      console.error("Failed to load movie sections:", error);
    }
  }

  /**
   * Build one slider per genre, showing the top-rated movies in each. We probe
   * a bounded set of genres in parallel, drop empty ones, then keep the genres
   * with the most movies (so niche/near-empty genres don't crowd the page).
   */
  async function loadGenreRows(libraryId: string) {
    try {
      const repo = auth.getRepository();
      const genres = await repo.getGenres(libraryId);
      if (genres.length === 0) return;

      const probed = genres.slice(0, MAX_GENRES_PROBED);
      const rows = await Promise.all(
        probed.map(async (genre): Promise<GenreRow> => {
          try {
            const result = await repo.getItems(libraryId, {
              includeItemTypes: ["Movie"],
              genres: [genre.name],
              sortBy: "CommunityRating",
              sortOrder: "Descending",
              recursive: true,
              limit: SECTION_LIMIT,
            });
            return { id: genre.id, name: genre.name, items: result.items };
          } catch (e) {
            console.warn(`Failed to load genre row "${genre.name}":`, e);
            return { id: genre.id, name: genre.name, items: [] };
          }
        })
      );

      const genreRows = rows
        .filter(row => row.items.length > 0)
        .sort((a, b) => b.items.length - a.items.length)
        .slice(0, MAX_GENRE_ROWS);

      update(s => ({ ...s, genreRows }));
    } catch (e) {
      console.warn("Failed to load movie genre rows:", e);
    }
  }

  function reset() {
    set(initialState);
  }

  return {
    subscribe,
    loadSections,
    reset,
  };
}

export const movies = createMoviesStore();

export const moviesHeroItems = derived(movies, $m => $m.heroItems);
export const isMoviesLoading = derived(movies, $m => $m.isLoading);
