/* global React, window */
// Command palette — Cmd+K (Mac) / Ctrl+K (Win/Linux) opens a centered modal
// with a single input. Search routes to one of three result groups:
//
//   OPEN     — navigation actions (open a KPI drill-in, jump to a team page)
//   INSIGHTS — curated insights from window.YUNO_CASCADE_DATA.insights
//              (sourced from the spreadsheet's `Insights` tab; empty until
//              owners fill it in, palette degrades gracefully)
//   GO TO    — period switches, page switches, region filters
//
// All actions dispatch a CustomEvent('yuno-palette-action', { detail: {...} })
// on window. Consumers (App, OverviewSection, TeamsSection) listen and route
// the action to the appropriate state setter — avoids the palette having to
// know about React state internals.
//
// Index sources:
//   - window.YUNO_MARCH_2026.STRATEGIC + HEADLINES → KPI names + ids
//   - window.YUNO_CASCADE_DATA.kpis → cascade-only KPIs (e.g. unmapped bug sub-cats)
//   - window.YUNO_DATA.TEAM_CLUSTERS → team navigation
//   - hardcoded: 12 months, 4 quarters, exec overview + teams pages
//
// Re-index runs on each open (cheap; <500 items). Globals can change as
// cascade-data.js refreshes — no stale index.

