/**
 * RichEditor - 共享富文本工具栏组件
 * 用于聊天和论坛的输入区域
 */

// ========== 常量 ==========
const RE_FONTS = [
    { label: '默认', value: '' },
    { label: '宋体', value: '宋体,SimSun' },
    { label: '黑体', value: '黑体,SimHei' },
    { label: '楷体', value: '楷体,KaiTi' },
    { label: '仿宋', value: '仿宋,FangSong' },
    { label: '微软雅黑', value: '微软雅黑,Microsoft YaHei' },
    { label: '华文行楷', value: '华文行楷,STXingkai' },
    { label: '华文新魏', value: '华文新魏,STXinwei' },
    { label: '隶书', value: '隶书,LiSu' },
    { label: '幼圆', value: '幼圆,YouYuan' },
    { label: 'Consolas', value: 'Consolas,monospace' },
    { label: 'Georgia', value: 'Georgia,serif' },
    { label: 'Comic Sans', value: 'Comic Sans MS,cursive' },
    { label: 'Times New Roman', value: 'Times New Roman,serif' },
];

const RE_EMOJIS = {
    '表情': ['😀','😁','😂','🤣','😊','😍','🥰','😘','😜','🤪'],
    '手势': ['👍','👎','👏','🙌','🤝','✌️','🤞','👌','🫶','🙏'],
    '心形': ['❤️','🧡','💛','💚','💙','💜','🖤','🤍','💖','💝'],
    '动物': ['🐱','🐶','🐼','🦊','🐰','🐸','🐵','🦁','🐯','🐮'],
    '物品': ['🎉','🎊','🔥','⭐','💡','📚','✏️','🏆','🎯','💻'],
    '符号': ['✅','❌','⚠️','💯','🔴','🟢','🔵','⬆️','⬇️','➡️'],
};

const RE_COLORS = [
    '#ef4444','#f97316','#eab308','#22c55e','#06b6d4',
    '#3b82f6','#8b5cf6','#ec4899','#6b7280','#000000',
    '#dc2626','#ea580c','#ca8a04','#16a34a','#0891b2',
    '#2563eb','#7c3aed','#db2777','#9ca3af','#ffffff',
];

