/* ============================================================
   Command Palette (Cmd+K / Ctrl+K)
   ------------------------------------------------------------
   A single overlay launched from anywhere in the dashboard.
   Fuzzy-search across students, batches, routes and quick
   actions; ↑/↓ to navigate, ↵ to execute, Esc to close.

   Builds its command list from window.Store + ctx so it stays
   in sync with the current user's role / store.
   ============================================================ */

(function () {

  function tokens(s) {
    return String(s || '').toLowerCase().match(/[a-z0-9]+/g) || [];
  }
  // Score how well needle matches an item's haystack. 0 = no match.
  function score(needle, haystack) {
    if (!needle) return 1;
    const n = needle.toLowerCase().trim();
    if (!n) return 1;
    const h = haystack.toLowerCase();
    if (h.includes(n)) return 10 + (h.startsWith(n) ? 5 : 0);
    // Multi-token: every token must appear.
    const ts = tokens(n);
    if (ts.length === 0) return 0;
    if (ts.every(t => h.includes(t))) return 3;
    return 0;
  }

  function navigateToStudent(ctx, sid) {
    const s = window.Store.getStudent(sid);
    const batchName = (s && s.profile && s.profile.batch) || '';
    sessionStorage.setItem('roster.batch', batchName);
    sessionStorage.setItem(`roster.focus.${batchName || '_unassigned'}`, sid);
    ctx.setRoute('roster');
  }
  function navigateToBatch(ctx, batchName) {
    sessionStorage.setItem('roster.batch', batchName);
    ctx.setRoute('roster');
  }

  function buildCommands(ctx) {
    const role = ctx.session.role;
    const cmds = [];

    // Quick navigation by role.
    const navByRole = {
      student: [
        ['Home', 'home'], ['Get started', 'onboarding'], ['Registration', 'registration'],
        ['Documents', 'documents'], ['Medical fitness', 'medical'],
        ['Progress & skill', 'tests'], ['Attendance', 'attendance'],
        ['Online Classes', 'online-classes'], ['Social media', 'social'],
        ['Announcements', 'announcements'], ['Final certificate', 'certificate'],
        ['Account', 'account'],
      ],
      instructor: [
        ['Cohort overview', 'overview'], ['Students', 'roster'],
        ['Verification queue', 'queue'], ['Test reports', 'tests-fill'],
        ['Mark attendance', 'attendance-mark'], ['Post notice', 'announcements-post'],
        ['Account', 'account'],
      ],
      manager: [
        ['Cohort overview', 'overview'], ['All students', 'roster'],
        ['Instructors', 'instructors'], ['Certificate issuance', 'issuance'],
        ['User management', 'users'], ['Activity log', 'audit'],
        ['Post notice', 'announcements-post'],
        ['Account', 'account'], ['Settings', 'settings'],
      ],
    };
    (navByRole[role] || []).forEach(([label, route]) => {
      cmds.push({
        id: `nav-${route}`,
        group: 'Go to',
        label,
        sub: `/ ${route}`,
        run: () => ctx.setRoute(route),
      });
    });

    // Students + batches — staff only.
    if (role === 'instructor' || role === 'manager') {
      const students = window.Store.listStudents();
      students.forEach(s => {
        const p = window.calcProgress(s) || {};
        cmds.push({
          id: `student-${s.id}`,
          group: 'Students',
          label: s.profile.fullName || '(unnamed student)',
          sub: `${s.profile.email || ''}${s.profile.rollNo ? ' · ' + s.profile.rollNo : ''}${s.profile.batch ? ' · ' + s.profile.batch : ' · Unassigned'} · ${p.overall || 0}%`,
          haystack: `${s.profile.fullName} ${s.profile.rollNo || ''} ${s.profile.email || ''} ${s.profile.batch || ''}`,
          run: () => navigateToStudent(ctx, s.id),
        });
      });
      const batches = ctx.store && ctx.store.batches ? Object.values(ctx.store.batches) : [];
      batches.forEach(b => {
        const roster = students.filter(s => (s.profile.batch || '') === b.name);
        cmds.push({
          id: `batch-${b.id}`,
          group: 'Batches',
          label: b.name,
          sub: `${b.course || 'Course not set'} · ${roster.length} student${roster.length===1?'':'s'}${b.archived ? ' · archived' : ''}`,
          haystack: `batch ${b.name} ${b.course || ''}`,
          run: () => navigateToBatch(ctx, b.name),
        });
      });
      // Pseudo-batch
      cmds.push({
        id: 'batch-unassigned',
        group: 'Batches',
        label: 'Unassigned',
        sub: 'Students not yet in a batch',
        haystack: 'batch unassigned',
        run: () => navigateToBatch(ctx, ''),
      });
    }

    // Quick actions
    cmds.push({
      id: 'sign-out', group: 'Account', label: 'Sign out',
      sub: ctx.session.email, run: () => window.Auth.signOut(),
    });

    return cmds;
  }

  function CommandPalette({ ctx, isOpen, onClose }) {
    const [q, setQ] = useState('');
    const [activeIdx, setActiveIdx] = useState(0);
    const listRef = useRef(null);

    const allCommands = useMemo(() => isOpen ? buildCommands(ctx) : [],
      [isOpen, ctx.session.role, ctx.session.uid, ctx.store.students, ctx.store.batches, ctx.store.users]);

    const results = useMemo(() => {
      if (!isOpen) return [];
      const ranked = allCommands.map(c => {
        const hay = c.haystack || `${c.label} ${c.sub || ''}`;
        return { c, s: score(q, hay) };
      }).filter(x => x.s > 0);
      ranked.sort((a, b) => b.s - a.s);
      return ranked.slice(0, 50).map(x => x.c);
    }, [allCommands, q, isOpen]);

    useEffect(() => {
      if (!isOpen) { setQ(''); setActiveIdx(0); }
    }, [isOpen]);

    useEffect(() => { setActiveIdx(0); }, [q]);

    useEffect(() => {
      if (!isOpen) return undefined;
      const onKey = (e) => {
        if (e.key === 'Escape') { e.preventDefault(); onClose(); }
        else if (e.key === 'ArrowDown') {
          e.preventDefault();
          setActiveIdx(i => Math.min(i + 1, Math.max(0, results.length - 1)));
        } else if (e.key === 'ArrowUp') {
          e.preventDefault();
          setActiveIdx(i => Math.max(i - 1, 0));
        } else if (e.key === 'Enter') {
          e.preventDefault();
          const r = results[activeIdx];
          if (r) { r.run(); onClose(); }
        }
      };
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, [isOpen, results, activeIdx, onClose]);

    // Auto-scroll the active item into view.
    useEffect(() => {
      const el = listRef.current?.querySelector('[data-cmdk-active="1"]');
      if (el) el.scrollIntoView({ block: 'nearest' });
    }, [activeIdx, results]);

    if (!isOpen) return null;

    // Group results by their group attribute, preserving rank order.
    const grouped = [];
    let lastGroup = null;
    results.forEach((c, i) => {
      if (c.group !== lastGroup) {
        grouped.push({ kind: 'header', label: c.group });
        lastGroup = c.group;
      }
      grouped.push({ kind: 'item', c, i });
    });

    return ReactDOM.createPortal(
      <div className="cmdk-backdrop" onClick={onClose}>
        <div className="cmdk-panel" onClick={e=>e.stopPropagation()}>
          <div className="cmdk-search">
            <span style={{color:'var(--muted)'}}>⌘K</span>
            <input autoFocus type="text" placeholder="Search students, batches, modules…"
              value={q} onChange={e=>setQ(e.target.value)}/>
            <button className="btn btn-xs" onClick={onClose}>Esc</button>
          </div>
          <div className="cmdk-list" ref={listRef}>
            {results.length === 0 && (
              <div className="cmdk-empty">No matches{q ? ` for “${q}”` : ''}.</div>
            )}
            {grouped.map((g, k) => g.kind === 'header'
              ? <div key={'h'+k} className="cmdk-group">{g.label}</div>
              : (
                  <button key={g.c.id}
                    data-cmdk-active={g.i === activeIdx ? '1' : '0'}
                    className={cls('cmdk-row', g.i === activeIdx && 'active')}
                    onMouseEnter={()=>setActiveIdx(g.i)}
                    onClick={()=>{ g.c.run(); onClose(); }}>
                    <div className="cmdk-row-main">
                      <div className="cmdk-row-label">{g.c.label}</div>
                      {g.c.sub && <div className="cmdk-row-sub">{g.c.sub}</div>}
                    </div>
                    {g.i === activeIdx && <span className="cmdk-enter">↵</span>}
                  </button>
                )
            )}
          </div>
          <div className="cmdk-foot">
            <span>↑ ↓ navigate · ↵ open · Esc close</span>
          </div>
        </div>
      </div>,
      document.body);
  }

  window.CommandPalette = CommandPalette;
})();