(function () {
  const { useState, useEffect, useRef, useMemo } = React;

  // ----- Index construction ------------------------------------------------

  const REGIONS = ['LATAM', 'EUROPE', 'APAC', 'NA', 'MENA'];
  const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  const MONTH_FULL = { Jan: 'January', Feb: 'February', Mar: 'March', Apr: 'April', May: 'May',
                       Jun: 'June', Jul: 'July', Aug: 'August', Sep: 'September',
                       Oct: 'October', Nov: 'November', Dec: 'December' };
  const QUARTERS = ['Q1', 'Q2', 'Q3', 'Q4'];

  function buildIndex() {
    const M = window.YUNO_MARCH_2026 || {};
    const D = window.YUNO_DATA || {};
    const cascade = window.YUNO_CASCADE_DATA || {};
    const items = [];

    // KPIs from march-data (strategic + headlines) — these have a drill-in path.
    const seen = new Set();
    const addKpi = (k, sourceLabel) => {
      if (!k || !k.id || seen.has(k.id)) return;
      seen.add(k.id);
      items.push({
        kind: 'kpi',
        id: k.id,
        title: k.name,
        subtitle: [k.pillar, k.team].filter(Boolean).join(' · '),
        searchText: `${k.name} ${k.id} ${k.pillar || ''} ${k.team || ''}`.toLowerCase(),
        action: { type: 'open-kpi', kpiId: k.id, pillar: k.pillar, team: k.team },
        group: 'OPEN',
      });
    };
    (M.STRATEGIC || []).forEach(k => addKpi(k, 'strategic'));
    Object.values(M.HEADLINES || {}).forEach(arr => (arr || []).forEach(k => addKpi(k, 'headline')));

    // Cascade-only KPIs (no drill-in yet, but searchable for visibility).
    (cascade.kpis || []).forEach(k => {
      if (!k.name) return;
      const id = (k.name || '').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');
      if (seen.has(id)) return;
      seen.add(id);
      items.push({
        kind: 'kpi-cascade',
        id,
        title: k.name,
        subtitle: [k.pillar, k.team].filter(Boolean).join(' · '),
        searchText: `${k.name} ${k.pillar || ''} ${k.team || ''}`.toLowerCase(),
        action: { type: 'open-kpi-cascade', kpiName: k.name, pillar: k.pillar, team: k.team },
        group: 'OPEN',
      });
    });

    // Teams.
    (D.TEAM_CLUSTERS || []).forEach(cluster => {
      if (cluster.id === 'all') return;
      const addTeam = (node, parent) => {
        items.push({
          kind: 'team',
          id: node.id,
          title: parent ? `${parent.label} · ${node.label}` : node.label,
          subtitle: 'Team',
          searchText: `${node.label} ${parent ? parent.label : ''}`.toLowerCase(),
          action: { type: 'navigate-team', teamId: node.id },
          group: 'GO TO',
        });
      };
      addTeam(cluster, null);
      (cluster.children || []).forEach(child => addTeam(child, cluster));
    });

    // Periods.
    MONTHS.forEach(m => items.push({
      kind: 'month',
      id: `month-${m}`,
      title: `Switch period to ${MONTH_FULL[m]}`,
      subtitle: 'Period',
      // Index both short and full forms so "april" and "apr" both match.
      searchText: `${m} ${MONTH_FULL[m]} period month`.toLowerCase(),
      action: { type: 'switch-period', month: m },
      group: 'GO TO',
    }));
    QUARTERS.forEach(q => items.push({
      kind: 'quarter',
      id: `quarter-${q}`,
      title: `Switch period to ${q}`,
      subtitle: 'Period',
      searchText: q.toLowerCase(),
      action: { type: 'switch-period', quarter: q },
      group: 'GO TO',
    }));

    // Pages.
    items.push({
      kind: 'page',
      id: 'page-overview',
      title: 'Executive Overview',
      subtitle: 'Page',
      searchText: 'executive overview home dashboard',
      action: { type: 'navigate-page', page: 'overview' },
      group: 'GO TO',
    });
    items.push({
      kind: 'page',
      id: 'page-teams',
      title: 'Teams',
      subtitle: 'Page',
      searchText: 'teams team picker',
      action: { type: 'navigate-page', page: 'teams' },
      group: 'GO TO',
    });

    // Insights (curated from spreadsheet's `Insights` tab via cascade.insights).
    // Each insight has { scope: 'pillar'|'kpi', identifier: 'P1'|'new_logo_arr', type: 'driving', text: '...' }
    const insights = cascade.insights || {};
    const byPillar = insights.byPillar || {};
    const byKpi = insights.byKpi || {};
    Object.entries(byPillar).forEach(([pillarTag, list]) => {
      (list || []).forEach((ins, i) => items.push({
        kind: 'insight',
        id: `insight-pillar-${pillarTag}-${i}`,
        title: `${pillarTag}: ${ins.text}`,
        subtitle: `Pillar insight · ${ins.type || 'note'}`,
        searchText: `${pillarTag} ${ins.type || ''} ${ins.text || ''}`.toLowerCase(),
        action: { type: 'show-insight', scope: 'pillar', identifier: pillarTag, text: ins.text, insightType: ins.type },
        group: 'INSIGHTS',
      }));
    });
    Object.entries(byKpi).forEach(([kpiId, list]) => {
      (list || []).forEach((ins, i) => {
        // Find KPI name for the label so the title reads naturally.
        const kpi = (M.STRATEGIC || []).find(k => k.id === kpiId)
                 || Object.values(M.HEADLINES || {}).flat().find(k => k.id === kpiId);
        const kpiName = kpi ? kpi.name : kpiId;
        items.push({
          kind: 'insight',
          id: `insight-kpi-${kpiId}-${i}`,
          title: `${kpiName}: ${ins.text}`,
          subtitle: `KPI insight · ${ins.type || 'note'}`,
          searchText: `${kpiName} ${kpiId} ${ins.type || ''} ${ins.text || ''}`.toLowerCase(),
          action: { type: 'show-insight', scope: 'kpi', identifier: kpiId, kpiName, text: ins.text, insightType: ins.type },
          group: 'INSIGHTS',
        });
      });
    });

    return items;
  }

  // ----- Scoring -----------------------------------------------------------
  // Heuristic: exact > prefix > word-prefix > substring > fuzzy. Insight queries
  // (containing keywords like "why", "driving", "watch", "risk") get a boost
  // toward INSIGHTS group results.

  const INSIGHT_KEYWORDS = ['why', 'driving', 'watch', 'risk', 'explain', 'reason', 'cause', 'context'];

  function scoreItem(item, q) {
    if (!q) return 0;
    const text = item.searchText;
    const title = item.title.toLowerCase();
    if (!text || !title) return 0;
    let score = 0;
    if (title === q) score += 1000;
    else if (title.startsWith(q)) score += 500;
    else if (text.startsWith(q)) score += 400;
    // Word-prefix: any token in searchText starts with q
    const tokens = text.split(/\s+/);
    if (tokens.some(t => t.startsWith(q))) score += 300;
    if (text.includes(q)) score += 100;
    // Insight-keyword boost
    if (item.group === 'INSIGHTS' && INSIGHT_KEYWORDS.some(kw => q.includes(kw))) score += 250;
    // Multi-word query: each word matched adds a small bonus. If ALL query
    // tokens match (and there's more than one), boost — covers "eng core"
    // surfacing the team over individual KPIs.
    const qWords = q.split(/\s+/).filter(Boolean);
    if (qWords.length > 1) {
      let matched = 0;
      qWords.forEach(w => { if (text.includes(w)) { score += 30; matched++; } });
      if (matched === qWords.length) score += 200;  // all tokens present
    }
    // Team-type results get a small boost when the query looks team-y
    // (avoids KPI noise drowning out the actual team page).
    if (item.kind === 'team' && qWords.length > 1) score += 100;
    return score;
  }

  // ----- UI ---------------------------------------------------------------

  function CommandPalette() {
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');
    const [selectedIdx, setSelectedIdx] = useState(0);
    const inputRef = useRef(null);
    const listRef = useRef(null);
    // Seeded query for when the palette is opened via a `yuno-palette-toggle`
    // event with `{ detail: { query: 'foo' } }` — e.g. the hero search chips.
    // The on-open useEffect normally resets the query to ''; this ref lets us
    // override that reset with the seeded value for one open.
    const seedRef = useRef('');

    // Build index lazily — once per open. Re-runs if globals change between opens.
    const index = useMemo(() => (open ? buildIndex() : []), [open]);

    // Score + group results.
    const results = useMemo(() => {
      if (!open) return [];
      const q = query.trim().toLowerCase();
      const scored = q
        ? index.map(item => ({ item, score: scoreItem(item, q) })).filter(r => r.score > 0).sort((a, b) => b.score - a.score)
        : index.slice(0, 0); // empty query → empty (shows suggestions block below)
      // Cap at 30 results, group preserving rank order
      return scored.slice(0, 30).map(r => r.item);
    }, [open, query, index]);

    const grouped = useMemo(() => {
      const order = ['OPEN', 'INSIGHTS', 'GO TO'];
      const groups = {};
      results.forEach(item => {
        if (!groups[item.group]) groups[item.group] = [];
        groups[item.group].push(item);
      });
      return order.filter(g => groups[g] && groups[g].length).map(g => ({ name: g, items: groups[g] }));
    }, [results]);

    // Flat list for keyboard navigation, preserves group order.
    const flat = useMemo(() => grouped.flatMap(g => g.items), [grouped]);

    // ----- Keyboard shortcut + lifecycle -----
    useEffect(() => {
      function onKey(e) {
        const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
        if ((isMac ? e.metaKey : e.ctrlKey) && e.key.toLowerCase() === 'k') {
          e.preventDefault();
          setOpen(prev => !prev);
        }
      }
      function onToggle(e) {
        // Allow the caller to seed an initial query (used by HeroSearch chips
        // to land in the palette with a pre-typed question).
        seedRef.current = (e && e.detail && typeof e.detail.query === 'string') ? e.detail.query : '';
        setOpen(prev => !prev);
      }
      window.addEventListener('keydown', onKey);
      window.addEventListener('yuno-palette-toggle', onToggle);
      return () => {
        window.removeEventListener('keydown', onKey);
        window.removeEventListener('yuno-palette-toggle', onToggle);
      };
    }, []);

    useEffect(() => {
      if (open) {
        // If a seed was set on this toggle, honor it; otherwise reset to ''.
        // Clear the seed after consuming so the next open starts fresh.
        setQuery(seedRef.current || '');
        seedRef.current = '';
        setSelectedIdx(0);
        // Autofocus
        setTimeout(() => inputRef.current && inputRef.current.focus(), 30);
      }
    }, [open]);

    // Reset selection when results change.
    useEffect(() => { setSelectedIdx(0); }, [query]);

    // Scroll selected row into view.
    useEffect(() => {
      if (!listRef.current) return;
      const sel = listRef.current.querySelector(`[data-pal-idx="${selectedIdx}"]`);
      if (sel && sel.scrollIntoView) sel.scrollIntoView({ block: 'nearest' });
    }, [selectedIdx]);

    function dispatch(action) {
      window.dispatchEvent(new CustomEvent('yuno-palette-action', { detail: action }));
      setOpen(false);
    }

    function onKeyDown(e) {
      if (e.key === 'Escape') { e.preventDefault(); setOpen(false); return; }
      if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIdx(i => Math.min(flat.length - 1, i + 1)); return; }
      if (e.key === 'ArrowUp')   { e.preventDefault(); setSelectedIdx(i => Math.max(0, i - 1)); return; }
      if (e.key === 'Enter') {
        e.preventDefault();
        const item = flat[selectedIdx];
        if (item) dispatch(item.action);
      }
    }

    if (!open) {
      // Render only the keyboard listener attachment + trigger button is rendered
      // by the top bar separately (see CommandPaletteTrigger below).
      return null;
    }

    // ----- Modal markup ---------------------------------------------------
    return (
      <div
        onClick={(e) => { if (e.target === e.currentTarget) setOpen(false); }}
        style={{
          position: 'fixed', inset: 0, zIndex: 10000,
          background: 'rgba(15, 23, 42, 0.45)', backdropFilter: 'blur(4px)',
          display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
          paddingTop: '15vh', paddingLeft: 16, paddingRight: 16,
        }}>
        <div style={{
          width: '100%', maxWidth: 640, maxHeight: '70vh',
          background: '#FFFFFF', borderRadius: 12,
          boxShadow: '0 25px 60px rgba(15, 23, 42, 0.35)',
          display: 'flex', flexDirection: 'column', overflow: 'hidden',
          fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
        }}>
          {/* Input */}
          <div style={{ display: 'flex', alignItems: 'center', padding: '14px 18px', borderBottom: '1px solid #E2E8F0' }}>
            <span style={{ marginRight: 12, color: '#64748B', fontSize: 16 }}>🔍</span>
            <input
              ref={inputRef}
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              onKeyDown={onKeyDown}
              placeholder="Search KPIs, teams, insights… (try 'arr', 'eng core', or 'why is arr missing')"
              style={{
                flex: 1, border: 'none', outline: 'none', fontSize: 15, color: '#0F172A',
                background: 'transparent', fontFamily: 'inherit',
              }}
            />
          </div>

          {/* Results */}
          <div ref={listRef} style={{ overflow: 'auto', flex: 1 }}>
            {flat.length === 0 && query.trim() && (
              <div style={{ padding: '24px 18px', color: '#94A3B8', fontSize: 13, textAlign: 'center' }}>
                No matches. Try a KPI name, team, or "why is &lt;kpi&gt; missing".
              </div>
            )}
            {flat.length === 0 && !query.trim() && (
              <div style={{ padding: '18px 18px', color: '#64748B', fontSize: 13 }}>
                <div style={{ marginBottom: 10, fontSize: 11, fontWeight: 700, color: '#94A3B8', letterSpacing: '0.06em' }}>SUGGESTIONS</div>
                <div style={{ lineHeight: 1.7 }}>
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>arr</code>
                  &nbsp;or&nbsp;
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>new logo arr latam</code>
                  &nbsp;to open a KPI.
                  <br/>
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>finance</code>
                  &nbsp;or&nbsp;
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>eng core</code>
                  &nbsp;to jump to a team.
                  <br/>
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>april</code>
                  &nbsp;to switch period.
                  <br/>
                  <code style={{ background: '#F1F5F9', padding: '2px 6px', borderRadius: 4 }}>why is arr missing</code>
                  &nbsp;to see curated insights.
                </div>
              </div>
            )}
            {grouped.map((group, gi) => {
              // Walking idx into flat list — preserves keyboard nav
              let runningIdx = 0;
              for (let i = 0; i < gi; i++) runningIdx += grouped[i].items.length;
              return (
                <div key={group.name}>
                  <div style={{
                    padding: '10px 18px 4px', fontSize: 10, fontWeight: 700,
                    color: '#94A3B8', letterSpacing: '0.08em',
                  }}>
                    {group.name}
                  </div>
                  {group.items.map((item, i) => {
                    const flatIdx = runningIdx + i;
                    const isSelected = flatIdx === selectedIdx;
                    return (
                      <div
                        key={item.id}
                        data-pal-idx={flatIdx}
                        onMouseEnter={() => setSelectedIdx(flatIdx)}
                        onClick={() => dispatch(item.action)}
                        style={{
                          padding: '8px 18px',
                          background: isSelected ? '#EEF2FF' : 'transparent',
                          cursor: 'pointer',
                          borderLeft: isSelected ? '3px solid #3E4FE0' : '3px solid transparent',
                        }}>
                        <div style={{ fontSize: 14, color: '#0F172A', fontWeight: 500 }}>{item.title}</div>
                        {item.subtitle && (
                          <div style={{ fontSize: 11, color: '#94A3B8', marginTop: 1, letterSpacing: '0.02em' }}>
                            {item.subtitle}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              );
            })}
          </div>

          {/* Footer */}
          <div style={{
            padding: '8px 18px', borderTop: '1px solid #E2E8F0',
            fontSize: 11, color: '#94A3B8', display: 'flex', gap: 16,
            background: '#F8FAFC',
          }}>
            <span><kbd style={kbdStyle}>↑↓</kbd> navigate</span>
            <span><kbd style={kbdStyle}>↵</kbd> select</span>
            <span><kbd style={kbdStyle}>esc</kbd> close</span>
            <span style={{ marginLeft: 'auto' }}>{flat.length} {flat.length === 1 ? 'result' : 'results'}</span>
          </div>
        </div>
      </div>
    );
  }

  const kbdStyle = {
    background: '#FFFFFF', border: '1px solid #E2E8F0',
    borderRadius: 4, padding: '1px 5px', fontFamily: 'inherit',
    fontSize: 10, color: '#64748B',
  };

  // ----- Trigger button (mounted in top bar by App) ------------------------

  function CommandPaletteTrigger() {
    const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
    return (
      <button
        onClick={() => window.dispatchEvent(new CustomEvent('yuno-palette-toggle'))}
        title={`Search (${isMac ? '⌘' : 'Ctrl+'}K)`}
        style={{
          display: 'inline-flex', alignItems: 'center', gap: 8,
          padding: '6px 12px', border: '1px solid #E2E8F0', borderRadius: 8,
          background: '#FFFFFF', cursor: 'pointer', fontSize: 13,
          color: '#64748B', minWidth: 180, justifyContent: 'flex-start',
          fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
        }}>
        <span>🔍</span>
        <span>Search…</span>
        <span style={{ marginLeft: 'auto', fontSize: 11, color: '#94A3B8' }}>
          {isMac ? '⌘K' : 'Ctrl+K'}
        </span>
      </button>
    );
  }

  window.YUNO_PALETTE = { CommandPalette, CommandPaletteTrigger };
})();
