/**
 * Lightweight rich text editor — no CDN dependencies.
 * Usage: initRichEditor(wrapId, hiddenId, { initialContent, mentionData, placeholder, minHeight })
 */
function initRichEditor(wrapId, hiddenId, opts) {
    opts = opts || {};
    const wrap = document.getElementById(wrapId);
    if (!wrap) return null;

    // ── Toolbar ──────────────────────────────────────────────
    const toolbar = document.createElement('div');
    toolbar.className = 're-toolbar';

    const editor = document.createElement('div');
    editor.className = 're-editor';
    editor.contentEditable = 'true';
    editor.style.minHeight = (opts.minHeight || 80) + 'px';
    if (opts.placeholder) editor.dataset.placeholder = opts.placeholder;

    wrap.innerHTML = '';
    wrap.appendChild(toolbar);
    wrap.appendChild(editor);

    document.execCommand('defaultParagraphSeparator', false, 'p');

    function cmd(c, v) {
        editor.focus();
        document.execCommand(c, false, v || null);
    }

    function addBtn(html, title, action) {
        const b = document.createElement('button');
        b.type = 'button';
        b.className = 're-btn';
        b.innerHTML = html;
        b.title = title;
        b.addEventListener('mousedown', e => { e.preventDefault(); action(); });
        toolbar.appendChild(b);
        return b;
    }
    function addSep() {
        const s = document.createElement('span');
        s.className = 're-sep';
        toolbar.appendChild(s);
    }

    addBtn('<b>B</b>', 'Fett (Ctrl+B)', () => cmd('bold'));
    addBtn('<i>I</i>', 'Kursiv (Ctrl+I)', () => cmd('italic'));
    addBtn('<u>U</u>', 'Unterstrichen (Ctrl+U)', () => cmd('underline'));
    addSep();
    addBtn(
        '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="9" y1="6" x2="20" y2="6"/><line x1="9" y1="12" x2="20" y2="12"/><line x1="9" y1="18" x2="20" y2="18"/><circle cx="4" cy="6" r="1.5" fill="currentColor" stroke="none"/><circle cx="4" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="4" cy="18" r="1.5" fill="currentColor" stroke="none"/></svg>',
        'Aufzählung', () => cmd('insertUnorderedList'));
    addBtn(
        '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="10" y1="6" x2="20" y2="6"/><line x1="10" y1="12" x2="20" y2="12"/><line x1="10" y1="18" x2="20" y2="18"/><text x="3" y="9" font-size="7" fill="currentColor" stroke="none">1</text><text x="3" y="15" font-size="7" fill="currentColor" stroke="none">2</text><text x="3" y="21" font-size="7" fill="currentColor" stroke="none">3</text></svg>',
        'Nummerierte Liste', () => cmd('insertOrderedList'));
    addSep();

    // Image: file picker
    const imgInput = document.createElement('input');
    imgInput.type = 'file';
    imgInput.accept = 'image/*';
    imgInput.style.display = 'none';
    wrap.appendChild(imgInput);
    addBtn(
        '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',
        'Bild einfügen', () => imgInput.click());
    imgInput.addEventListener('change', () => {
        const file = imgInput.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = ev => { editor.focus(); cmd('insertHTML', `<img src="${ev.target.result}" style="max-width:100%">`); };
        reader.readAsDataURL(file);
        imgInput.value = '';
    });

    // Table
    addBtn('⊞', 'Tabelle einfügen', () => {
        const rows = parseInt(prompt('Zeilen:', '3') || '0');
        const cols = parseInt(prompt('Spalten:', '3') || '0');
        if (!rows || !cols) return;
        let h = '<table><thead><tr>' + '<th>&nbsp;</th>'.repeat(cols) + '</tr></thead><tbody>';
        for (let r = 1; r < rows; r++) h += '<tr>' + '<td>&nbsp;</td>'.repeat(cols) + '</tr>';
        h += '</tbody></table>';
        editor.focus();
        cmd('insertHTML', h);
    });

    // ── Initial content ───────────────────────────────────────
    if (opts.initialContent) {
        if (opts.initialContent.includes('<')) {
            editor.innerHTML = opts.initialContent;
        } else {
            editor.textContent = opts.initialContent;
        }
    }

    // ── Paste image from clipboard ────────────────────────────
    editor.addEventListener('paste', e => {
        const items = e.clipboardData && e.clipboardData.items;
        if (!items) return;
        for (let i = 0; i < items.length; i++) {
            if (items[i].type.startsWith('image/')) {
                e.preventDefault();
                const blob = items[i].getAsFile();
                const reader = new FileReader();
                reader.onload = ev => cmd('insertHTML', `<img src="${ev.target.result}" style="max-width:100%">`);
                reader.readAsDataURL(blob);
                return;
            }
        }
    });

    // ── Sync to hidden input on submit ────────────────────────
    const hidden = document.getElementById(hiddenId);
    if (hidden) {
        const form = wrap.closest('form');
        if (form) {
            form.addEventListener('submit', () => {
                const html = editor.innerHTML;
                hidden.value = (html === '<br>' || html === '' || html === '<p><br></p>') ? '' : html;
            });
        }
    }

    // ── @mention ──────────────────────────────────────────────
    if (opts.mentionData && opts.mentionData.length) {
        attachMentionToEditor(editor, opts.mentionData);
    }

    return editor;
}

