import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import { qk } from "../lib/queryKeys";
import { useQuery } from "@tanstack/react-query";
import { api } from "../lib/api";
import { parseFeedView, type FeedView } from "../lib/feedView";
import { LS, readAccount, writeAccount } from "../lib/storage";

// Owns the feed's view mode (the card/row/tile density switcher), lifted out of App so both the feed
// page and the channel page read it via hooks instead of prop-drilling `view`/`setView` through App.
// Split State + Actions contexts, mirroring the other providers; composed in main.tsx around <App/>.
//
// The view mode is an account PREFERENCE, not a filter: it persists to the server on pick (savePrefs)
// and is adopted from server prefs on login — so unlike the ephemeral list filters, this provider
// carries the same server-sync the App god component used to. A localStorage mirror seeds the initial
// render synchronously; the passive qk.me() observer adopts the server value once the account resolves.

interface FeedViewActions {
  setView: (v: FeedView) => void;
}

const StateContext = createContext<FeedView>("cards");
const ActionsContext = createContext<FeedViewActions>({ setView: () => {} });

export function useFeedView(): FeedView {
  return useContext(StateContext);
}
export function useFeedViewActions(): FeedViewActions {
  return useContext(ActionsContext);
}

export function FeedViewProvider({ children }: { children: ReactNode }) {
  const [view, setViewState] = useState<FeedView>(() =>
    parseFeedView(readAccount(LS.feedView, null)),
  );
  // Passive observer of the account App fetches (enabled:false → reads cache, re-renders on update).
  const { data: me } = useQuery({ queryKey: qk.me(), queryFn: api.me, enabled: false });

  // A user pick persists both to the localStorage mirror (instant reload) and to the server.
  const setView = useCallback((next: FeedView) => {
    setViewState(next);
    writeAccount(LS.feedView, next);
    api.savePrefs({ view: next }).catch(() => {});
  }, []);

  // Adopt the server-stored view on login / account switch. Writes the mirror but does NOT savePrefs
  // (that would echo the just-adopted value straight back). parseFeedView also maps the pre-0.45
  // "grid" / "list" values forward.
  useEffect(() => {
    const prefs = me?.preferences;
    if (!prefs) return;
    const adopted = parseFeedView(prefs.view);
    setViewState(adopted);
    writeAccount(LS.feedView, adopted);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [me?.id]);

  const actions = useMemo<FeedViewActions>(() => ({ setView }), [setView]);

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