const GlobalSearch = ({ onClose, onSelectAccount }) => {
    const [q, setQ]           = React.useState('');
    const [results, setResults] = React.useState(null);
    const [loading, setLoading] = React.useState(false);
    const [active, setActive]   = React.useState(0);   // index into the flat result list
    const inputRef = React.useRef(null);

    // One ordered list across every section — the keyboard's view of the
    // results. Derived from `results` (not collected during child render, which
    // proved order-fragile) so index N here is row N on screen.
    const SECTIONS = [
        { key: 'accounts',       icon: 'fas fa-building', label: 'Accounts',       cls: 'account',
          renderSub: i => [i.customer_number, i.type, i.main_email, i.main_phone].filter(Boolean).join(' · '),
          onPick: i => onSelectAccount(i) },
        { key: 'contacts',       icon: 'fas fa-user',     label: 'Contacts',       cls: 'contact',
          renderSub: i => [i.title, i.account_name].filter(Boolean).join(' · '),
          onPick: i => onSelectAccount({ id: i.account_id }) },
        { key: 'tasks',          icon: 'fas fa-tasks',    label: 'Tasks',          cls: 'task',
          renderSub: i => [i.account_name, i.due_date ? formatDate(i.due_date) : null].filter(Boolean).join(' · '),
          onPick: i => onSelectAccount({ id: i.account_id }) },
        { key: 'communications', icon: 'fas fa-comment',  label: 'Communications', cls: 'comm',
          renderSub: i => [i.account_name, i.type, formatDate(i.timestamp)].filter(Boolean).join(' · '),
          onPick: i => onSelectAccount({ id: i.account_id }) },
    ];
    const flat = React.useMemo(() => results
        ? SECTIONS.flatMap(sec => (results[sec.key] || []).map(item => ({ item, onPick: sec.onPick })))
        : [], [results]);

    React.useEffect(() => { inputRef.current?.focus(); }, []);

    React.useEffect(() => {
        // Mounted only while search is open, so the handler needs no open-state guard.
        // Arrow/Enter handled here rather than useListNav: focus stays in the
        // input, whose typing guard would swallow the keys.
        const handler = (e) => {
            if (e.key === 'Escape') return onClose();
            const n = flat.length;
            if (!n) return;
            if (e.key === 'ArrowDown')      { e.preventDefault(); setActive(i => (i + 1) % n); }
            else if (e.key === 'ArrowUp')   { e.preventDefault(); setActive(i => (i - 1 + n) % n); }
            else if (e.key === 'Enter')     { e.preventDefault(); const r = flat[active]; if (r) { r.onPick(r.item); onClose(); } }
        };
        document.addEventListener('keydown', handler);
        return () => document.removeEventListener('keydown', handler);
    }, [active, flat]);

    React.useEffect(() => { setActive(0); }, [results]);   // new results → cursor back to the top
    React.useEffect(() => { document.querySelector('.search-result-item.is-active')?.scrollIntoView({ block: 'nearest' }); }, [active]);

    React.useEffect(() => {
        if (q.trim().length < 2) { setResults(null); return; }
        // stale flag: a fetch in flight when the palette closes (or q changes)
        // must not setState on the way out.
        let stale = false;
        const t = setTimeout(async () => {
            setLoading(true);
            try { const r = await api.search(q); if (!stale) setResults(r); }
            catch(e) { /* transient search failure — palette just shows no results */ }
            finally { if (!stale) setLoading(false); }
        }, 280);
        return () => { stale = true; clearTimeout(t); };
    }, [q]);

    const total = flat.length;

    const Section = ({ icon, label, items, cls, renderSub, onPick, offset }) => {
        if (!items?.length) return null;
        return (
            <div className="search-section">
                <div className="search-section-title"><i className={icon} style={{ marginRight: '0.375rem' }}></i>{label}</div>
                {items.map((item, j) => {
                    const idx = offset + j;
                    return (
                    <div key={item.id} className={`search-result-item${idx === active ? ' is-active' : ''}`}
                         onMouseEnter={() => setActive(idx)} onClick={() => { onPick(item); onClose(); }}>
                        <div className={`search-result-icon ${cls}`}><i className={icon}></i></div>
                        <div className="search-result-main">
                            {/* join+filter so a nameless row falls through — a template literal would stringify undefined and shadow title/subject */}
                            <div className="search-result-name">{item.name || [item.first_name, item.last_name].filter(Boolean).join(' ') || item.title || item.subject || '(no subject)'}</div>
                            <div className="search-result-sub">{renderSub(item)}</div>
                        </div>
                    </div>
                    );
                })}
            </div>
        );
    };

    return (
        <div className="search-overlay" onClick={(e) => e.target === e.currentTarget && onClose()}>
            <div className="search-overlay-box">
                <div className="search-overlay-input-row">
                    <i className="fas fa-search"></i>
                    <input ref={inputRef} className="search-overlay-input" placeholder="Search accounts, contacts, tasks, communications…" value={q} onChange={e => setQ(e.target.value)} />
                    {loading && <i className="fas fa-spinner fa-spin" style={{ color: 'var(--text-3)' }}></i>}
                    <button style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-3)', fontSize: '1.1rem' }} onClick={onClose}><i className="fas fa-times"></i></button>
                </div>
                <div className="search-results">
                    {results && total === 0 && <div className="search-empty">No results for "{q}"</div>}
                    {results && SECTIONS.map((sec, k) => (
                        <Section key={sec.key} {...sec} items={results[sec.key]}
                            offset={SECTIONS.slice(0, k).reduce((n, x) => n + (results[x.key] || []).length, 0)} />
                    ))}
                    {!results && q.length < 2 && (
                        <div className="search-empty" style={{ color: 'var(--text-3)' }}>Type at least 2 characters to search</div>
                    )}
                </div>
            </div>
        </div>
    );
};