const RE_MATH_SYMBOLS = {
    '基础运算': [
        { label: '+', tex: '+' },
        { label: '−', tex: '-' },
        { label: '±', tex: '\\pm' },
        { label: '∓', tex: '\\mp' },
        { label: '×', tex: '\\times' },
        { label: '÷', tex: '\\div' },
        { label: '·', tex: '\\cdot' },
        { label: '=', tex: '=' },
        { label: '≠', tex: '\\neq' },
        { label: '≈', tex: '\\approx' },
        { label: '≡', tex: '\\equiv' },
        { label: '<', tex: '<' },
        { label: '>', tex: '>' },
        { label: '≤', tex: '\\leq' },
        { label: '≥', tex: '\\geq' },
        { label: '≪', tex: '\\ll' },
        { label: '≫', tex: '\\gg' },
        { label: '∝', tex: '\\propto' },
    ],
    '上下标': [
        { label: 'x²', tex: '^{2}' },
        { label: 'x³', tex: '^{3}' },
        { label: 'xⁿ', tex: '^{}', cursor: -1 },
        { label: 'x₁', tex: '_{}', cursor: -1 },
        { label: 'xₙ', tex: '_{n}' },
        { label: 'x₁²', tex: '_{}^{}', cursor: -4 },
    ],
    '分数根号': [
        { label: '分数', tex: '\\frac{}{}', cursor: -3 },
        { label: '√', tex: '\\sqrt{}', cursor: -1 },
        { label: 'ⁿ√', tex: '\\sqrt[n]{}', cursor: -1 },
        { label: 'ᵃ⁄ᵦ', tex: '\\dfrac{}{}', cursor: -3 },
    ],
    '希腊字母': [
        { label: 'α', tex: '\\alpha' },
        { label: 'β', tex: '\\beta' },
        { label: 'γ', tex: '\\gamma' },
        { label: 'δ', tex: '\\delta' },
        { label: 'ε', tex: '\\epsilon' },
        { label: 'ζ', tex: '\\zeta' },
        { label: 'η', tex: '\\eta' },
        { label: 'θ', tex: '\\theta' },
        { label: 'λ', tex: '\\lambda' },
        { label: 'μ', tex: '\\mu' },
        { label: 'ξ', tex: '\\xi' },
        { label: 'π', tex: '\\pi' },
        { label: 'ρ', tex: '\\rho' },
        { label: 'σ', tex: '\\sigma' },
        { label: 'τ', tex: '\\tau' },
        { label: 'φ', tex: '\\varphi' },
        { label: 'ω', tex: '\\omega' },
        { label: 'Δ', tex: '\\Delta' },
        { label: 'Σ', tex: '\\Sigma' },
        { label: 'Ω', tex: '\\Omega' },
        { label: 'Φ', tex: '\\Phi' },
        { label: 'Π', tex: '\\Pi' },
        { label: 'Λ', tex: '\\Lambda' },
        { label: 'Γ', tex: '\\Gamma' },
    ],
    '高等数学': [
        { label: '∑', tex: '\\sum_{i=1}^{n}', cursor: 0 },
        { label: '∏', tex: '\\prod_{i=1}^{n}', cursor: 0 },
        { label: '∫', tex: '\\int_{a}^{b}', cursor: 0 },
        { label: '∬', tex: '\\iint' },
        { label: '∮', tex: '\\oint' },
        { label: 'lim', tex: '\\lim_{x \\to }', cursor: -1 },
        { label: '∞', tex: '\\infty' },
        { label: 'log', tex: '\\log_{}', cursor: -1 },
        { label: 'ln', tex: '\\ln' },
        { label: 'sin', tex: '\\sin' },
        { label: 'cos', tex: '\\cos' },
        { label: 'tan', tex: '\\tan' },
        { label: 'arcsin', tex: '\\arcsin' },
        { label: 'arccos', tex: '\\arccos' },
        { label: 'arctan', tex: '\\arctan' },
        { label: '∂', tex: '\\partial' },
        { label: '∇', tex: '\\nabla' },
        { label: 'dx', tex: '\\mathrm{d}x' },
    ],
    '集合逻辑': [
        { label: '∈', tex: '\\in' },
        { label: '∉', tex: '\\notin' },
        { label: '⊂', tex: '\\subset' },
        { label: '⊃', tex: '\\supset' },
        { label: '⊆', tex: '\\subseteq' },
        { label: '⊇', tex: '\\supseteq' },
        { label: '∪', tex: '\\cup' },
        { label: '∩', tex: '\\cap' },
        { label: '∅', tex: '\\emptyset' },
        { label: '∀', tex: '\\forall' },
        { label: '∃', tex: '\\exists' },
        { label: '¬', tex: '\\neg' },
        { label: '∧', tex: '\\land' },
        { label: '∨', tex: '\\lor' },
        { label: '⇒', tex: '\\Rightarrow' },
        { label: '⇔', tex: '\\Leftrightarrow' },
        { label: '→', tex: '\\to' },
        { label: '↦', tex: '\\mapsto' },
    ],
    '括号矩阵': [
        { label: '()', tex: '\\left( \\right)', cursor: -8 },
        { label: '[]', tex: '\\left[ \\right]', cursor: -8 },
        { label: '{}', tex: '\\left\\{ \\right\\}', cursor: -9 },
        { label: '||', tex: '\\left| \\right|', cursor: -8 },
        { label: '⌈⌉', tex: '\\lceil \\rceil', cursor: -7 },
        { label: '⌊⌋', tex: '\\lfloor \\rfloor', cursor: -8 },
        { label: '矩阵', tex: '\\begin{pmatrix}  \\\\  \\end{pmatrix}', cursor: -18 },
        { label: '行列式', tex: '\\begin{vmatrix}  \\\\  \\end{vmatrix}', cursor: -18 },
        { label: '方程组', tex: '\\begin{cases}  \\\\  \\end{cases}', cursor: -15 },
    ],
    '其他符号': [
        { label: '…', tex: '\\cdots' },
        { label: '⋮', tex: '\\vdots' },
        { label: '⋱', tex: '\\ddots' },
        { label: '°', tex: '^{\\circ}' },
        { label: '‰', tex: '\\permil' },
        { label: '→', tex: '\\vec{}', cursor: -1 },
        { label: 'â', tex: '\\hat{}', cursor: -1 },
        { label: 'ā', tex: '\\bar{}', cursor: -1 },
        { label: 'ã', tex: '\\tilde{}', cursor: -1 },
        { label: '⊥', tex: '\\perp' },
        { label: '∥', tex: '\\parallel' },
        { label: '∠', tex: '\\angle' },
        { label: '△', tex: '\\triangle' },
        { label: '□', tex: '\\square' },
        { label: '⊕', tex: '\\oplus' },
        { label: '⊗', tex: '\\otimes' },
        { label: '★', tex: '\\star' },
        { label: '♠', tex: '\\spadesuit' },
    ],
};

