/* ═══════════════════════════════════════════════════════════════
   Command palette — Ctrl/Cmd+K cross-project quick-jump.
   Searches projects and tasks via /api/search; navigation by
   keyboard, mouse, or Enter on the highlighted result.
═══════════════════════════════════════════════════════════════ */

(function () {
    'use strict';

    const overlay = document.getElementById('cmdkOverlay');
    const input   = document.getElementById('cmdkInput');
    const list    = document.getElementById('cmdkResults');
    if (!overlay || !input || !list) return;

    const base   = typeof BASE_URL   !== 'undefined' ? BASE_URL   : '';
    const csrf   = () => typeof CSRF_TOKEN !== 'undefined' ? CSRF_TOKEN : '';
    const labels = typeof CMDK_LABELS !== 'undefined' ? CMDK_LABELS : { projects: 'Projects', tasks: 'Tasks', people: 'People', external: 'External', openTasks: 'open', empty: 'No results', typeMore: 'Type at least 2 characters…' };

    let items   = []; // flat list of {url, title, subtitle, dotColor, kind}
    let active  = -1;
    let abortCtrl = null;
    let debounce  = null;
    let reqSeq    = 0;

    function open() {
        overlay.style.display = 'flex';
        input.value = '';
        renderHint();
        // Defer focus; some browsers race the display change with autofocus.
        setTimeout(() => input.focus(), 10);
    }
    function close() {
        overlay.style.display = 'none';
        if (abortCtrl) abortCtrl.abort();
        items = [];
        active = -1;
    }

    function isOpen() { return overlay.style.display !== 'none'; }

    function el(tag, attrs, children) {
        const e = document.createElement(tag);
        if (attrs) for (const [k, v] of Object.entries(attrs)) {
            if (v == null || v === false) continue;
            if (k === 'class') e.className = v;
            else e.setAttribute(k, v);
        }
        if (children) for (const c of children) {
            if (c == null) continue;
            e.appendChild(typeof c === 'string' ? document.createTextNode(c) : c);
        }
        return e;
    }

    function renderHint() {
        list.replaceChildren(el('div', { class: 'cmdk-empty' }, [labels.typeMore]));
        items = [];
        active = -1;
    }

    function renderEmpty() {
        list.replaceChildren(el('div', { class: 'cmdk-empty' }, [labels.empty]));
        items = [];
        active = -1;
    }

    function renderResults(data) {
        list.replaceChildren();
        items = [];

        const projects = (data.projects || []);
        const tasks    = (data.tasks    || []);
        const people   = (data.people   || []);
        if (projects.length === 0 && tasks.length === 0 && people.length === 0) { renderEmpty(); return; }

        if (projects.length) {
            list.appendChild(el('div', { class: 'cmdk-section' }, [labels.projects]));
            projects.forEach(p => {
                const dot   = el('span', { class: 'cmdk-dot', style: 'background:' + (p.color || '#888') });
                const title = el('span', { class: 'cmdk-item-title' });
                title.textContent = String(p.name || '');
                const node  = el('a', { class: 'cmdk-item', href: base + '/project/' + parseInt(p.id) }, [dot, title]);
                list.appendChild(node);
                items.push(node);
            });
        }
        if (tasks.length) {
            list.appendChild(el('div', { class: 'cmdk-section' }, [labels.tasks]));
            tasks.forEach(t => {
                const dot   = el('span', { class: 'cmdk-dot', style: 'background:' + (t.project_color || '#888') });
                const title = el('span', { class: 'cmdk-item-title' });
                title.textContent = String(t.title || '');
                const sub   = el('span', { class: 'cmdk-item-sub' });
                sub.textContent = String(t.project_name || '');
                const node  = el('a', { class: 'cmdk-item', href: base + '/task/' + parseInt(t.id) }, [dot, title, sub]);
                list.appendChild(node);
                items.push(node);
            });
        }
        if (people.length) {
            list.appendChild(el('div', { class: 'cmdk-section' }, [labels.people]));
            people.forEach(p => {
                const isExt = p.kind === 'external';
                // Click navigates to the regular Tasks page with the assigned-to
                // filter pre-selected, so the user lands in the same view as if
                // they had typed the person into the filter picker themselves.
                const token = (isExt ? 'e_' : 'u_') + parseInt(p.id);
                const url   = base + '/my-tasks?assigned_to=' + encodeURIComponent(token) + '&status=open';
                // Avatar slot: a circle with initials. We do not load remote avatars
                // to keep the palette responsive and reduce IO during typing.
                const initial = (p.name || '?').slice(0, 1).toUpperCase();
                const avatar = el('span', { class: 'cmdk-avatar' + (isExt ? ' cmdk-avatar--ext' : '') });
                avatar.textContent = initial;
                const title = el('span', { class: 'cmdk-item-title' });
                title.textContent = String(p.name || '');
                const sub   = el('span', { class: 'cmdk-item-sub' });
                if (isExt) {
                    sub.textContent = labels.external + (p.subtitle ? ' · ' + p.subtitle : '');
                } else {
                    sub.textContent = String(p.subtitle || '');
                }
                const counter = el('span', { class: 'cmdk-counter' });
                counter.textContent = String(p.open_count || 0) + ' ' + labels.openTasks;
                const node = el('a', { class: 'cmdk-item', href: url }, [avatar, title, sub, counter]);
                list.appendChild(node);
                items.push(node);
            });
        }

        setActive(0);
    }

    function setActive(idx) {
        if (items.length === 0) { active = -1; return; }
        if (idx < 0) idx = 0;
        if (idx >= items.length) idx = items.length - 1;
        items.forEach((n, i) => n.classList.toggle('active', i === idx));
        active = idx;
        items[idx].scrollIntoView({ block: 'nearest' });
    }

    async function search(q) {
        if (q.length < 2) { renderHint(); return; }
        if (abortCtrl) abortCtrl.abort();
        abortCtrl = new AbortController();
        const seq = ++reqSeq;
        try {
            const res = await fetch(base + '/api/search', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ q: q, csrf_token: csrf() }),
                signal: abortCtrl.signal,
            });
            if (!res.ok) { renderEmpty(); return; }
            const data = await res.json();
            if (seq !== reqSeq) return; // stale
            renderResults(data.results || {});
        } catch (e) {
            if (e.name !== 'AbortError') renderEmpty();
        }
    }

    function schedule() {
        clearTimeout(debounce);
        const q = input.value.trim();
        debounce = setTimeout(() => search(q), 180);
    }

    // Open on Ctrl/Cmd+K from anywhere except inside an input/textarea/contenteditable.
    document.addEventListener('keydown', e => {
        const inField = e.target && (
            e.target.tagName === 'INPUT' ||
            e.target.tagName === 'TEXTAREA' ||
            e.target.isContentEditable
        );
        // Allow shortcut even from fields — power users expect that.
        if ((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'K')) {
            e.preventDefault();
            isOpen() ? close() : open();
            return;
        }
        if (!isOpen()) return;
        if (e.key === 'Escape') { e.preventDefault(); close(); }
        else if (e.key === 'ArrowDown') { e.preventDefault(); setActive(active + 1); }
        else if (e.key === 'ArrowUp')   { e.preventDefault(); setActive(active - 1); }
        else if (e.key === 'Enter') {
            if (items[active]) { e.preventDefault(); items[active].click(); }
        }
    });

    overlay.addEventListener('click', e => { if (e.target === overlay) close(); });
    input.addEventListener('input', schedule);
    list.addEventListener('mouseover', e => {
        const item = e.target.closest('.cmdk-item');
        if (!item) return;
        const idx = items.indexOf(item);
        if (idx >= 0) setActive(idx);
    });

    // Programmatic open for the topbar search affordance.
    window.openCmdK = () => { isOpen() ? close() : open(); };

    // Mac users see ⌘ instead of Ctrl in the topbar kbd hint.
    const isMac = /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent || '');
    if (isMac) {
        document.querySelectorAll('.topbar-search-kbd .kbd-mod').forEach(el => { el.textContent = '⌘'; });
    }
})();