/**
 * Attach @mention autocomplete to a contenteditable element.
 */
function attachMentionToEditor(editor, data) {
    let dropdown = null;
    let mentionAnchor = null; // { node: TextNode, offset: number }

    function buildDD() {
        if (dropdown) return;
        dropdown = document.createElement('div');
        dropdown.className = 'mention-dropdown';
        document.body.appendChild(dropdown);
    }

    function showDD(items, x, y) {
        buildDD();
        dropdown.innerHTML = '';
        items.forEach(item => {
            const el = document.createElement('div');
            el.className = 'mention-item';
            el.innerHTML = '@' + item.display +
                (item.type === 'ext' ? '<span class="mention-item-badge">Ext</span>' : '');
            el.addEventListener('mousedown', e => { e.preventDefault(); insertMention(item); });
            dropdown.appendChild(el);
        });
        // Clamp to viewport
        const ddW = 240, ddH = 220;
        const vw = window.innerWidth, vh = window.innerHeight;
        dropdown.style.left = Math.min(x, vw - ddW - 8) + 'px';
        dropdown.style.top  = (y + ddH > vh ? y - ddH - 4 : y) + 'px';
        dropdown.style.display = 'block';
    }

    function hideDD() {
        if (dropdown) dropdown.style.display = 'none';
        mentionAnchor = null;
    }

    function insertMention(item) {
        if (!mentionAnchor) return;
        const sel = window.getSelection();
        if (!sel || !sel.rangeCount) return;

        const endRange = sel.getRangeAt(0);
        const range = document.createRange();
        try {
            range.setStart(mentionAnchor.node, mentionAnchor.offset);
            range.setEnd(endRange.startContainer, endRange.startOffset);
        } catch (e) { hideDD(); return; }

        range.deleteContents();
        sel.removeAllRanges();
        sel.addRange(range);

        const span = document.createElement('span');
        span.className = 'mention';
        span.dataset.mention = item.key;
        span.textContent = '@' + item.key;
        span.contentEditable = 'false';
        range.insertNode(span);

        const after = document.createRange();
        after.setStartAfter(span);
        after.collapse(true);
        sel.removeAllRanges();
        sel.addRange(after);
        document.execCommand('insertText', false, '\u00a0');

        hideDD();
    }

    editor.addEventListener('input', () => {
        const sel = window.getSelection();
        if (!sel || !sel.rangeCount) return;
        const range = sel.getRangeAt(0);
        const node = range.startContainer;
        if (node.nodeType !== Node.TEXT_NODE) { hideDD(); return; }

        const text = node.textContent.substring(0, range.startOffset);
        const m = text.match(/@(\S*)$/);
        if (m) {
            const atOffset = range.startOffset - m[0].length;
            mentionAnchor = { node, offset: atOffset };
            const query = m[1].toLowerCase();
            const hits = data.filter(d => d.display.toLowerCase().startsWith(query)).slice(0, 8);
            if (hits.length) {
                const rect = range.getBoundingClientRect();
                showDD(hits, rect.left, rect.bottom + 4);
            } else {
                hideDD();
            }
        } else {
            hideDD();
        }
    });

    editor.addEventListener('keydown', e => {
        if (!dropdown || dropdown.style.display === 'none') return;
        const items = Array.from(dropdown.querySelectorAll('.mention-item'));
        const ai = items.findIndex(x => x.classList.contains('active'));
        if (e.key === 'ArrowDown') {
            e.preventDefault();
            if (ai >= 0) items[ai].classList.remove('active');
            items[Math.min(ai + 1, items.length - 1)].classList.add('active');
        } else if (e.key === 'ArrowUp') {
            e.preventDefault();
            if (ai >= 0) items[ai].classList.remove('active');
            items[Math.max(ai - 1, 0)].classList.add('active');
        } else if (e.key === 'Enter') {
            const active = dropdown.querySelector('.mention-item.active');
            if (active) { e.preventDefault(); active.dispatchEvent(new MouseEvent('mousedown')); }
        } else if (e.key === 'Escape') {
            hideDD();
        }
    });

    document.addEventListener('click', e => {
        if (dropdown && !editor.contains(e.target) && !dropdown.contains(e.target)) hideDD();
    });
}