const RE_FORMULA_TEMPLATES = [
    { label: '二次公式', tex: 'x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}' },
    { label: '勾股定理', tex: 'a^2 + b^2 = c^2' },
    { label: '求和公式', tex: '\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}' },
    { label: '二项式定理', tex: '(a+b)^n = \\sum_{k=0}^{n} \\binom{n}{k} a^{n-k} b^k' },
    { label: '欧拉公式', tex: 'e^{i\\pi} + 1 = 0' },
    { label: '三角恒等式', tex: '\\sin^2\\theta + \\cos^2\\theta = 1' },
    { label: '对数换底', tex: '\\log_a b = \\frac{\\ln b}{\\ln a}' },
    { label: '导数定义', tex: "f'(x) = \\lim_{h \\to 0} \\frac{f(x+h) - f(x)}{h}" },
    { label: '定积分', tex: '\\int_a^b f(x)\\,dx = F(b) - F(a)' },
    { label: '矩阵乘法', tex: '\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix} \\begin{pmatrix} e \\\\ f \\end{pmatrix} = \\begin{pmatrix} ae+bf \\\\ ce+df \\end{pmatrix}' },
    { label: '方程组', tex: '\\begin{cases} x + y = 5 \\\\ 2x - y = 1 \\end{cases}' },
    { label: '极限', tex: '\\lim_{x \\to \\infty} \\left(1 + \\frac{1}{x}\\right)^x = e' },
];

// ========== RichEditor 类 ==========
class RichEditor {
    constructor(textareaId, options = {}) {
        this.ta = document.getElementById(textareaId);
        if (!this.ta) return;
        this.compact = options.compact || false; // 紧凑模式（聊天用）
        this.onEnter = options.onEnter || null;
        this._buildToolbar();
        this._buildPreview();
        this._bindKeys();
        this._bindPreviewUpdate();
    }

