/**
 * AutolinkChipPreview — Smart-quote Chip B + nested-recursion Chip C.
 *
 * Click an autolink chip → popover with title/status/desc/last-2 comments and
 * a 📌 requote button. Embedded refs inside the popover content (a card whose
 * description mentions another card_/src:// token) re-render as nested chips;
 * clicking one stacks a child popover on top, up to MAX_DEPTH layers.
 *
 * Cycle guard: clicking a chip whose refId is already on the open stack shows
 * a transient toast "已在引用堆疊上". Depth guard: stack at MAX_DEPTH shows
 * "太深，請直接跳頁".
 *
 * ESC / outside-click closes the entire stack.
 *
 * Supported ref types (Phase 1):
 *   - src://kanban/card/<id>  → GET /api/mission/card/:id
 */
(function (global) {
    'use strict';

    const MAX_DEPTH = 5;
    let stack = []; // pop elements; stack[0] = root, last = innermost
    let rootAnchor = null;

    function t(key, fallback) {
        try { return (global.i18n && typeof global.i18n.t === 'function') ? (global.i18n.t(key) || fallback) : fallback; }
        catch (_) { return fallback; }
    }

    function escapeHtml(s) {
        const d = document.createElement('div');
        d.textContent = s == null ? '' : String(s);
        return d.innerHTML;
    }

    function renderChips(escapedHtml) {
        if (global.AutolinkChip && typeof global.AutolinkChip.render === 'function') {
            try { return global.AutolinkChip.render(escapedHtml); } catch (_) {}
        }
        return escapedHtml;
    }

    function closeAll() {
        while (stack.length) stack.pop().remove();
        rootAnchor = null;
    }

    function closeFromIndex(idx) {
        while (stack.length > idx) stack.pop().remove();
        if (!stack.length) rootAnchor = null;
    }

    function positionPopover(pop, anchorEl) {
        const rect = anchorEl.getBoundingClientRect();
        const width = 320;
        const viewportW = window.innerWidth;
        const gap = 6;
        let left = rect.left + window.scrollX;
        if (left + width > window.scrollX + viewportW - 8) {
            left = window.scrollX + viewportW - width - 8;
        }
        if (left < window.scrollX + 8) left = window.scrollX + 8;
        pop.style.position = 'absolute';
        pop.style.top = (rect.bottom + window.scrollY + gap) + 'px';
        pop.style.left = left + 'px';
        pop.style.width = width + 'px';
        pop.style.zIndex = String(9999 + stack.length);
    }

    function refKey(refType, refId) { return refType + '|' + refId; }

    function isOnStack(refType, refId) {
        const key = refKey(refType, refId);
        return stack.some(p => refKey(p._refType, p._refId) === key);
    }

    function openPreview(refType, refId, anchorEl) {
        // Top-level call (from a chip outside any popover) — close existing stack first
        if (!anchorEl || !anchorEl.closest('.autolink-chip-popover')) {
            closeAll();
            rootAnchor = anchorEl;
        }

        // Cycle / depth guards
        if (isOnStack(refType, refId)) {
            showToast(anchorEl, t('chip_popover_cycle', '已在引用堆疊上'));
            return;
        }
        if (stack.length >= MAX_DEPTH) {
            showToast(anchorEl, t('chip_popover_too_deep', '太深，請直接跳頁'));
            return;
        }

        const pop = document.createElement('div');
        pop.className = 'autolink-chip-popover';
        pop.setAttribute('data-ref-type', refType);
        pop.setAttribute('data-ref-id', refId);
        pop._refType = refType;
        pop._refId = refId;
        pop._data = null;
        pop._depth = stack.length;
        pop._anchorEl = anchorEl;
        pop.innerHTML = buildLoadingHtml();
        document.body.appendChild(pop);
        positionPopover(pop, anchorEl);
        stack.push(pop);
        bindPopoverActions(pop);

        resolveRef(refType, refId).then(data => {
            if (!stack.includes(pop)) return;
            pop._data = data;
            pop.innerHTML = buildContentHtml(data, refType, refId);
        }).catch(err => {
            if (!stack.includes(pop)) return;
            pop._data = null;
            pop.innerHTML = buildErrorHtml(err, refType, refId);
        });
    }

    function resolveRef(refType, refId) {
        if (refType === 'src') {
            const m = /^src:\/\/([a-z]+)\/([a-z]+)\/([a-f0-9]{8,})(#.+)?$/i.exec(refId);
            if (!m) return Promise.reject(new Error('bad src token'));
            const kind = m[1], type = m[2], id = m[3], anchor = m[4] || null;
            if (kind === 'kanban' && type === 'card') {
                const deviceId = (global.currentUser && global.currentUser.deviceId) || '';
                const deviceSecret = (global.currentUser && global.currentUser.deviceSecret) || '';
                const qs = deviceId
                    ? '?deviceId=' + encodeURIComponent(deviceId) + (deviceSecret ? '&deviceSecret=' + encodeURIComponent(deviceSecret) : '')
                    : '';
                const url = '/api/mission/card/card_' + id + qs;
                return fetch(url, { credentials: 'include' })
                    .then(r => r.json())
                    .then(j => {
                        if (j && j.success === false) throw new Error(j.error || 'fetch failed');
                        const card = j.card || j;
                        if (!card || !card.id) throw new Error('card not found');
                        return { kind: 'card', data: card, anchor, refType, refId };
                    });
            }
            return Promise.reject(new Error('ref_not_supported:' + kind + '/' + type));
        }
        if (refType === 'review') {
            return Promise.reject(new Error('ref_not_supported:review'));
        }
        return Promise.reject(new Error('ref_not_supported:' + refType));
    }

    function buildLoadingHtml() {
        return `<div class="chip-popover-loading">${escapeHtml(t('chip_popover_loading', '載入中…'))}</div>`;
    }

    function buildErrorHtml(err, refType, refId) {
        const msg = (err && err.message && err.message.startsWith('ref_not_supported:'))
            ? t('chip_popover_not_supported', '此引用類型尚未支援預覽')
            : t('chip_popover_load_error', '載入失敗') + (err && err.message ? ' (' + escapeHtml(err.message.slice(0, 60)) + ')' : '');
        const requoteTitle = t('chip_popover_requote', '再引用到聊天');
        const closeTitle = t('common_close', '關閉');
        return `
            <div class="chip-popover-header">
                <span class="chip-popover-title">${escapeHtml(refId || '')}</span>
                <button class="chip-popover-btn chip-popover-quote" title="${escapeHtml(requoteTitle)}" data-action="requote">📌</button>
                <button class="chip-popover-btn chip-popover-close" title="${escapeHtml(closeTitle)}" data-action="close">✖</button>
            </div>
            <div class="chip-popover-body"><div class="chip-popover-error">${escapeHtml(msg)}</div></div>
        `;
    }

    function buildContentHtml(d, refType, refId) {
        if (d.kind !== 'card') return buildErrorHtml(new Error('ref_not_supported:kind'), refType, refId);
        const c = d.data;
        const status = c.status || 'todo';
        const descRaw = (c.description || '').slice(0, 200);
        const hasMoreDesc = (c.description || '').length > 200;
        const desc = renderChips(escapeHtml(descRaw)) + (hasMoreDesc ? '…' : '');
        const comments = (Array.isArray(c.comments) ? c.comments.slice(-2) : []).map(cmt => {
            const raw = (cmt.text || '').slice(0, 120);
            const truncated = cmt.text && cmt.text.length > 120 ? '…' : '';
            return '<div class="chip-popover-comment">💬 ' + renderChips(escapeHtml(raw)) + truncated + '</div>';
        }).join('');
        const titleRendered = renderChips(escapeHtml(c.title || ''));
        const hashId = c.id.indexOf('card_') === 0 ? c.id : ('card_' + c.id);
        const fullUrl = '/portal/kanban.html#' + hashId;
        const requoteTitle = t('chip_popover_requote', '再引用到聊天');
        const closeTitle = t('common_close', '關閉');
        const openFullLabel = t('chip_popover_open_full', '打開完整頁面 →');
        return `
            <div class="chip-popover-header">
                <span class="chip-popover-title" title="${escapeHtml(c.title || '')}">${titleRendered}</span>
                <span class="chip-popover-status chip-status--${escapeHtml(status)}">${escapeHtml(status)}</span>
                <button class="chip-popover-btn chip-popover-quote" title="${escapeHtml(requoteTitle)}" data-action="requote">📌</button>
                <button class="chip-popover-btn chip-popover-close" title="${escapeHtml(closeTitle)}" data-action="close">✖</button>
            </div>
            <div class="chip-popover-body">
                ${descRaw ? '<div class="chip-popover-desc">' + desc + '</div>' : ''}
                ${comments}
            </div>
            <div class="chip-popover-footer">
                <a href="${escapeHtml(fullUrl)}" class="chip-popover-open">${escapeHtml(openFullLabel)}</a>
            </div>
        `;
    }

    function bindPopoverActions(pop) {
        pop.addEventListener('click', (e) => {
            // Nested chip click → recurse into openPreview
            const chip = e.target.closest('.autolink-chip');
            if (chip && pop.contains(chip)) {
                e.stopPropagation();
                e.preventDefault();
                const refType = chip.getAttribute('data-ref-type');
                const refId = chip.getAttribute('data-ref-id');
                if (refType && refId) {
                    // Truncate stack above this popover (close any deeper siblings) before opening
                    const myIdx = stack.indexOf(pop);
                    if (myIdx >= 0) closeFromIndex(myIdx + 1);
                    openPreview(refType, refId, chip);
                }
                return;
            }
            const btn = e.target.closest('[data-action]');
            if (!btn) return;
            e.stopPropagation();
            const action = btn.getAttribute('data-action');
            if (action === 'close') {
                const idx = stack.indexOf(pop);
                if (idx >= 0) closeFromIndex(idx);
                return;
            }
            if (action === 'requote') { insertRequoteToken(pop._data, pop._refType, pop._refId, pop._anchorEl || rootAnchor); closeAll(); return; }
        });
    }

    function showToast(anchorEl, msg) {
        const tip = document.createElement('div');
        tip.className = 'autolink-chip-toast';
        tip.textContent = msg;
        const rect = (anchorEl && anchorEl.getBoundingClientRect) ? anchorEl.getBoundingClientRect() : { left: 100, top: 100, bottom: 120 };
        tip.style.position = 'absolute';
        tip.style.top = (rect.bottom + window.scrollY + 4) + 'px';
        tip.style.left = (rect.left + window.scrollX) + 'px';
        tip.style.zIndex = String(9999 + stack.length + 1);
        document.body.appendChild(tip);
        setTimeout(() => { tip.style.opacity = '0'; }, 1200);
        setTimeout(() => { tip.remove(); }, 1800);
    }

    function insertRequoteTokenIntoInput(input, token) {
        if (input.tagName === 'TEXTAREA' || input.tagName === 'INPUT') {
            const cur = input.value || '';
            const pos = input.selectionStart != null ? input.selectionStart : cur.length;
            const before = cur.slice(0, pos), after = cur.slice(pos);
            const insert = (before && !before.endsWith(' ') ? ' ' : '') + token + ' ';
            input.value = before + insert + after;
            input.focus();
            const caret = before.length + insert.length;
            try { input.setSelectionRange(caret, caret); } catch (_) {}
            input.dispatchEvent(new Event('input', { bubbles: true }));
        } else {
            input.focus();
            document.execCommand && document.execCommand('insertText', false, token + ' ');
        }
    }

    function insertRequoteToken(data, refType, refId, anchorEl) {
        const token = tokenFor(data, refType, refId);
        const chatInput = document.getElementById('messageInput');
        if (chatInput) {
            insertRequoteTokenIntoInput(chatInput, token);
            showToast(anchorEl, t('chip_popover_requoted', '已引用'));
            return;
        }
        // No local chat input — try cross-pane relay (workspace split-view).
        // Source page posts to its parent; workspace forwards to the chat iframe.
        if (window.parent && window.parent !== window) {
            try {
                window.parent.postMessage(
                    { type: 'eclaw_requote', token, refType, refId },
                    window.location.origin
                );
                showToast(anchorEl, t('chip_popover_requoted', '已引用'));
                return;
            } catch (_) {}
        }
        // Last-resort fallback: any other writable surface on the page (e.g. a
        // mindmap inline-note editor). Silent — caller doesn't know if landing
        // target was actually chat-shaped.
        const fallback = document.querySelector('textarea, [contenteditable="true"]');
        if (fallback) insertRequoteTokenIntoInput(fallback, token);
    }

    // Receive cross-pane requote (chat iframe side). Workspace forwards
    // 'eclaw_requote' here; insert into messageInput if present.
    window.addEventListener('message', (e) => {
        if (e.origin !== window.location.origin) return;
        if (!e.data || e.data.type !== 'eclaw_requote') return;
        const input = document.getElementById('messageInput');
        if (input && typeof e.data.token === 'string') {
            insertRequoteTokenIntoInput(input, e.data.token);
        }
    });

    function tokenFor(data, refType, refId) {
        if (data && data.kind === 'card' && data.data && data.data.id) {
            return data.data.id;
        }
        return refId;
    }

    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && stack.length) { closeAll(); }
    });
    document.addEventListener('click', (e) => {
        if (!stack.length) return;
        if (e.target.closest('.autolink-chip-popover')) return;
        if (e.target.closest('.autolink-chip-toast')) return;
        if (e.target === rootAnchor) return;
        if (e.target.closest('.autolink-chip')) return;
        closeAll();
    });

    global.AutolinkChipPreview = openPreview;
    global.AutolinkChipPreview._closeAll = closeAll;
    global.AutolinkChipPreview._stack = () => stack.slice();
    global.AutolinkChipPreview._MAX_DEPTH = MAX_DEPTH;
})(window);
