import { useEffect, useRef, useState } from 'react';
import { Link, Outlet, useRouterState } from '@tanstack/react-router';
import {
  Crown, LayoutDashboard, UserRound, Swords, Map as MapIcon, Dices, BookOpenText, RadioTower,
  LibraryBig, Settings as SettingsIcon, Search, PanelLeftClose, PanelLeftOpen, Sun, Moon, PanelRight,
  ScrollText, Drama, Target, CalendarDays, FlaskConical, Sparkles,
  type LucideIcon,
} from 'lucide-react';
import { useUiStore } from '@/stores/uiStore';
import { CommandPalette } from '@/components/CommandPalette';
import { useActiveCampaign, useCampaigns } from '@/features/campaigns/hooks';
import { cn } from '@/lib/cn';
import { ErrorBoundary } from '@/components/ui/ErrorBoundary';
import { RollTray } from '@/components/ui/RollTray';
import { Select } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { SessionControl } from '@/features/play/SessionControl';
import { HandoutControl } from '@/features/play/HandoutControl';
import { useSessionBroadcaster } from '@/features/play/useSessionBroadcaster';
import { usePlayerConnection } from '@/features/play/usePlayerConnection';
import { useCloudAutosave } from '@/features/cloud/useCloudAutosave';
import { PlayerSessionBadge } from '@/features/play/PlayerConnection';
import { SignalsBell } from '@/features/assistant/SignalsBell';
import { SyncStatusIndicator } from '@/features/cloud/SyncStatusIndicator';
import { SessionSidebar } from '@/features/play/SessionSidebar';
import { useSessionStore } from '@/stores/sessionStore';

type NavItem = { to: string; label: string; icon: LucideIcon; exact: boolean; group: 'top' | 'play' | 'world' | 'reference' };
const NAV: NavItem[] = [
  { to: '/', label: 'Campaigns', icon: LibraryBig, exact: true, group: 'top' },
  { to: '/dashboard', label: 'Dashboard', icon: LayoutDashboard, exact: false, group: 'play' },
  { to: '/characters', label: 'Characters', icon: UserRound, exact: false, group: 'play' },
  { to: '/combat', label: 'Combat', icon: Swords, exact: false, group: 'play' },
  { to: '/maps', label: 'Battle Map', icon: MapIcon, exact: false, group: 'play' },
  { to: '/dice', label: 'Dice', icon: Dices, exact: false, group: 'play' },
  { to: '/notes', label: 'Notes', icon: ScrollText, exact: false, group: 'world' },
  { to: '/npcs', label: 'NPCs', icon: Drama, exact: false, group: 'world' },
  { to: '/quests', label: 'Quests', icon: Target, exact: false, group: 'world' },
  { to: '/calendar', label: 'Calendar', icon: CalendarDays, exact: false, group: 'world' },
  { to: '/compendium', label: 'Compendium', icon: BookOpenText, exact: false, group: 'reference' },
  { to: '/homebrew', label: 'Homebrew', icon: FlaskConical, exact: false, group: 'reference' },
  { to: '/assistant', label: 'Assistant', icon: Sparkles, exact: false, group: 'reference' },
  { to: '/play', label: 'Live Session', icon: RadioTower, exact: false, group: 'reference' },
];
const GROUPS: { id: NavItem['group']; label: string | null }[] = [
  { id: 'top', label: null },
  { id: 'play', label: 'At the Table' },
  { id: 'world', label: 'World' },
  { id: 'reference', label: 'Reference' },
];

function CampaignSwitcher() {
  const campaigns = useCampaigns();
  const active = useActiveCampaign();
  const setActive = useUiStore((s) => s.setActiveCampaign);

  if (campaigns.length === 0) {
    return <span className="text-xs text-muted">No campaigns yet</span>;
  }
  return (
    <Select
      aria-label="Active campaign"
      className="w-auto min-w-0 max-w-[34vw] shrink truncate sm:min-w-44"
      value={active?.id ?? ''}
      onChange={(e) => setActive(e.target.value || null)}
    >
      <option value="">— Select campaign —</option>
      {campaigns.map((c) => (
        <option key={c.id} value={c.id}>
          {c.name} ({c.system === '5e' ? 'D&D 5e' : 'PF2e'})
        </option>
      ))}
    </Select>
  );
}

