// Home screen data store - featured items, continue watching, recently added
// TRACES: UR-023, UR-024, UR-034, UR-059, UR-067 | DR-026, DR-027, DR-038, DR-039, DR-089, DR-118, DR-197
import { writable, derived } from "svelte/store";
import type { MediaItem } from "$lib/api/types";
import { auth } from "./auth";
import {
  filterSupersededResumeItems,
  filterInProgressNextUpItems,
} from "./continueWatchingFilter";

interface HomeState {
  heroItems: MediaItem[];
  resumeItems: MediaItem[];
  nextUpItems: MediaItem[];
  latestItems: MediaItem[];
  recentlyPlayedAudio: MediaItem[];
  resumeMovies: MediaItem[];
  /** Favourites per scope. Empty rows are not rendered. TRACES: UR-067 | DR-118 */
  favoriteMovies: MediaItem[];
  favoriteShows: MediaItem[];
  favoriteMusic: MediaItem[];
  isLoading: boolean;
  error: string | null;
}

function createHomeStore() {
  const initialState: HomeState = {
    heroItems: [],
    resumeItems: [],
    nextUpItems: [],
    latestItems: [],
    recentlyPlayedAudio: [],
    resumeMovies: [],
    favoriteMovies: [],
    favoriteShows: [],
    favoriteMusic: [],
    isLoading: false,
    error: null,
  };

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

  async function loadHomeSections() {
    // Only show loading spinner when no data is available yet
    update(s => ({ ...s, isLoading: s.heroItems.length === 0 && s.latestItems.length === 0, error: null }));

    try {
      const repo = auth.getRepository();

      // Use allSettled so one failing section (e.g. Next Up is online-only and
      // rejects offline) doesn't wipe out the whole homepage. Each section falls
      // back to an empty list; cached sections (resume/latest/recent) still show.
      const settled = await Promise.allSettled([
        repo.getResumeItems(undefined, 12),
        repo.getNextUpEpisodes(undefined, 12),
        repo.getLatestItems("", 16),
        repo.getRecentlyPlayedAudio(12), // Backend now handles intelligent grouping
        repo.getResumeMovies(12),
        // Favourites, one request per row. The scope is opaque — Rust decides
        // which item types it covers. TRACES: UR-067 | DR-118
        repo.getFavorites("movies", { limit: 20 }),
        repo.getFavorites("tv", { limit: 20 }),
        repo.getFavorites("music", { limit: 20 }),
      ]);

      const valueOr = <T>(i: number, fallback: T): T =>
        settled[i].status === "fulfilled" ? (settled[i] as PromiseFulfilledResult<T>).value : fallback;

      const rawResume = valueOr(0, [] as typeof initialState.resumeItems);
      const rawNextUp = valueOr(1, [] as typeof initialState.nextUpItems);
      // Drop episodes the user has already moved past (their series' Next Up
      // points further ahead) so Continue Watching isn't cluttered with stale
      // partial positions left behind by skipping. The frontier is read from the
      // unfiltered Next Up list, before in-progress entries are removed from it.
      const resume = filterSupersededResumeItems(rawResume, rawNextUp);
      // ...and the other way round: an episode already under way is Continue
      // Watching's, so Next Episode only offers unstarted ones.
      const nextUp = filterInProgressNextUpItems(rawNextUp, rawResume);
      const latest = valueOr(2, [] as typeof initialState.latestItems);
      const recentAudio = valueOr(3, [] as typeof initialState.recentlyPlayedAudio);
      const resumeMovies = valueOr(4, [] as typeof initialState.resumeMovies);
      const emptyResult = { items: [] as MediaItem[], totalRecordCount: 0 };
      const favoriteMovies = valueOr(5, emptyResult).items;
      const favoriteShows = valueOr(6, emptyResult).items;
      const favoriteMusic = valueOr(7, emptyResult).items;

      // Use resume items or latest as hero items
      const hero = resume.length >= 3 ? resume.slice(0, 5) : latest.slice(0, 5);

      update(s => ({
        ...s,
        heroItems: hero,
        resumeItems: resume,
        nextUpItems: nextUp,
        latestItems: latest,
        recentlyPlayedAudio: recentAudio,
        resumeMovies: resumeMovies,
        favoriteMovies,
        favoriteShows,
        favoriteMusic,
        isLoading: false,
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to load home sections";
      update(s => ({ ...s, isLoading: false, error: message }));
      console.error("Failed to load home sections:", error);
    }
  }

  function reset() {
    set(initialState);
  }

  return {
    subscribe,
    loadHomeSections,
    reset,
  };
}

export const home = createHomeStore();

// Derived stores for convenience
export const heroItems = derived(home, $home => $home.heroItems);
export const resumeItems = derived(home, $home => $home.resumeItems);
export const nextUpItems = derived(home, $home => $home.nextUpItems);
export const latestItems = derived(home, $home => $home.latestItems);
export const recentlyPlayedAudio = derived(home, $home => $home.recentlyPlayedAudio);
export const resumeMovies = derived(home, $home => $home.resumeMovies);
export const favoriteMovies = derived(home, $home => $home.favoriteMovies);
export const favoriteShows = derived(home, $home => $home.favoriteShows);
export const favoriteMusic = derived(home, $home => $home.favoriteMusic);
export const isHomeLoading = derived(home, $home => $home.isLoading);
