import {
  Map,
  User,
  Swords,
  Dice5,
  Volume2,
  Settings,
  ChevronLeft,
  Timer,
  Calendar,
  Wand2,
  BookOpen,
  ImagePlus,
  Shuffle,
  Flag,
  History,
} from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { Dashboard } from "./components/Dashboard";
import { SettingsPanel } from "./components/SettingsPanel";
import { NpcGenerator } from "./components/NpcGenerator";
import { DiceRoller } from "./components/DiceRoller";
import { SessionLogger } from "./components/SessionLogger";
import { EncounterBuilder } from "./components/EncounterBuilder";
import { InitiativeTracker } from "./components/InitiativeTracker";
import { RandomTables } from "./components/RandomTables";
import { CalendarWidget } from "./components/CalendarWidget";
import { WorldBuilder } from "./components/WorldBuilder";
import { ItemForge } from "./components/ItemForge";
import { QuestDesigner } from "./components/QuestDesigner";
import { Soundboard } from "./components/Soundboard";
import { LorePanel } from "./components/LorePanel";
import { ImageGenerator } from "./components/ImageGenerator";
import { ToastContainer } from "./components/Toast";
import { CommandPalette } from "./components/CommandPalette";
import { ErrorBoundary } from "./components/ErrorBoundary";
import { ConnectionPill } from "./components/ConnectionPill";
import { HistoryView } from "./components/HistoryView";
import type { Generation, GenerationKind } from "./lib/generations";

export type View =
  | "dashboard"
  | "world"
  | "npcs"
  | "encounter"
  | "dice"
  | "session"
  | "sound"
  | "initiative"
  | "tables"
  | "calendar"
  | "quest"
  | "items"
  | "lore"
  | "image"
  | "settings"
  | "history";

// ponytail: tools that accept a prefill from history. Mirrors the kinds.
const PREFILLABLE: Partial<Record<View, GenerationKind>> = {
  npcs: "npc",
  encounter: "encounter",
  world: "world",
  items: "item",
  quest: "quest",
  session: "session",
  image: "image",
};

type NavGroup = "session" | "world";

interface NavItem {
  icon: typeof Map;
  label: string;
  view: View;
  group: NavGroup;
  shortcut?: string;
}

// ponytail: single source of truth for nav; groups drive the rail layout.
export const navItems: NavItem[] = [
  { icon: Timer, label: "Initiative", view: "initiative", group: "session", shortcut: "1" },
  { icon: Dice5, label: "Dice", view: "dice", group: "session", shortcut: "2" },
  { icon: Swords, label: "Encounter", view: "encounter", group: "session", shortcut: "3" },
  { icon: User, label: "NPCs", view: "npcs", group: "session", shortcut: "4" },
  { icon: Flag, label: "Quest", view: "quest", group: "session", shortcut: "5" },
  { icon: Volume2, label: "Sound", view: "sound", group: "session", shortcut: "6" },
  { icon: Map, label: "World", view: "world", group: "world", shortcut: "7" },
  { icon: BookOpen, label: "Lore", view: "lore", group: "world" },
  { icon: Wand2, label: "Items", view: "items", group: "world" },
  { icon: Calendar, label: "Calendar", view: "calendar", group: "world" },
  { icon: Shuffle, label: "Tables", view: "tables", group: "world" },
  { icon: ImagePlus, label: "Image", view: "image", group: "world" },
  { icon: History, label: "History", view: "history", group: "world" },
];

function renderView(
  view: View,
  prefill: Generation | null,
  onPrefillConsumed: () => void,
  rehydrate: (kind: GenerationKind, data: Generation) => void,
): React.ReactNode {
  // ponytail: history view renders its own list/detail panes, so it doesn't
  // use the prefill or wrapper pattern.
  if (view === "history") {
    return <HistoryView onRehydrate={rehydrate} />;
  }
  // Tools that accept prefill.
  if (view === "npcs") return <NpcGenerator prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "encounter") return <EncounterBuilder prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "world") return <WorldBuilder prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "items") return <ItemForge prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "quest") return <QuestDesigner prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "session") return <SessionLogger prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  if (view === "image") return <ImageGenerator prefill={prefill} onPrefillConsumed={onPrefillConsumed} />;
  switch (view) {
    case "dice":
      return <DiceRoller />;
    case "initiative":
      return <InitiativeTracker />;
    case "tables":
      return <RandomTables />;
    case "calendar":
      return <CalendarWidget />;
    case "settings":
      return <SettingsPanel />;
    case "lore":
      return <LorePanel />;
    case "sound":
      return <Soundboard />;
    default:
      return null;
  }
}

