import { useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { api, HttpError, type FeedFilters } from "./lib/api";
import {
  applyTheme,
  DEFAULT_THEME,
  loadLocalTheme,
  saveLocalTheme,
  type ThemePrefs,
} from "./lib/theme";
import { hasFilterParams, paramsToFilters, readPage, syncUrl, type Page } from "./lib/urlState";
import {
  loadLayout,
  normalizeLayout,
  saveLayoutLocal,
  type SidebarLayout,
} from "./lib/sidebarLayout";
import { configureNotifications, notify } from "./lib/notifications";
import { setHintsEnabled } from "./lib/hints";
import Login from "./components/Login";
import Header from "./components/Header";
import Sidebar from "./components/Sidebar";
import Feed from "./components/Feed";
import Channels from "./components/Channels";
import SettingsPanel from "./components/SettingsPanel";
import Toaster from "./components/Toaster";

const DEFAULT_FILTERS: FeedFilters = {
  tags: [],
  tagMode: "or",
  q: "",
  sort: "newest",
  includeNormal: true,
  includeShorts: false,
  includeLive: false,
  show: "unwatched",
};

const FILTERS_KEY = "subfeed.filters";

function loadStoredFilters(): FeedFilters {
  try {
    return { ...DEFAULT_FILTERS, ...JSON.parse(localStorage.getItem(FILTERS_KEY) || "{}") };
  } catch {
    return DEFAULT_FILTERS;
  }
}

// URL wins over localStorage so a pasted link reproduces the exact view.
function loadInitialFilters(): FeedFilters {
  const params = new URLSearchParams(window.location.search);
  if (hasFilterParams(params)) return paramsToFilters(params, DEFAULT_FILTERS);
  return loadStoredFilters();
}

export default function App() {
  const [theme, setThemeState] = useState<ThemePrefs>(() => loadLocalTheme());
  const [filters, setFiltersState] = useState<FeedFilters>(loadInitialFilters);
  const [view, setView] = useState<"grid" | "list">("grid");
  const [sidebarLayout, setSidebarLayoutState] = useState<SidebarLayout>(loadLayout);
  const [page, setPageState] = useState<Page>(readPage);
  const [settingsOpen, setSettingsOpen] = useState(false);

  function setFilters(next: FeedFilters) {
    setFiltersState(next);
    localStorage.setItem(FILTERS_KEY, JSON.stringify(next));
    syncUrl(next, page);
  }

  function setPage(next: Page) {
    setPageState(next);
    syncUrl(filters, next);
  }

  function setSidebarLayout(next: SidebarLayout) {
    setSidebarLayoutState(next);
    saveLayoutLocal(next);
    api.savePrefs({ sidebarLayout: next }).catch(() => {});
  }

  useEffect(() => applyTheme(theme), [theme]);

  // Reflect the initial filters + page into the address bar so the URL is always shareable.
  useEffect(() => syncUrl(filters, page), []); // eslint-disable-line react-hooks/exhaustive-deps

  const meQuery = useQuery({ queryKey: ["me"], queryFn: api.me });

  // On login, adopt server-stored preferences.
  useEffect(() => {
    const prefs = meQuery.data?.preferences;
    if (!prefs) return;
    if (prefs.theme) {
      const merged = { ...DEFAULT_THEME, ...prefs.theme };
      setThemeState(merged);
      saveLocalTheme(merged);
    }
    if (prefs.view === "grid" || prefs.view === "list") setView(prefs.view);
    if (prefs.sidebarLayout) {
      const l = normalizeLayout(prefs.sidebarLayout);
      setSidebarLayoutState(l);
      saveLayoutLocal(l);
    }
    if (prefs.notifications) configureNotifications(prefs.notifications);
    if (typeof prefs.hints === "boolean") setHintsEnabled(prefs.hints);
    if (typeof prefs.performanceMode === "boolean")
      document.documentElement.dataset.perf = prefs.performanceMode ? "1" : "";
    // Nudge admins when access requests are waiting (in lieu of a server-push bell).
    const pending = meQuery.data?.pending_invites ?? 0;
    if (meQuery.data?.role === "admin" && pending > 0) {
      notify({
        level: "warning",
        title: "Access requests",
        message: `${pending} pending — review in Settings → Account.`,
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [meQuery.data?.id]);

  function setTheme(next: ThemePrefs) {
    setThemeState(next);
    saveLocalTheme(next);
    api.savePrefs({ theme: next }).catch(() => {});
  }
  function changeView(v: "grid" | "list") {
    setView(v);
    api.savePrefs({ view: v }).catch(() => {});
  }

  if (meQuery.isLoading)
    return <div className="min-h-screen grid place-items-center text-muted">Loading…</div>;
  if (meQuery.error instanceof HttpError && meQuery.error.status === 401)
    return <Login />;
  if (meQuery.error)
    return (
      <div className="min-h-screen grid place-items-center text-muted">
        Something went wrong.
      </div>
    );

  return (
    <div className="h-screen flex flex-col bg-bg text-fg">
      <Header
        me={meQuery.data!}
        filters={filters}
        setFilters={setFilters}
        page={page}
        setPage={setPage}
        onOpenSettings={() => setSettingsOpen(true)}
      />
      <div className="flex flex-1 min-h-0">
        {page === "feed" && (
          <Sidebar
            filters={filters}
            setFilters={setFilters}
            layout={sidebarLayout}
            setLayout={setSidebarLayout}
          />
        )}
        <main className="flex-1 min-w-0 overflow-y-auto">
          {page === "feed" ? (
            <Feed filters={filters} setFilters={setFilters} view={view} />
          ) : (
            <Channels
              canWrite={meQuery.data!.can_write}
              onViewChannel={(id, name) => {
                setFilters({ ...filters, channelId: id, channelName: name, show: "all" });
                setPage("feed");
              }}
            />
          )}
        </main>
      </div>
      {settingsOpen && (
        <SettingsPanel
          me={meQuery.data!}
          theme={theme}
          setTheme={setTheme}
          view={view}
          setView={changeView}
          onClose={() => setSettingsOpen(false)}
        />
      )}
      <Toaster />
    </div>
  );
}
