import { createContext, useCallback, useContext, useMemo, useState, type ReactNode } from "react";
import { EMPTY_PLEX_FILTERS, type PlexFilters } from "../lib/api";
import { getAccountRaw, LS, setAccountRaw } from "../lib/storage";

// Owns the Plex module's shared local state — the left-rail library scope / watch-state / sort /
// expanded filters, the header search term, and the "open this playlist" hand-off — lifted out of
// App so the PlexSidebar (rail), PlexBrowse (content), and the header search box read it via hooks
// instead of prop-drilling through App. Mirrors FeedFiltersProvider (split State + Actions contexts,
// stable useCallback setters, one-line hooks; composed in main.tsx around <App/>).
//
// scope / show / sort / filters / q are per-account persisted (localStorage); the account switch does
// a full reload, so init-from-storage is all the hydration they need. `playlistOpen` is an ephemeral
// hand-off (the rail sets it, PlexBrowse consumes it into a history subview then clears it). The Plex
// search term is deliberately its OWN state, NOT the feed's `filters.q`, so a Plex search never leaks
// into (and is never greeted by a stale value from) the feed.

type PlexState = {
  scope: string; // movie | show | both (unified cross-library scope)
  show: string;
  sort: string;
  filters: PlexFilters;
  q: string;
  playlistOpen: number | null;
};

interface PlexActions {
  setScope: (v: string) => void;
  setShow: (v: string) => void;
  setSort: (v: string) => void;
  setFilters: (f: PlexFilters) => void;
  setQ: (q: string) => void;
  setPlaylistOpen: (id: number | null) => void;
}

const StateContext = createContext<PlexState>({
  scope: "both",
  show: "all",
  sort: "title",
  filters: EMPTY_PLEX_FILTERS,
  q: "",
  playlistOpen: null,
});
const ActionsContext = createContext<PlexActions>({
  setScope: () => {},
  setShow: () => {},
  setSort: () => {},
  setFilters: () => {},
  setQ: () => {},
  setPlaylistOpen: () => {},
});

export function usePlex(): PlexState {
  return useContext(StateContext);
}
export function usePlexActions(): PlexActions {
  return useContext(ActionsContext);
}

export function PlexProvider({ children }: { children: ReactNode }) {
  // The former per-library picker is now a cross-library SCOPE: movie | show | both (unified library).
  // (Reuses the old LS.plexLibrary key; an old stored library-id value falls back to "both".)
  const [scope, setScopeState] = useState<string>(() => {
    const v = getAccountRaw(LS.plexLibrary) ?? "both";
    return ["movie", "show", "both"].includes(v) ? v : "both";
  });
  const [show, setShowState] = useState<string>(() => getAccountRaw(LS.plexShow) ?? "all");
  const [sort, setSortState] = useState<string>(() => getAccountRaw(LS.plexSort) ?? "title");
  // The expanded Plex filters live as one JSON blob (the string-only account store serializes it).
  const [filtersRaw, setFiltersRaw] = useState<string>(() => getAccountRaw(LS.plexFilters) ?? "{}");
  const filters = useMemo<PlexFilters>(() => {
    try {
      return { ...EMPTY_PLEX_FILTERS, ...JSON.parse(filtersRaw) };
    } catch {
      return EMPTY_PLEX_FILTERS;
    }
  }, [filtersRaw]);
  // Survives F5 (persisted), unlike the feed search — see the scope note above.
  const [q, setQState] = useState<string>(() => getAccountRaw(LS.plexQ) ?? "");
  const [playlistOpen, setPlaylistOpen] = useState<number | null>(null);

  const setScope = useCallback((v: string) => {
    setScopeState(v);
    setAccountRaw(LS.plexLibrary, v);
  }, []);
  const setShow = useCallback((v: string) => {
    setShowState(v);
    setAccountRaw(LS.plexShow, v);
  }, []);
  const setSort = useCallback((v: string) => {
    setSortState(v);
    setAccountRaw(LS.plexSort, v);
  }, []);
  const setFilters = useCallback((f: PlexFilters) => {
    const s = JSON.stringify(f);
    setFiltersRaw(s);
    setAccountRaw(LS.plexFilters, s);
  }, []);
  const setQ = useCallback((v: string) => {
    setQState(v);
    setAccountRaw(LS.plexQ, v);
  }, []);

  const state = useMemo<PlexState>(
    () => ({ scope, show, sort, filters, q, playlistOpen }),
    [scope, show, sort, filters, q, playlistOpen],
  );
  const actions = useMemo<PlexActions>(
    () => ({ setScope, setShow, setSort, setFilters, setQ, setPlaylistOpen }),
    [setScope, setShow, setSort, setFilters, setQ],
  );

  return (
    <ActionsContext.Provider value={actions}>
      <StateContext.Provider value={state}>{children}</StateContext.Provider>
    </ActionsContext.Provider>
  );
}