    _buildToolbar() {
        const bar = document.createElement('div');
        bar.className = 're-toolbar' + (this.compact ? ' re-compact' : '');

        // 粗体
        bar.appendChild(this._btn('B', '粗体', 're-bold', () => this._wrap('**', '**')));
        // 斜体
        bar.appendChild(this._btn('I', '斜体', 're-italic', () => this._wrap('*', '*')));
        // 代码
        bar.appendChild(this._btn('&lt;&gt;', '代码', 're-code', () => this._wrap('`', '`')));
        bar.appendChild(this._sep());

        // 颜色
        const colorWrap = document.createElement('div');
        colorWrap.className = 're-dropdown-wrap';
        const colorBtn = this._btn('A', '文字颜色', 're-color-btn', () => this._togglePanel(colorWrap));
        colorBtn.innerHTML = '<span style="border-bottom:2px solid #ef4444;padding-bottom:1px">A</span>';
        colorWrap.appendChild(colorBtn);
        colorWrap.appendChild(this._buildColorPanel(colorBtn));
        bar.appendChild(colorWrap);

        // 字体
        const fontWrap = document.createElement('div');
        fontWrap.className = 're-dropdown-wrap';
        fontWrap.appendChild(this._btn('字', '字体', 're-font-btn', () => this._togglePanel(fontWrap)));
        fontWrap.appendChild(this._buildFontPanel());
        bar.appendChild(fontWrap);
        bar.appendChild(this._sep());

        // Emoji
        const emojiWrap = document.createElement('div');
        emojiWrap.className = 're-dropdown-wrap';
        emojiWrap.appendChild(this._btn('😊', 'Emoji', 're-emoji-btn', () => this._togglePanel(emojiWrap)));
        emojiWrap.appendChild(this._buildEmojiPanel());
        bar.appendChild(emojiWrap);

        // 公式编辑器按钮
        bar.appendChild(this._sep());
        const self = this;
        bar.appendChild(this._btn('fx', '公式编辑器', 're-fx-btn', () => openMathEditor(self.ta)));

        this.ta.parentNode.insertBefore(bar, this.ta);
        this.toolbar = bar;

        // 点击外部关闭面板
        document.addEventListener('click', (e) => {
            if (!bar.contains(e.target)) {
                bar.querySelectorAll('.re-panel').forEach(p => p.classList.add('hidden'));
            }
        });
    }