// ponytail: per-tool preferred max-width. Wider tools stop fighting the rail.
const viewMaxWidth: Partial<Record<View, string>> = {
  dice: "max-w-2xl",
  settings: "max-w-2xl",
  npcs: "max-w-4xl",
  encounter: "max-w-4xl",
  quest: "max-w-4xl",
  items: "max-w-4xl",
  world: "max-w-6xl",
  lore: "max-w-6xl",
  image: "max-w-6xl",
  sound: "max-w-6xl",
  session: "max-w-6xl",
  initiative: "max-w-2xl",
  tables: "max-w-2xl",
  calendar: "max-w-2xl",
};

// ponytail: tools that accept a prefill. The map mirrors `PREFILLABLE` above
// and exists so rehydrate() can find the right View for a given kind.
const PREFILLABLE_TOOLS = {
  npcs: NpcGenerator,
  encounter: EncounterBuilder,
  world: WorldBuilder,
  items: ItemForge,
  quest: QuestDesigner,
  session: SessionLogger,
  image: ImageGenerator,
} as const;

export default function App() {
  const [view, setView] = useState<View>("dashboard");
  const [paletteOpen, setPaletteOpen] = useState(false);
  // ponytail: prefill is set when the user clicks "Open in tool" in History.
  // The targeted tool reads it via usePrefillEffect and calls onConsumed
  // to clear it. State lives here so the rehydrate→switch→consume dance
  // doesn't depend on a shared store.
  const [prefill, setPrefill] = useState<Generation | null>(null);

  function rehydrate(kind: GenerationKind, data: Generation) {
    const target = (Object.keys(PREFILLABLE_TOOLS) as View[]).find(
      (v) => PREFILLABLE[v] === kind,
    );
    if (!target) return;
    setPrefill(data);
    setView(target);
  }

  // ⌘K / Ctrl-K opens the command palette; ⌘H opens the History page; Esc closes the palette.
  useEffect(() => {
    function onKey(e: KeyboardEvent) {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setPaletteOpen((o) => !o);
        return;
      }
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "h") {
        e.preventDefault();
        setView("history");
        return;
      }
      if (e.key === "Escape" && paletteOpen) {
        setPaletteOpen(false);
        return;
      }
      // Digit shortcuts jump to nav items, but not while typing in an input.
      if (
        !paletteOpen &&
        !e.metaKey &&
        !e.ctrlKey &&
        !e.altKey &&
        /^[1-9]$/.test(e.key) &&
        !(e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
      ) {
        const target = navItems.find((n) => n.shortcut === e.key);
        if (target) {
          e.preventDefault();
          setView(target.view);
        }
      }
      // ⌘, opens settings.
      if ((e.metaKey || e.ctrlKey) && e.key === ",") {
        e.preventDefault();
        setView("settings");
      }
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [paletteOpen]);

  const isOnDashboard = view === "dashboard";
  const groupedNav = useMemo(
    () => ({
      session: navItems.filter((n) => n.group === "session"),
      world: navItems.filter((n) => n.group === "world"),
    }),
    [],
  );

  function NavButton({ item }: { item: NavItem }) {
    const active = view === item.view;
    return (
      <button
        onClick={() => setView(item.view)}
        aria-label={item.label + (item.shortcut ? ` (${item.shortcut})` : "")}
        data-tooltip={item.label}
        className={`w-10 h-10 rounded-lg flex items-center justify-center transition-colors cursor-pointer ${
          active
            ? "bg-[var(--color-bg-card)] text-[var(--color-gold-bright)]"
            : "text-[var(--color-text-dim)] hover:text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-card)]"
        }`}
      >
        <item.icon size={item.view === "tables" ? 18 : 18} />
      </button>
    );
  }

  return (
    <div className="flex h-screen w-screen overflow-hidden bg-[var(--color-bg-deep)]">
      {/* ponytail: skip-to-content for keyboard users — jumps past the rail. */}
      <a
        href="#main-content"
        className="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:top-2 focus:left-2 focus:px-3 focus:py-1.5 focus:rounded-lg focus:bg-[var(--color-gold-bright)] focus:text-[var(--color-bg-deep)] focus:text-xs focus:font-semibold"
      >
        Skip to content
      </a>
      {/* Left Rail */}
      <nav
        aria-label="Primary"
        className="flex flex-col items-center w-14 bg-[var(--color-bg-surface)] border-r border-[var(--color-border-subtle)] py-3 gap-1 shrink-0"
      >
        {/* App Logo — goes to dashboard */}
        <button
          onClick={() => setView("dashboard")}
          aria-label="Dashboard"
          data-tooltip="Dashboard"
          className={`w-8 h-8 rounded-lg flex items-center justify-center mb-4 font-heading font-bold text-lg cursor-pointer transition-colors ${
            isOnDashboard
              ? "bg-[var(--color-gold-bright)] text-[var(--color-bg-deep)]"
              : "bg-[var(--color-bg-card)] text-[var(--color-gold-bright)] hover:bg-[var(--color-gold-bright)] hover:text-[var(--color-bg-deep)]"
          }`}
        >
          ⚔
        </button>

        {/* SESSION group — in-combat tools */}
        <GroupLabel>Session</GroupLabel>
        {groupedNav.session.map((item) => (
          <NavButton key={item.view} item={item} />
        ))}

        <div className="w-6 h-px bg-[var(--color-border-subtle)] my-1.5" />

        {/* WORLD group — prep / worldbuilding tools */}
        <GroupLabel>World</GroupLabel>
        {groupedNav.world.map((item) => (
          <NavButton key={item.view} item={item} />
        ))}

        {/* Spacer */}
        <div className="flex-1" />

        {/* Settings */}
        <button
          onClick={() => setView("settings")}
          aria-label="Settings (⌘,)"
          data-tooltip="Settings"
          className={`w-10 h-10 rounded-lg flex items-center justify-center transition-colors cursor-pointer ${
            view === "settings"
              ? "bg-[var(--color-bg-card)] text-[var(--color-gold-bright)]"
              : "text-[var(--color-text-dim)] hover:text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-card)]"
          }`}
        >
          <Settings size={18} />
        </button>
      </nav>

      {/* Main Content Area */}
      <div className="flex flex-col flex-1 overflow-hidden">
        {/* Title Bar */}
        <header
          className="flex items-center h-10 px-4 bg-[var(--color-bg-surface)] border-b border-[var(--color-border-subtle)] shrink-0"
          data-tauri-drag-region
        >
          {!isOnDashboard && (
            <button
              onClick={() => setView("dashboard")}
              data-tauri-no-drag
              className="mr-3 text-[var(--color-text-secondary)] hover:text-[var(--color-gold-bright)] transition-colors cursor-pointer"
              title="Back to dashboard"
              aria-label="Back to dashboard"
            >
              <ChevronLeft size={18} />
            </button>
          )}
          <span className="font-heading text-[var(--color-gold-bright)] text-base font-bold tracking-wider">
            DM-Pal
          </span>
          <button
            onClick={() => setPaletteOpen(true)}
            data-tauri-no-drag
            className="ml-4 flex items-center gap-2 text-[var(--color-text-dim)] text-xs hover:text-[var(--color-text-secondary)] transition-colors cursor-pointer"
            aria-label="Open command palette (⌘K)"
          >
            <span>Jump to…</span>
            <kbd className="hidden sm:inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded border border-[var(--color-border-subtle)] bg-[var(--color-bg-deep)] text-[10px] font-mono">
              ⌘K
            </kbd>
          </button>
          <button
            onClick={() => setView("history")}
            data-tauri-no-drag
            className="ml-2 flex items-center gap-1.5 text-[var(--color-text-dim)] text-xs hover:text-[var(--color-gold-bright)] transition-colors cursor-pointer"
            aria-label="Open history (⌘H)"
            title="History (⌘H)"
          >
            <History size={12} />
            <span className="hidden sm:inline">History</span>
            <kbd className="hidden md:inline-flex items-center px-1.5 py-0.5 rounded border border-[var(--color-border-subtle)] bg-[var(--color-bg-deep)] text-[10px] font-mono">
              ⌘H
            </kbd>
          </button>
          <div className="ml-auto" data-tauri-no-drag />
          <ConnectionPill />
        </header>

        {/* Main Content */}
        <main className="flex-1 overflow-auto" id="main-content">
          <ErrorBoundary>
            {isOnDashboard ? (
              <Dashboard onNavigate={setView} />
            ) : view === "history" ? (
              <HistoryView onRehydrate={(k, d) => rehydrate(k, d)} />
            ) : (
              <div className={`${viewMaxWidth[view] ?? "max-w-2xl"} mx-auto p-6`}>
                {view === "settings" ? (
                  <div className="glass-card p-6">
                    <h2 className="font-heading text-[var(--color-gold-bright)] text-lg font-semibold mb-4">
                      Settings
                    </h2>
                    <SettingsPanel />
                  </div>
                ) : (
                  <div className="glass-card p-6">
                    {renderView(view, prefill, () => setPrefill(null), rehydrate)}
                  </div>
                )}
              </div>
            )}
          </ErrorBoundary>
        </main>
      </div>

      <CommandPalette
        open={paletteOpen}
        onClose={() => setPaletteOpen(false)}
        onSelect={(v) => {
          setView(v);
          setPaletteOpen(false);
        }}
      />

      {/* Toast notifications */}
      <ToastContainer />
    </div>
  );
}

function GroupLabel({ children }: { children: React.ReactNode }) {
  return (
    <span
      className="text-[9px] uppercase tracking-widest text-[var(--color-text-dim)] font-medium mb-1 mt-1"
      aria-hidden="true"
    >
      {children}
    </span>
  );
}
