/* Saints Calendar — Global Command Palette */

const { useState: useStateCP, useEffect: useEffectCP, useRef: useRefCP, useMemo: useMemoCP } = React;

const CommandPalette = ({ open, onClose, onNavigate, onOpenSaint, onSearch }) => {
  const [q, setQ] = useStateCP("");
  const [active, setActive] = useStateCP(0);
  const inputRef = useRefCP(null);
  const listRef = useRefCP(null);
  const [recent, setRecent] = useStateCP(() => {
    try { return JSON.parse(localStorage.getItem("sc.cp.recent") || "[]"); } catch { return []; }
  });

  useEffectCP(() => {
    if (open) {
      setQ("");
      setActive(0);
      setTimeout(() => inputRef.current?.focus(), 30);
    }
  }, [open]);

  // Destinations / actions surface
  const destinations = useMemoCP(() => [
    { id: "go-home", kind: "view", label: "Today", sub: "Today's principal feast & upcoming", glyph: "☀", action: () => onNavigate("home"), keywords: "home today landing" },
    { id: "go-calendar", kind: "view", label: "Calendar", sub: "Browse the liturgical year, day by day", glyph: "▦", action: () => onNavigate("calendar"), keywords: "calendar month year days feasts liturgical" },
    { id: "go-timeline", kind: "view", label: "Timeline", sub: "Saints across two millennia", glyph: "≡", action: () => onNavigate("timeline"), keywords: "timeline history century centuries era" },
    { id: "go-research", kind: "view", label: "Research", sub: "Corpus statistics, network, query builder, citations", glyph: "✦", action: () => onNavigate("research"), keywords: "research analytics tools query export citation graph network" },
    { id: "go-saved", kind: "view", label: "Library", sub: "Your saved saints, quotes, prayers, readings", glyph: "❦", action: () => onNavigate("saved"), keywords: "saved library bookmarks favorites collection" },
    { id: "go-search", kind: "view", label: "Advanced Search", sub: "Faceted search with filters", glyph: "⌕", action: () => onNavigate("search"), keywords: "search find filter advanced" },
    { id: "go-login", kind: "view", label: "Account & sign in", sub: "Sign in, manage subscriptions", glyph: "◉", action: () => onNavigate("login"), keywords: "account login signin signup subscribe email" },

    // Features in Research
    { id: "feat-compare", kind: "feature", label: "Compare saints", sub: "Side-by-side analysis", glyph: "⇆", action: () => onNavigate("research"), keywords: "compare comparison side by side" },
    { id: "feat-network", kind: "feature", label: "Relationships graph", sub: "Master/disciple, contemporaries", glyph: "✺", action: () => onNavigate("research"), keywords: "network graph relationships master disciple connections" },
    { id: "feat-query", kind: "feature", label: "Query builder", sub: "Build complex faceted queries", glyph: "{ }", action: () => onNavigate("research"), keywords: "query builder filter sql" },
    { id: "feat-citation", kind: "feature", label: "Citation export", sub: "Chicago, MLA, BibTeX", glyph: "❝", action: () => onNavigate("research"), keywords: "citation export bibliography chicago mla bibtex apa" },
    { id: "feat-stats", kind: "feature", label: "Corpus statistics", sub: "Distributions across the dataset", glyph: "▤", action: () => onNavigate("research"), keywords: "statistics stats dashboard chart data corpus" },

    // Browse facets
    { id: "br-doctors", kind: "browse", label: "Doctors of the Church", sub: "All proclaimed Doctors", glyph: "☩", action: () => onSearch("Doctor of the Church"), keywords: "doctor doctors church augustine aquinas teresa" },
    { id: "br-martyrs", kind: "browse", label: "Martyrs", sub: "Those who gave their lives", glyph: "✝", action: () => onSearch("martyr"), keywords: "martyr martyrs persecution" },
    { id: "br-franciscan", kind: "browse", label: "Franciscans", sub: "Order of Friars Minor", glyph: "✠", action: () => onSearch("Franciscan"), keywords: "franciscan francis assisi order" },
    { id: "br-dominican", kind: "browse", label: "Dominicans", sub: "Order of Preachers", glyph: "✠", action: () => onSearch("Dominican"), keywords: "dominican dominic preachers" },
    { id: "br-benedictine", kind: "browse", label: "Benedictines", sub: "Rule of St Benedict", glyph: "✠", action: () => onSearch("Benedictine"), keywords: "benedictine benedict monastery rule" },
    { id: "br-carmelite", kind: "browse", label: "Carmelites", sub: "Mount Carmel tradition", glyph: "✠", action: () => onSearch("Carmelite"), keywords: "carmelite teresa john cross" },
    { id: "br-italy", kind: "browse", label: "Italian saints", sub: "Saints of Italy", glyph: "◐", action: () => onSearch("Italy"), keywords: "italy italian rome assisi" },
    { id: "br-france", kind: "browse", label: "French saints", sub: "Saints of France", glyph: "◐", action: () => onSearch("France"), keywords: "france french" },
    { id: "br-13c", kind: "browse", label: "13th century", sub: "High medieval saints", glyph: "▣", action: () => onSearch("13th century"), keywords: "13th century medieval middle ages" },

    // Quick actions
    { id: "act-random", kind: "action", label: "Random saint", sub: "Open one at random", glyph: "✧", action: () => {
      const r = window.SAINTS[Math.floor(Math.random() * window.SAINTS.length)];
      onOpenSaint(r.id);
    }, keywords: "random surprise lucky" },
    { id: "act-today", kind: "action", label: "Jump to today's feast", sub: "Today's principal saint", glyph: "●", action: () => {
      const today = window.getSaintsForDay(5, 1);
      if (today.primary) onOpenSaint(today.primary.id);
    }, keywords: "today now current" },
    { id: "act-theme", kind: "action", label: "Toggle theme — Parchment / Vellum", sub: "Switch light & dark", glyph: "◐", action: () => {
      const cur = document.documentElement.dataset.theme;
      window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { theme: cur === "light" ? "dark" : "light" } }, "*");
      document.documentElement.dataset.theme = cur === "light" ? "dark" : "light";
    }, keywords: "theme dark light mode toggle parchment vellum" },
    { id: "act-density", kind: "action", label: "Toggle density — Spacious / Compact", sub: "Switch layout density", glyph: "▤", action: () => {
      const cur = document.documentElement.dataset.density;
      const next = cur === "spacious" ? "compact" : "spacious";
      window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { density: next } }, "*");
      document.documentElement.dataset.density = next;
    }, keywords: "density spacious compact layout" },
    { id: "act-nov3na", kind: "action", label: "Open Nov3na — sister site", sub: "Novenas & devotional prayer", glyph: "↗", action: () => window.open("https://nov3na.com", "_blank"), keywords: "nov3na novena prayer external" },
  ], [onNavigate, onOpenSaint, onSearch]);

  // Build full result set
  const results = useMemoCP(() => {
    const s = q.trim().toLowerCase();
    if (!s) {
      // Default state: recent + suggested destinations
      const recentItems = recent.map(rid => destinations.find(d => d.id === rid)).filter(Boolean).slice(0, 4);
      const suggested = destinations.filter(d => !recentItems.find(r => r.id === d.id) && (d.kind === "view" || d.kind === "feature")).slice(0, 8);
      return [
        ...(recentItems.length ? [{ header: "Recent" }, ...recentItems] : []),
        { header: "Jump to" }, ...suggested,
        { header: "Quick actions" }, ...destinations.filter(d => d.kind === "action").slice(0, 4),
      ];
    }
    const score = (item) => {
      const hay = `${item.label} ${item.sub} ${item.keywords || ""}`.toLowerCase();
      if (item.label.toLowerCase().startsWith(s)) return 100;
      if (item.label.toLowerCase().includes(s)) return 80;
      if (hay.includes(s)) return 50;
      return 0;
    };

    // Saints
    const saintHits = window.SAINTS.map(saint => {
      const hay = `${saint.honorific} ${saint.name} ${saint.epithet} ${saint.region} ${saint.order || ""} ${(saint.classification || []).join(" ")} ${(saint.patronage || []).join(" ")}`.toLowerCase();
      let sc = 0;
      if (saint.name.toLowerCase().startsWith(s)) sc = 100;
      else if (saint.name.toLowerCase().includes(s)) sc = 80;
      else if (hay.includes(s)) sc = 40;
      return sc > 0 ? {
        id: `s-${saint.id}`, kind: "saint", label: `${saint.honorific} ${saint.name}`,
        sub: `${saint.epithet} · ${window.formatDate(saint.feast.month, saint.feast.day)}`,
        glyph: "✦", _score: sc,
        action: () => onOpenSaint(saint.id)
      } : null;
    }).filter(Boolean).sort((a, b) => b._score - a._score).slice(0, 8);

    // Destinations / features / browse / actions
    const destHits = destinations
      .map(d => ({ ...d, _score: score(d) }))
      .filter(d => d._score > 0)
      .sort((a, b) => b._score - a._score);

    const grouped = (kind, header) => {
      const items = destHits.filter(d => d.kind === kind);
      return items.length ? [{ header }, ...items] : [];
    };

    const out = [
      ...(saintHits.length ? [{ header: "Saints" }, ...saintHits] : []),
      ...grouped("view", "Pages"),
      ...grouped("feature", "Features"),
      ...grouped("browse", "Browse"),
      ...grouped("action", "Actions"),
    ];

    if (out.length === 0) {
      return [
        { header: "No matches" },
        { id: "fallback-search", kind: "action", label: `Search corpus for "${q}"`, sub: "Open advanced search", glyph: "⌕",
          action: () => onSearch(q) }
      ];
    }
    return out;
  }, [q, destinations, recent]);

  const flatItems = useMemoCP(() => results.filter(r => !r.header), [results]);

  useEffectCP(() => { setActive(0); }, [q]);

  // scroll active into view
  useEffectCP(() => {
    if (!listRef.current) return;
    const el = listRef.current.querySelector(`[data-cp-idx="${active}"]`);
    if (el) {
      const rect = el.getBoundingClientRect();
      const wrap = listRef.current.getBoundingClientRect();
      if (rect.bottom > wrap.bottom) el.scrollIntoView({ block: "nearest" });
      if (rect.top < wrap.top) el.scrollIntoView({ block: "nearest" });
    }
  }, [active]);

  const choose = (item) => {
    if (!item || item.header) return;
    setRecent(prev => {
      const next = [item.id, ...prev.filter(id => id !== item.id)].slice(0, 6);
      localStorage.setItem("sc.cp.recent", JSON.stringify(next));
      return next;
    });
    onClose();
    setTimeout(() => item.action && item.action(), 60);
  };

  useEffectCP(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") { e.preventDefault(); onClose(); }
      else if (e.key === "ArrowDown") { e.preventDefault(); setActive(a => (a + 1) % flatItems.length); }
      else if (e.key === "ArrowUp") { e.preventDefault(); setActive(a => (a - 1 + flatItems.length) % flatItems.length); }
      else if (e.key === "Enter") { e.preventDefault(); choose(flatItems[active]); }
    };
    window.addEventListener("keydown", onKey, true);
    return () => window.removeEventListener("keydown", onKey, true);
  }, [open, flatItems, active]);

  if (!open) return null;

  let runningIdx = -1;
  return (
    <div className="cp-overlay" onMouseDown={(e) => { if (e.target.classList.contains("cp-overlay")) onClose(); }}>
      <div className="cp-modal" role="dialog" aria-label="Command palette">
        <div className="cp-header">
          <span className="cp-glyph"><IconSearch size={16} /></span>
          <input
            ref={inputRef}
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="Search saints, jump to a page, run an action…"
            className="cp-input"
          />
          <span className="cp-esc">esc</span>
        </div>
        <div className="cp-results" ref={listRef}>
          {results.length === 0 && (
            <div className="cp-empty">
              <Fleuron />
              <p>Begin typing to search the calendar.</p>
            </div>
          )}
          {results.map((item, i) => {
            if (item.header) {
              return <div key={`h-${i}`} className="cp-section">{item.header}</div>;
            }
            runningIdx++;
            const idx = runningIdx;
            return (
              <button
                key={item.id}
                data-cp-idx={idx}
                onMouseEnter={() => setActive(idx)}
                onMouseDown={(e) => { e.preventDefault(); choose(item); }}
                className={`cp-item ${active === idx ? "active" : ""}`}
              >
                <span className={`cp-item-glyph cp-kind-${item.kind}`}>{item.glyph}</span>
                <span className="cp-item-text">
                  <span className="cp-item-label">{item.label}</span>
                  {item.sub && <span className="cp-item-sub">{item.sub}</span>}
                </span>
                <span className={`cp-item-kind cp-kind-tag-${item.kind}`}>{item.kind}</span>
              </button>
            );
          })}
        </div>
        <div className="cp-footer">
          <span><span className="kbd">↑</span><span className="kbd">↓</span> navigate</span>
          <span><span className="kbd">↵</span> open</span>
          <span><span className="kbd">esc</span> close</span>
          <span style={{ marginLeft: "auto", color: "var(--ink-mute)" }}>Saints Calendar · global search</span>
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { CommandPalette });