    _btn(html, title, cls, onclick) {
        const b = document.createElement('button');
        b.type = 'button';
        b.className = 're-btn ' + (cls || '');
        b.title = title;
        b.innerHTML = html;
        b.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); onclick(); });
        return b;
    }

    _sep() {
        const s = document.createElement('span');
        s.className = 're-sep';
        return s;
    }

    _togglePanel(wrap) {
        const panel = wrap.querySelector('.re-panel');
        const wasHidden = panel.classList.contains('hidden');
        this.toolbar.querySelectorAll('.re-panel').forEach(p => p.classList.add('hidden'));
        if (wasHidden) panel.classList.remove('hidden');
    }

    _wrap(pre, suf) {
        const s = this.ta.selectionStart, e = this.ta.selectionEnd;
        const txt = this.ta.value;
        const sel = txt.substring(s, e) || '文本';
        this.ta.value = txt.substring(0, s) + pre + sel + suf + txt.substring(e);
        this.ta.focus();
        this.ta.selectionStart = s + pre.length;
        this.ta.selectionEnd = s + pre.length + sel.length;
        this._refreshPreview();
    }

    _insertAt(text, cursorOffset) {
        const s = this.ta.selectionStart;
        const v = this.ta.value;
        this.ta.value = v.substring(0, s) + text + v.substring(s);
        this.ta.focus();
        this.ta.selectionStart = this.ta.selectionEnd = s + text.length + (cursorOffset || 0);
        this._refreshPreview();
    }

    _bindKeys() {
        if (!this.onEnter) return;
        this.ta.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                this.onEnter();
            }
        });
    }

    _buildPreview() {
        // 实时预览面板，插在 textarea 后面
        const pv = document.createElement('div');
        pv.className = 're-live-preview';
        pv.innerHTML = '<div class="re-pv-label">预览</div><div class="re-pv-body"></div>';
        // 插到 textarea 的父容器末尾（border 容器内）
        this.ta.parentNode.appendChild(pv);
        this.previewEl = pv.querySelector('.re-pv-body');
    }

    _bindPreviewUpdate() {
        let timer = null;
        const update = () => {
            if (!this.previewEl) return;
            const val = this.ta.value.trim();
            if (!val) { this.previewEl.innerHTML = '<span style="color:#94a3b8;font-size:13px">输入内容后这里会显示实时预览...</span>'; return; }
            this.previewEl.innerHTML = renderRichContent(val);
        };
        this.ta.addEventListener('input', () => { clearTimeout(timer); timer = setTimeout(update, 150); });
        update();
    }

    _refreshPreview() {
        if (!this.previewEl) return;
        const val = this.ta.value.trim();
        if (!val) { this.previewEl.innerHTML = '<span style="color:#94a3b8;font-size:13px">输入内容后这里会显示实时预览...</span>'; return; }
        this.previewEl.innerHTML = renderRichContent(val);
    }

    // ===== 颜色面板 =====
    _buildColorPanel(colorBtn) {
        const panel = document.createElement('div');
        panel.className = 're-panel re-color-panel hidden';
        RE_COLORS.forEach(c => {
            const swatch = document.createElement('button');
            swatch.type = 'button';
            swatch.className = 're-swatch';
            swatch.style.background = c;
            if (c === '#ffffff') swatch.style.border = '1px solid #e2e8f0';
            swatch.addEventListener('click', (e) => {
                e.stopPropagation();
                this._wrap(`[color:${c}]`, '[/color]');
                colorBtn.querySelector('span').style.borderBottomColor = c;
                panel.classList.add('hidden');
            });
            panel.appendChild(swatch);
        });
        return panel;
    }

    // ===== 字体面板 =====
    _buildFontPanel() {
        const panel = document.createElement('div');
        panel.className = 're-panel re-font-panel hidden';
        RE_FONTS.forEach(f => {
            const item = document.createElement('button');
            item.type = 'button';
            item.className = 're-font-item';
            item.textContent = f.label;
            if (f.value) item.style.fontFamily = f.value;
            item.addEventListener('click', (e) => {
                e.stopPropagation();
                if (f.value) {
                    this._wrap(`[font:${f.label}]`, '[/font]');
                }
                panel.classList.add('hidden');
            });
            panel.appendChild(item);
        });
        return panel;
    }

    // ===== Emoji 面板 =====
    _buildEmojiPanel() {
        const panel = document.createElement('div');
        panel.className = 're-panel re-emoji-panel hidden';
        const tabs = document.createElement('div');
        tabs.className = 're-emoji-tabs';
        const body = document.createElement('div');
        body.className = 're-emoji-body';

        const categories = Object.keys(RE_EMOJIS);
        categories.forEach((cat, i) => {
            const tab = document.createElement('button');
            tab.type = 'button';
            tab.className = 're-emoji-tab' + (i === 0 ? ' active' : '');
            tab.textContent = cat;
            tab.addEventListener('click', (e) => {
                e.stopPropagation();
                tabs.querySelectorAll('.re-emoji-tab').forEach(t => t.classList.remove('active'));
                tab.classList.add('active');
                this._showEmojiCat(body, cat);
            });
            tabs.appendChild(tab);
        });

        panel.appendChild(tabs);
        panel.appendChild(body);
        this._showEmojiCat(body, categories[0]);
        return panel;
    }

    _showEmojiCat(body, cat) {
        body.innerHTML = '';
        RE_EMOJIS[cat].forEach(em => {
            const btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 're-emoji-item';
            btn.textContent = em;
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                this._insertAt(em);
            });
            body.appendChild(btn);
        });
    }
}

// ========== MathFormulaEditor 单例类 ==========
class MathFormulaEditor {
    constructor() {
        if (MathFormulaEditor._instance) return MathFormulaEditor._instance;
        MathFormulaEditor._instance = this;
        this._built = false;
        this._target = null;
        this._onInsert = null;
        this._debounceTimer = null;
    }

