import { lazy, type ComponentType } from "react";
import type { Page } from "../lib/urlState";
import type { PanelId, PanelLayout } from "../lib/panelLayout";
import { useMe } from "../lib/useMe";
import { useFeedFilters, useFeedFiltersActions } from "./FeedFiltersProvider";
import { useFeedView, useFeedViewActions } from "./FeedViewProvider";
import { useNavigation, useNavigationActions } from "./NavigationProvider";
import Sidebar from "./Sidebar";
import PlaylistsRail from "./PlaylistsRail";

// The RENDER half of the module registry: which component (and side rail) each page renders. The
// metadata half — nav order, label, icon, gate — lives in lib/modules.ts (imported by NavSidebar /
// Header / App's gate check). Together they let App drive the whole shell from `page` alone, with no
// `page === X` chrome conditionals.
//
// Every content entry is a PROP-FREE component: it reads `me` from useMe() and its module-local state
// from the scoped providers, so App renders `<Content />` uniformly. The two that need per-render
// wiring get a thin wrapper here (FeedPage supplies the GLOBAL feed scope; the channel page threads
// its own isolated scope to <Feed> directly — see the scope note in FeedFiltersProvider).

// Route-level code splitting: each page is its own lazy chunk (admin-only pages never reach
// non-admins; the logged-out landing pulls only the shell). Rendered inside App's <Suspense>.
const Feed = lazy(() => import("./Feed"));
const Channels = lazy(() => import("./Channels"));
const Playlists = lazy(() => import("./Playlists"));
const PlexBrowse = lazy(() => import("./PlexBrowse"));
const PlexSidebar = lazy(() => import("./PlexSidebar"));
const NotificationsPanel = lazy(() => import("./NotificationsPanel"));
const Messages = lazy(() => import("./Messages"));
const DownloadCenter = lazy(() => import("./DownloadCenter"));
const Stats = lazy(() => import("./Stats"));
const Scheduler = lazy(() => import("./Scheduler"));
const ConfigPanel = lazy(() => import("./ConfigPanel"));
const AdminUsers = lazy(() => import("./AdminUsers"));
const AuditLog = lazy(() => import("./AuditLog"));
const SettingsPanel = lazy(() => import("./SettingsPanel"));

// The GLOBAL feed page: wires <Feed> to the app-wide feed filters / view / live-search. (The channel
// page renders <Feed> itself with its own channel-scoped filters, so those two never share state.)
function FeedPage() {
  const me = useMe();
  const filters = useFeedFilters();
  const { setFilters } = useFeedFiltersActions();
  const view = useFeedView();
  const { setView } = useFeedViewActions();
  const { ytSearch } = useNavigation();
  const { enterYtSearch, exitYtSearch } = useNavigationActions();
  return (
    <Feed
      filters={filters}
      setFilters={setFilters}
      view={view}
      setView={setView}
      canRead={me.can_read}
      isDemo={me.is_demo}
      ytSearch={ytSearch}
      onYtSearch={enterYtSearch}
      onExitYtSearch={exitYtSearch}
    />
  );
}

function MessagesPage() {
  const me = useMe();
  return (
    <div className="p-4 max-w-3xl w-full mx-auto">
      <Messages meId={me.id} />
    </div>
  );
}

export type PageDef = {
  // Prop-free by construction: reads `me` + module state from hooks/providers.
  Component: ComponentType;
  // Channels + Audit render a table with a sticky header at the scroller top; the shell's top fade
  // would sit on it and flip on with the first scroll, so they turn it off. Defaults to on.
  fadeTop?: boolean;
};

// page id → the component App renders in the content column (+ its shell chrome config).
export const PAGE_CONTENT: Record<Page, PageDef> = {
  feed: { Component: FeedPage },
  channels: { Component: Channels, fadeTop: false },
  playlists: { Component: Playlists },
  plex: { Component: PlexBrowse },
  notifications: { Component: NotificationsPanel },
  messages: { Component: MessagesPage },
  downloads: { Component: DownloadCenter },
  stats: { Component: Stats },
  scheduler: { Component: Scheduler },
  config: { Component: ConfigPanel },
  users: { Component: AdminUsers },
  audit: { Component: AuditLog, fadeTop: false },
  settings: { Component: SettingsPanel },
};

// The uniform side-rail contract — shell layout/collapse only; the rail reads its module state from
// its provider and `me` from useMe().
type RailProps = {
  layout: PanelLayout;
  setLayout: (l: PanelLayout) => void;
  collapsed: boolean;
  onToggleCollapse: () => void;
};

// Which collapse flag a rail uses (feed + plex share the filter rail's flag; playlists has its own).
type RailCollapseKey = "filter" | "playlists";

export type RailDef = {
  Rail: ComponentType<RailProps>;
  // The persisted panel-layout record this rail edits (App owns the panelLayouts map).
  panelId: PanelId;
  collapse: RailCollapseKey;
};

// page id → its side rail (only the three pages that have one). App renders it in the rail slot.
export const PAGE_RAIL: Partial<Record<Page, RailDef>> = {
  feed: { Rail: Sidebar, panelId: "feed", collapse: "filter" },
  plex: { Rail: PlexSidebar, panelId: "plex", collapse: "filter" },
  playlists: { Rail: PlaylistsRail, panelId: "playlists", collapse: "playlists" },
};