function ThemeToggle() {
  const theme = useUiStore((s) => s.theme);
  const toggle = useUiStore((s) => s.toggleTheme);
  return (
    <Button size="icon" variant="ghost" onClick={toggle} aria-label="Toggle light/dark theme" title="Toggle theme">
      {theme === 'dark' ? <Sun size={18} aria-hidden /> : <Moon size={18} aria-hidden />}
    </Button>
  );
}

export function RootLayout() {
  const pathname = useRouterState({ select: (s) => s.location.pathname });
  const [paletteOpen, setPaletteOpen] = useState(false);
  const sessionDockOpen = useUiStore((s) => s.sessionDockOpen);
  const setSessionDock = useUiStore((s) => s.setSessionDock);
  const railCollapsed = useUiStore((s) => s.railCollapsed);
  const toggleRail = useUiStore((s) => s.toggleRail);
  const sessionConnected = useSessionStore((s) => s.status === 'connected');
  const sessionRole = useSessionStore((s) => s.role);
  const joinIntent = useSessionStore((s) => s.joinIntent);
  const activeCampaign = useActiveCampaign();
  // While the GM is hosting, mirror state to players (inert unless hosting).
  useSessionBroadcaster(activeCampaign ?? null);
  usePlayerConnection();
  useCloudAutosave();

  // Global Ctrl/Cmd+K opens the command palette.
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        setPaletteOpen((v) => !v);
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  // Players get the session panel docked open by default (once) — they live in it.
  const autoOpenedRef = useRef(false);
  useEffect(() => {
    if (!autoOpenedRef.current && joinIntent && sessionRole === 'player') {
      autoOpenedRef.current = true;
      setSessionDock(true);
    }
  }, [joinIntent, sessionRole, setSessionDock]);

  // Labels show only when expanded AND on >= sm; the rail is an icon strip (68px)
  // on phones and when collapsed, so a single nav serves every size.
  const showLabel = !railCollapsed;

  return (
    <>
      <div className="grid h-full grid-cols-[auto_1fr]">
        {/* ---- Left nav rail (single, responsive: icon strip on phones / collapsed) ---- */}
        <aside className={cn('paper-grain relative z-20 flex flex-col border-r border-line bg-panel transition-[width] duration-200 print:hidden', railCollapsed ? 'w-[68px]' : 'w-[68px] sm:w-60')}>
          <div className="relative z-[1] flex h-full flex-col">
            <Link to="/" className={cn('flex h-[60px] flex-none items-center gap-3 border-b border-line px-4', railCollapsed ? 'justify-center px-0' : 'justify-center px-0 sm:justify-start sm:px-4')} title="TTRPG Manager">
              <span className="grid h-9 w-9 flex-none place-items-center rounded-lg bg-gradient-to-b from-accent-soft to-accent text-accent-ink shadow-[inset_0_1px_0_rgba(255,255,255,0.3)]">
                <Crown size={19} strokeWidth={2} aria-hidden />
              </span>
              {showLabel && (
                <span className="hidden min-w-0 leading-tight sm:block">
                  <span className="block truncate font-display text-base font-semibold text-ink">TTRPG Manager</span>
                  <span className="smallcaps block" style={{ fontSize: 9, letterSpacing: '0.22em' }}>The Living Codex</span>
                </span>
              )}
            </Link>

            <nav aria-label="Primary" className="flex-1 overflow-y-auto py-2">
              {GROUPS.map((group) => (
                <div key={group.id}>
                  {group.label && showLabel && <div className="smallcaps hidden px-6 pt-4 pb-1.5 sm:block" style={{ fontSize: 9.5 }}>{group.label}</div>}
                  {NAV.filter((n) => n.group === group.id).map((item) => {
                    const active = item.exact ? pathname === item.to : pathname.startsWith(item.to);
                    const Ico = item.icon;
                    return (
                      <Link
                        key={item.to}
                        to={item.to}
                        title={item.label}
                        className={cn(
                          'relative mx-2.5 my-px flex h-[42px] items-center gap-3 rounded-[10px] text-[14.5px] font-medium transition-colors',
                          'justify-center px-0',
                          showLabel && 'sm:justify-start sm:px-3.5',
                          active ? 'bg-accent-glow font-semibold text-accent-deep' : 'text-muted hover:bg-elevated hover:text-ink',
                        )}
                      >
                        {active && <span className="absolute -left-2.5 top-2 bottom-2 w-[3px] rounded-r bg-accent" aria-hidden />}
                        <Ico size={19} strokeWidth={active ? 2 : 1.7} aria-hidden className="flex-none" />
                        {showLabel && <span className="hidden sm:inline">{item.label}</span>}
                      </Link>
                    );
                  })}
                </div>
              ))}
            </nav>

            <div className="hidden flex-none border-t border-line p-2.5 sm:block">
              <button
                onClick={toggleRail}
                className={cn('flex h-[42px] w-full items-center gap-3 rounded-[10px] text-[14.5px] font-medium text-muted transition-colors hover:bg-elevated hover:text-ink', railCollapsed ? 'justify-center px-0' : 'justify-start px-3.5')}
                title={railCollapsed ? 'Expand navigation' : 'Collapse navigation'}
                aria-label={railCollapsed ? 'Expand navigation' : 'Collapse navigation'}
              >
                {railCollapsed ? <PanelLeftOpen size={18} aria-hidden /> : <PanelLeftClose size={18} aria-hidden />}
                {!railCollapsed && <span>Collapse</span>}
              </button>
            </div>
          </div>
        </aside>

        {/* ---- Workarea: top context bar + canvas ---- */}
        <div className="flex min-w-0 flex-col">
          <header className="paper-grain relative z-10 flex h-[60px] flex-none items-center gap-2 border-b border-line bg-panel px-3 sm:px-5">
            <div className="relative z-[1] flex w-full items-center gap-2">
              <CampaignSwitcher />
              <div className="flex-1" />

              <button
                onClick={() => setPaletteOpen(true)}
                aria-label="Open command palette"
                title="Command palette (Ctrl/Cmd+K)"
                className="hidden h-[38px] min-w-44 items-center gap-2 rounded-full border border-line bg-surface px-3 text-muted transition-[border-color,box-shadow] hover:border-accent focus-visible:border-accent focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-accent-glow md:flex"
              >
                <Search size={16} aria-hidden />
                <span className="flex-1 text-left text-sm text-faint">Search the codex…</span>
                <kbd className="rounded border border-line px-1.5 font-mono text-[10.5px] text-faint">⌘K</kbd>
              </button>
              <Button size="icon" variant="ghost" className="md:hidden" onClick={() => setPaletteOpen(true)} aria-label="Open command palette" title="Command palette">
                <Search size={18} aria-hidden />
              </Button>

              <PlayerSessionBadge />
              <Button size="sm" variant="subtle" onClick={() => setSessionDock(true)} title="Session panel — who's here, rolls, chat" aria-label="Open session panel">
                <PanelRight size={15} aria-hidden />
                <span className="hidden sm:inline">Session</span>
                {sessionConnected && <span className="inline-block h-1.5 w-1.5 rounded-full bg-success align-middle" />}
              </Button>
              {activeCampaign && <HandoutControl />}
              <SessionControl />
              <SyncStatusIndicator />
              <SignalsBell />
              <ThemeToggle />
              <Link to="/settings" className="grid h-9 w-9 flex-none place-items-center rounded-md text-muted hover:bg-elevated hover:text-ink" title="Settings" aria-label="Settings">
                <SettingsIcon size={18} aria-hidden />
              </Link>
            </div>
          </header>

          <div className="flex min-h-0 flex-1">
            <main className="flex-1 overflow-auto">
              <ErrorBoundary resetKey={pathname}>
                <Outlet />
              </ErrorBoundary>
            </main>
            <SessionSidebar open={sessionDockOpen} onClose={() => setSessionDock(false)} />
          </div>
        </div>
      </div>

      <RollTray />
      {paletteOpen && <CommandPalette onClose={() => setPaletteOpen(false)} />}
    </>
  );
}