    open(targetTextarea, onInsert) {
        this._target = targetTextarea;
        this._onInsert = onInsert || null;
        if (!this._built) this._buildDOM();
        this._input.value = '';
        this._previewEl.innerHTML = '<span style="color:#94a3b8">在上方输入 LaTeX 公式，这里实时预览</span>';
        this._overlay.classList.remove('hidden');
        document.body.style.overflow = 'hidden';
        // 激活第一个符号分类 tab
        const firstTab = this._symbolTabs.querySelector('.re-emoji-tab');
        if (firstTab) firstTab.click();
        setTimeout(() => this._input.focus(), 50);
    }

    close() {
        this._overlay.classList.add('hidden');
        document.body.style.overflow = '';
    }

    _buildDOM() {
        this._built = true;
        const overlay = document.createElement('div');
        overlay.className = 're-math-editor-overlay hidden';
        overlay.addEventListener('click', (e) => { if (e.target === overlay) this.close(); });

        const modal = document.createElement('div');
        modal.className = 're-math-editor-modal';

        // Header
        const header = document.createElement('div');
        header.className = 're-math-editor-header';
        header.innerHTML = '<span style="font-weight:600;font-size:16px;color:#1e293b">数学公式编辑器</span>';
        const closeBtn = document.createElement('button');
        closeBtn.type = 'button';
        closeBtn.className = 're-math-editor-close';
        closeBtn.innerHTML = '&times;';
        closeBtn.addEventListener('click', () => this.close());
        header.appendChild(closeBtn);
        modal.appendChild(header);

        // Body
        const body = document.createElement('div');
        body.className = 're-math-editor-body';

        // LaTeX input
        const inputLabel = document.createElement('div');
        inputLabel.style.cssText = 'font-size:12px;color:#64748b;margin-bottom:4px;font-weight:500';
        inputLabel.textContent = 'LaTeX 公式';
        body.appendChild(inputLabel);
        const input = document.createElement('textarea');
        input.className = 're-math-editor-input';
        input.rows = 3;
        input.placeholder = '输入 LaTeX 公式，如 \\frac{a}{b}、x^2 + y^2 = r^2';
        input.addEventListener('input', () => this._updatePreview());
        this._input = input;
        body.appendChild(input);

        // Preview
        const pvLabel = document.createElement('div');
        pvLabel.style.cssText = 'font-size:12px;color:#64748b;margin:12px 0 4px;font-weight:500';
        pvLabel.textContent = '实时预览';
        body.appendChild(pvLabel);
        const preview = document.createElement('div');
        preview.className = 're-math-editor-preview';
        this._previewEl = preview;
        body.appendChild(preview);

        // Symbol panel
        const symLabel = document.createElement('div');
        symLabel.style.cssText = 'font-size:12px;color:#64748b;margin:12px 0 4px;font-weight:500';
        symLabel.textContent = '符号面板';
        body.appendChild(symLabel);
        // PLACEHOLDER_SYMBOL_PANEL
        const symTabs = document.createElement('div');
        symTabs.className = 're-emoji-tabs';
        symTabs.style.cssText = 'border:1px solid #e2e8f0;border-radius:8px 8px 0 0';
        this._symbolTabs = symTabs;
        const symGrid = document.createElement('div');
        symGrid.className = 're-math-grid';
        symGrid.style.cssText = 'border:1px solid #e2e8f0;border-top:none;border-radius:0 0 8px 8px;margin-bottom:0';
        const categories = Object.keys(RE_MATH_SYMBOLS);
        categories.forEach((cat, i) => {
            const tab = document.createElement('button');
            tab.type = 'button';
            tab.className = 're-emoji-tab' + (i === 0 ? ' active' : '');
            tab.textContent = cat;
            tab.addEventListener('click', (e) => {
                e.stopPropagation();
                symTabs.querySelectorAll('.re-emoji-tab').forEach(t => t.classList.remove('active'));
                tab.classList.add('active');
                this._showSymCat(symGrid, cat);
            });
            symTabs.appendChild(tab);
        });
        body.appendChild(symTabs);
        body.appendChild(symGrid);
        this._showSymCat(symGrid, categories[0]);

        // Template section
        const tplLabel = document.createElement('div');
        tplLabel.style.cssText = 'font-size:12px;color:#64748b;margin:14px 0 6px;font-weight:500';
        tplLabel.textContent = '常用公式模板';
        body.appendChild(tplLabel);
        const tplGrid = document.createElement('div');
        tplGrid.className = 're-math-editor-templates';
        RE_FORMULA_TEMPLATES.forEach(tpl => {
            const card = document.createElement('button');
            card.type = 'button';
            card.className = 're-math-editor-tpl-card';
            const texDiv = document.createElement('div');
            texDiv.className = 're-math-editor-tpl-tex';
            if (window.katex) {
                try { texDiv.innerHTML = katex.renderToString(tpl.tex, { throwOnError: false, displayMode: false }); }
                catch(e) { texDiv.textContent = tpl.tex; }
            } else { texDiv.textContent = tpl.tex; }
            const labelDiv = document.createElement('div');
            labelDiv.className = 're-math-editor-tpl-label';
            labelDiv.textContent = tpl.label;
            card.appendChild(texDiv);
            card.appendChild(labelDiv);
            card.addEventListener('click', () => this._applyTemplate(tpl.tex));
            tplGrid.appendChild(card);
        });
        body.appendChild(tplGrid);
        modal.appendChild(body);

        // Footer
        const footer = document.createElement('div');
        footer.className = 're-math-editor-footer';
        const cancelBtn = document.createElement('button');
        cancelBtn.type = 'button';
        cancelBtn.className = 're-math-editor-btn-cancel';
        cancelBtn.textContent = '取消';
        cancelBtn.addEventListener('click', () => this.close());
        const confirmBtn = document.createElement('button');
        confirmBtn.type = 'button';
        confirmBtn.className = 're-math-editor-btn-confirm';
        confirmBtn.textContent = '插入公式';
        confirmBtn.addEventListener('click', () => this._confirm());
        footer.appendChild(cancelBtn);
        footer.appendChild(confirmBtn);
        modal.appendChild(footer);

        overlay.appendChild(modal);
        document.body.appendChild(overlay);
        this._overlay = overlay;

        // ESC to close
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && !this._overlay.classList.contains('hidden')) this.close();
        });
    }

    _updatePreview() {
        clearTimeout(this._debounceTimer);
        this._debounceTimer = setTimeout(() => {
            const tex = this._input.value.trim();
            if (!tex) {
                this._previewEl.innerHTML = '<span style="color:#94a3b8">在上方输入 LaTeX 公式，这里实时预览</span>';
                return;
            }
            if (window.katex) {
                try {
                    this._previewEl.innerHTML = katex.renderToString(tex, { throwOnError: true, displayMode: true });
                } catch(e) {
                    this._previewEl.innerHTML = '<span style="color:#ef4444;font-size:13px">语法错误: ' + e.message.replace(/</g,'&lt;') + '</span>';
                }
            } else {
                this._previewEl.textContent = tex;
            }
        }, 150);
    }

    _insertSymbol(tex, cursor) {
        const start = this._input.selectionStart;
        const val = this._input.value;
        this._input.value = val.substring(0, start) + tex + val.substring(start);
        this._input.focus();
        this._input.selectionStart = this._input.selectionEnd = start + tex.length + (cursor || 0);
        this._updatePreview();
    }

    _applyTemplate(tex) {
        this._input.value = tex;
        this._input.focus();
        this._input.selectionStart = this._input.selectionEnd = tex.length;
        this._updatePreview();
    }

    _confirm() {
        const tex = this._input.value.trim();
        if (!tex) { this.close(); return; }
        const formula = '$' + tex + '$';
        if (this._target) {
            const start = this._target.selectionStart || this._target.value.length;
            const val = this._target.value;
            this._target.value = val.substring(0, start) + formula + val.substring(start);
            this._target.selectionStart = this._target.selectionEnd = start + formula.length;
            this._target.dispatchEvent(new Event('input', { bubbles: true }));
        }
        if (typeof this._onInsert === 'function') this._onInsert(formula);
        this.close();
    }

    _showSymCat(grid, cat) {
        grid.innerHTML = '';
        RE_MATH_SYMBOLS[cat].forEach(sym => {
            const btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 're-math-item';
            btn.textContent = sym.label;
            btn.title = sym.tex;
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                this._insertSymbol(sym.tex, sym.cursor || 0);
            });
            grid.appendChild(btn);
        });
    }
}

