// Favourites overlay — in-session heart state shared across every surface.
//
// The durable record lives in Rust (local `user_data` + the Jellyfin server).
// This store holds only what the *current session* has changed, so a heart
// tapped on a card is reflected on the detail page and the item vanishes from
// the Favourites grid without anyone refetching. It is view state, not truth.
//
// TRACES: UR-068 | DR-119 | UT-105

import { derived, get, writable } from "svelte/store";
import type { MediaItem } from "$lib/api/types";

/** Item id → favourite state set during this session. */
const overrides = writable<Map<string, boolean>>(new Map());

export const favoriteOverrides = { subscribe: overrides.subscribe };

/**
 * Record a favourite state locally so every mounted view agrees immediately.
 * Called by the toggle service after the optimistic local write.
 */
export function setFavorite(itemId: string, isFavorite: boolean): void {
  overrides.update((map) => {
    const next = new Map(map);
    next.set(itemId, isFavorite);
    return next;
  });
}

/**
 * Forget a session override, so the item's own `userData` is authoritative
 * again. Used when the backend reports the server's state changed underneath
 * us (`favorites-changed`) — the fresh fetch that follows carries the truth.
 */
export function clearFavorite(itemId: string): void {
  overrides.update((map) => {
    if (!map.has(itemId)) return map;
    const next = new Map(map);
    next.delete(itemId);
    return next;
  });
}

export function clearAllFavorites(): void {
  overrides.set(new Map());
}

/**
 * Resolution order: a session override wins, then the item's own server-sent
 * `userData`, then "not favourited".
 *
 * The override has to win, or tapping the heart on a card would flip back the
 * moment the (unchanged) item object re-rendered.
 *
 * TRACES: UR-068 | DR-119 | UT-105
 */
export function resolveIsFavorite(
  item: Pick<MediaItem, "id" | "userData"> | null | undefined,
  overrideMap: Map<string, boolean>
): boolean {
  if (!item) return false;
  const override = overrideMap.get(item.id);
  if (override !== undefined) return override;
  return item.userData?.isFavorite ?? false;
}

/** Non-reactive read, for call sites outside a component. */
export function isFavoriteNow(item: Pick<MediaItem, "id" | "userData">): boolean {
  return resolveIsFavorite(item, get(overrides));
}

/**
 * Drop the items a listing should no longer show once un-favourited.
 *
 * Pure so it can be unit-tested without mounting the page: un-hearting on the
 * Favourites grid must remove the card, while a *newly* favourited item is
 * left alone (it belongs to whatever scope the caller fetched).
 *
 * TRACES: UR-067 | DR-117, DR-119 | UT-106
 */
export function retainFavorites<T extends Pick<MediaItem, "id" | "userData">>(
  items: T[],
  overrideMap: Map<string, boolean>
): T[] {
  return items.filter((item) => resolveIsFavorite(item, overrideMap));
}

/** Count of items still favourited, for "hide the row when empty" decisions. */
export const hasOverrides = derived(overrides, ($o) => $o.size > 0);