function openMathEditor(textarea, callback) {
    new MathFormulaEditor().open(textarea, callback);
}

// ========== 全局渲染函数 ==========
const RE_FONT_MAP = {};
RE_FONTS.forEach(f => { if (f.value) RE_FONT_MAP[f.label] = f.value; });

function _reEsc(text) {
    const d = document.createElement('div');
    d.textContent = text;
    return d.innerHTML;
}

function renderRichContent(text) {
    if (!text) return '';

    // 1. 先提取公式，避免 HTML 转义破坏 LaTeX
    const formulas = [];
    let raw = text.replace(/\$([^$\n]+?)\$/g, function(m, tex) {
        const idx = formulas.length;
        formulas.push(tex);
        return '\x00MATH' + idx + '\x00';
    });

    // 2. HTML 转义
    let h = _reEsc(raw);

    // 3. 图片标签 [img:url]
    h = h.replace(/\[img:(\/static\/uploads\/[^\]]+)\]/g,
        '<img src="$1" class="max-w-full rounded-lg border border-slate-200 my-2 cursor-pointer" style="max-height:400px" onclick="window.open(this.src)">');

    // 4. 还原公式并用 KaTeX 渲染
    h = h.replace(/\x00MATH(\d+)\x00/g, function(m, idx) {
        const tex = formulas[parseInt(idx)];
        if (window.katex) {
            try {
                return katex.renderToString(tex, { throwOnError: false });
            } catch(e) { return '$' + _reEsc(tex) + '$'; }
        }
        // KaTeX 未加载时显示原始公式并标记 class 供后续渲染
        return '<span class="re-pending-math" data-tex="' + _reEsc(tex) + '">$' + _reEsc(tex) + '$</span>';
    });

    // 5. 粗体 **...**
    h = h.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
    // 6. 斜体 *...*
    h = h.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em>$1</em>');
    // 7. 行内代码 `...`
    h = h.replace(/`([^`]+?)`/g, '<code class="re-inline-code">$1</code>');

    // 8. 颜色 [color:#hex]...[/color]
    h = h.replace(/\[color:(#[0-9a-fA-F]{3,8})\]([\s\S]*?)\[\/color\]/g,
        '<span style="color:$1">$2</span>');

    // 9. 字体 [font:name]...[/font]
    h = h.replace(/\[font:([^\]]+)\]([\s\S]*?)\[\/font\]/g, function(m, name, content) {
        const family = RE_FONT_MAP[name];
        if (family) return '<span style="font-family:' + _reEsc(family) + '">' + content + '</span>';
        return content;
    });

    return h;
}

// KaTeX 延迟加载后，重新渲染页面上未渲染的公式
function _reRenderPendingMath() {
    if (!window.katex) return;
    document.querySelectorAll('.re-pending-math').forEach(el => {
        try {
            el.innerHTML = katex.renderToString(el.dataset.tex, { throwOnError: false });
            el.classList.remove('re-pending-math');
        } catch(e) {}
    });
}
// 定期检查 KaTeX 是否加载完成
(function _waitKatex() {
    if (window.katex) { _reRenderPendingMath(); return; }
    setTimeout(_waitKatex, 500);
})();
