/**
 * 消息标记插件
 * 在导航栏添加标记图标，点击后在面板左侧贴边展示标记数据列表
 * 每条标记包含：标记内容 + 截止时间
 * 支持从聊天消息右键菜单「生成标记」，调用 AI 分析后保存
 */

const fs = require('fs');
const path = require('path');

module.exports = {
    name: '消息标记',
    description: '智能消息标记助手，支持快速记录待办、设置截止时间、到期高亮提醒，支持从聊天消息一键生成AI标记',
    version: 'dev',
    author: 'zfeng',
    defaultEnabled: false,

    defaultConfig: {},

    // ---- 内部运行参数 ----
    _settings: {
        apiPath: '/api/ai/memo',      // AI 标记生成接口路径
        contextMessageCount: 20,      // 获取最近上下文消息条数
    },

    // ---- 常量 ----
    NAV_ICON_ID: 'ai-memo-nav-icon',
    STYLE_ID: 'ai-memo-styles',
    PANEL_ID: 'ai-memo-panel',
    CONTEXT_MENU_ITEM_CLASS: 'ai-memo-context-menu-item',
    CONFIRM_DIALOG_ID: 'ai-memo-confirm-dialog',

    // ---- 数据文件路径 ----
    _getDataPath() {
        try {
            const cacheDir = path.join(__dirname, 'cache');
            if (!fs.existsSync(cacheDir)) {
                fs.mkdirSync(cacheDir, { recursive: true });
            }
            return path.join(cacheDir, 'ai-memo-data.json');
        } catch (e) {
            return null;
        }
    },

    // ---- 加载标记数据 ----
    _loadMemos() {
        const dataPath = this._getDataPath();
        if (!dataPath) return [];
        try {
            if (fs.existsSync(dataPath)) {
                const data = fs.readFileSync(dataPath, 'utf-8');
                return JSON.parse(data);
            }
        } catch (e) {
            console.error('[消息标记] 加载数据失败:', e);
        }
        return [];
    },

    // ---- 保存标记数据 ----
    _saveMemos(memos) {
        const dataPath = this._getDataPath();
        if (!dataPath) return;
        try {
            fs.writeFileSync(dataPath, JSON.stringify(memos, null, 2), 'utf-8');
        } catch (e) {
            console.error('[消息标记] 保存数据失败:', e);
        }
    },

    // ---- 生成唯一 ID ----
    _genId() {
        return Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
    },

    // ---- 导航栏图标 SVG（记事本/标记样式） ----
    _getNavIconSvg(color) {
        return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="${color}"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1s-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/></svg>`;
    },

    _getNavIconBase64(color) {
        return btoa(this._getNavIconSvg(color));
    },

    // ---- 注入样式（从外部 styles.css 文件加载） ----
    _injectStyles() {
        if (document.getElementById(this.STYLE_ID)) return;
        try {
            const cssPath = path.join(__dirname, 'styles.css');
            const cssContent = fs.readFileSync(cssPath, 'utf-8');
            const style = document.createElement('style');
            style.id = this.STYLE_ID;
            style.textContent = cssContent;
            document.head.appendChild(style);
        } catch (e) {
            console.error('[消息标记] 加载样式文件失败:', e);
        }
    },

    // ---- 移除样式 ----
    _removeStyles() {
        const el = document.getElementById(this.STYLE_ID);
        if (el) el.remove();
    },

    // ---- 判断是否过期 ----
    _isOverdue(deadline) {
        if (!deadline) return false;
        return new Date(deadline) < new Date();
    },

    // ---- 格式化截止时间 ----
    _formatDeadline(deadline) {
        if (!deadline) return '';
        const d = new Date(deadline);
        const now = new Date();
        const diff = d - now;

        const pad = n => String(n).padStart(2, '0');
        const dateStr = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;

        if (diff < 0) {
            return `已过期 · ${dateStr}`;
        }

        const hours = Math.floor(diff / 3600000);
        if (hours < 1) {
            const mins = Math.floor(diff / 60000);
            return `${mins} 分钟后到期`;
        }
        if (hours < 24) {
            return `${hours} 小时后到期`;
        }
        const days = Math.floor(hours / 24);
        if (days <= 7) {
            return `${days} 天后到期`;
        }
        return dateStr;
    },

    // ---- 创建面板 ----
    _createPanel(instance) {
        const panel = document.createElement('div');
        panel.id = this.PANEL_ID;

        panel.innerHTML = `
            <div class="memo-header">
                <div class="memo-header-left">
                    <span class="memo-header-icon">📋</span>
                    <span class="memo-header-title">消息标记</span>
                    <span class="memo-header-count" id="memo-count">0</span>
                </div>
                <div class="memo-header-actions">
                    <button class="memo-header-btn" id="memo-close-btn" title="关闭">✕</button>
                </div>
            </div>
            <div class="memo-add-area">
                <div class="memo-add-row">
                    <textarea class="memo-input" id="memo-content-input" placeholder="✏️ 输入标记内容..." rows="2"></textarea>
                    <div class="memo-add-bottom">
                        <input type="datetime-local" class="memo-deadline-input" id="memo-deadline-input">
                        <button class="memo-add-btn" id="memo-add-btn">添加</button>
                    </div>
                </div>
            </div>
            <div class="memo-list-wrapper" id="memo-list-wrapper">
                <div class="memo-empty" id="memo-empty">
                    <div class="memo-empty-icon">📝</div>
                    <div class="memo-empty-text">暂无标记，添加一条吧</div>
                </div>
            </div>
        `;

        document.body.appendChild(panel);
        instance.panel = panel;

        // 绑定事件
        this._bindPanelEvents(instance);

        return panel;
    },

    // ---- 绑定面板事件 ----
    _bindPanelEvents(instance) {
        const panel = instance.panel;
        const self = this;

        // 关闭
        panel.querySelector('#memo-close-btn').addEventListener('click', () => {
            self._togglePanel(instance, false);
        });

        // 添加备忘
        panel.querySelector('#memo-add-btn').addEventListener('click', () => {
            self._addMemo(instance);
        });

        // 回车快速添加
        panel.querySelector('#memo-content-input').addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                self._addMemo(instance);
            }
        });

        // 设置默认截止时间为明天此刻
        const deadlineInput = panel.querySelector('#memo-deadline-input');
        const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
        const pad = n => String(n).padStart(2, '0');
        deadlineInput.value = `${tomorrow.getFullYear()}-${pad(tomorrow.getMonth() + 1)}-${pad(tomorrow.getDate())}T${pad(tomorrow.getHours())}:${pad(tomorrow.getMinutes())}`;
    },

    // ---- 添加标记 ----
    _addMemo(instance) {
        const contentInput = instance.panel.querySelector('#memo-content-input');
        const deadlineInput = instance.panel.querySelector('#memo-deadline-input');
        const content = contentInput.value.trim();

        if (!content) {
            contentInput.focus();
            contentInput.style.borderColor = '#e74c3c';
            setTimeout(() => { contentInput.style.borderColor = ''; }, 1000);
            return;
        }

        const memo = {
            id: this._genId(),
            content,
            deadline: deadlineInput.value || null,
            done: false,
            createdAt: new Date().toISOString(),
        };

        instance.memos.unshift(memo);
        this._saveMemos(instance.memos);
        this._renderList(instance);

        // 清空输入
        contentInput.value = '';

        // 重设截止时间为明天
        const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
        const pad = n => String(n).padStart(2, '0');
        deadlineInput.value = `${tomorrow.getFullYear()}-${pad(tomorrow.getMonth() + 1)}-${pad(tomorrow.getDate())}T${pad(tomorrow.getHours())}:${pad(tomorrow.getMinutes())}`;

        contentInput.focus();
        this._updateBadge(instance);
        console.log('[消息标记] ✅ 添加标记:', memo.content);
    },

    // ---- 直接添加标记（从 AI 生成结果直接保存，无需 UI 输入） ----
    _addMemoDirectly(instance, { content, deadline, initiator }) {
        const memo = {
            id: this._genId(),
            content,
            deadline: deadline || null,
            initiator: initiator || null,
            done: false,
            createdAt: new Date().toISOString(),
            source: 'ai-generated',
        };

        instance.memos.unshift(memo);
        this._saveMemos(instance.memos);
        this._renderList(instance);
        this._updateBadge(instance);
        console.log('[消息标记] ✅ AI 生成标记已保存:', memo.content);
    },

    // ---- 删除标记 ----
    _deleteMemo(instance, memoId) {
        instance.memos = instance.memos.filter(m => m.id !== memoId);
        this._saveMemos(instance.memos);
        this._renderList(instance);
        this._updateBadge(instance);
        console.log('[消息标记] 🗑 删除标记:', memoId);
    },

    // ---- 切换完成状态 ----
    _toggleDone(instance, memoId) {
        const memo = instance.memos.find(m => m.id === memoId);
        if (memo) {
            memo.done = !memo.done;
            this._saveMemos(instance.memos);
            this._renderList(instance);
            this._updateBadge(instance);
        }
    },

    // ---- 编辑备忘（内联编辑模式） ----
    _editMemo(instance, memoId, itemEl) {
        const memo = instance.memos.find(m => m.id === memoId);
        if (!memo) return;
        const self = this;

        // 设置截止时间输入的值
        const deadlineVal = memo.deadline || '';

        itemEl.classList.add('memo-item-editing');
        itemEl.innerHTML = `
            <textarea class="memo-edit-textarea" rows="3">${self._escapeHtml(memo.content).replace(/<br>/g, '\n')}</textarea>
            <div class="memo-edit-row">
                <div class="memo-edit-field">
                    <span class="memo-edit-label">⏰ 截止</span>
                    <input type="datetime-local" class="memo-edit-input" id="memo-edit-deadline" value="${deadlineVal}">
                </div>
                <div class="memo-edit-field">
                    <span class="memo-edit-label">👤 发起人</span>
                    <input type="text" class="memo-edit-input" id="memo-edit-initiator" value="${self._escapeHtml(memo.initiator || '')}" placeholder="无">
                </div>
            </div>
            <div class="memo-edit-actions">
                <button class="memo-edit-btn memo-edit-btn-cancel">取消</button>
                <button class="memo-edit-btn memo-edit-btn-save">保存</button>
            </div>
        `;

        const textarea = itemEl.querySelector('.memo-edit-textarea');
        textarea.focus();
        // 光标放到末尾
        textarea.selectionStart = textarea.value.length;

        // 保存
        itemEl.querySelector('.memo-edit-btn-save').addEventListener('click', (e) => {
            e.stopPropagation();
            const newContent = textarea.value.trim();
            if (!newContent) {
                textarea.style.borderColor = '#e74c3c';
                textarea.focus();
                setTimeout(() => { textarea.style.borderColor = ''; }, 1000);
                return;
            }
            memo.content = newContent;
            memo.deadline = itemEl.querySelector('#memo-edit-deadline').value || null;
            memo.initiator = itemEl.querySelector('#memo-edit-initiator').value.trim() || null;
            self._saveMemos(instance.memos);
            self._renderList(instance);
            self._updateBadge(instance);
            console.log('[消息标记] ✏️ 标记已更新:', memo.id);
        });

        // 取消
        itemEl.querySelector('.memo-edit-btn-cancel').addEventListener('click', (e) => {
            e.stopPropagation();
            self._renderList(instance);
        });
    },

    // ---- 渲染列表 ----
    _renderList(instance) {
        const wrapper = instance.panel.querySelector('#memo-list-wrapper');
        const emptyEl = instance.panel.querySelector('#memo-empty');
        const countEl = instance.panel.querySelector('#memo-count');

        const activeMemos = instance.memos.filter(m => !m.done);
        const doneMemos = instance.memos.filter(m => m.done);
        const allMemos = [...activeMemos, ...doneMemos];

        countEl.textContent = instance.memos.length;

        if (instance.memos.length === 0) {
            wrapper.innerHTML = `
                <div class="memo-empty">
                    <div class="memo-empty-icon">📝</div>
                    <div class="memo-empty-text">暂无标记，添加一条吧</div>
                </div>
            `;
            return;
        }

        const self = this;
        wrapper.innerHTML = '';

        allMemos.forEach(memo => {
            const isOverdue = !memo.done && self._isOverdue(memo.deadline);
            const item = document.createElement('div');
            item.className = 'memo-item' + (isOverdue ? ' overdue' : '') + (memo.done ? ' done' : '');
            item.dataset.id = memo.id;

            const deadlineDisplay = memo.deadline ? self._formatDeadline(memo.deadline) : '无截止时间';
            const deadlineIcon = isOverdue ? '⚠️' : '⏰';
            const sourceTag = memo.source === 'ai-generated' ? '<span class="memo-ai-tag">🤖 AI</span>' : '';
            const initiatorTag = memo.initiator ? `<span class="memo-initiator-tag">👤 ${self._escapeHtml(memo.initiator)}</span>` : '';

            item.innerHTML = `
                <div class="memo-item-content">${self._escapeHtml(memo.content)}</div>
                <div class="memo-item-footer">
                    <div class="memo-item-deadline">
                        <span class="memo-item-deadline-icon">${deadlineIcon}</span>
                        <span>${deadlineDisplay}</span>
                        ${initiatorTag}
                        ${sourceTag}
                    </div>
                    <div class="memo-item-actions">
                        <button class="memo-action-btn" data-action="edit" title="编辑">✏️</button>
                        <button class="memo-action-btn" data-action="toggle" title="${memo.done ? '恢复' : '完成'}">
                            ${memo.done ? '↩️' : '✅'}
                        </button>
                        <button class="memo-action-btn danger" data-action="delete" title="删除">🗑</button>
                    </div>
                </div>
            `;

            // 编辑
            item.querySelector('[data-action="edit"]').addEventListener('click', (e) => {
                e.stopPropagation();
                self._editMemo(instance, memo.id, item);
            });

            // 完成/恢复
            item.querySelector('[data-action="toggle"]').addEventListener('click', (e) => {
                e.stopPropagation();
                self._toggleDone(instance, memo.id);
            });

            // 删除
            item.querySelector('[data-action="delete"]').addEventListener('click', (e) => {
                e.stopPropagation();
                self._deleteMemo(instance, memo.id);
            });

            wrapper.appendChild(item);
        });
    },

    // ---- HTML 转义 ----
    _escapeHtml(text) {
        return text
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/\n/g, '<br>');
    },

    // ---- 切换面板 ----
    _togglePanel(instance, forceState) {
        const panel = instance.panel;
        if (!panel) return;

        const targetState = typeof forceState === 'boolean' ? forceState : !instance.isOpen;
        instance.isOpen = targetState;

        if (targetState) {
            panel.classList.add('memo-visible');
            this._renderList(instance);
        } else {
            panel.classList.remove('memo-visible');
        }
    },

    // ---- 更新导航徽标 ----
    _updateBadge(instance) {
        const badge = instance.navIcon?.querySelector('.memo-nav-badge');
        if (!badge) return;

        const overdueCount = instance.memos.filter(m => !m.done && this._isOverdue(m.deadline)).length;
        badge.style.display = overdueCount > 0 ? 'block' : 'none';
    },

    // ---- 注册导航栏图标 ----
    _registerNavIcon(instance) {
        const CHECK_INTERVAL = 1000;
        const MAX_ATTEMPTS = 60;
        let attempts = 0;
        const self = this;

        const checkAndAddIcon = () => {
            if (document.getElementById(self.NAV_ICON_ID)) return;

            const navTab = document.querySelector('body > div.rong-im > div > div.rong-nav > ul.rong-nav-tab');
            if (!navTab) {
                attempts++;
                if (attempts < MAX_ATTEMPTS) {
                    setTimeout(checkAndAddIcon, CHECK_INTERVAL);
                }
                return;
            }

            const navItem = document.createElement('li');
            navItem.id = self.NAV_ICON_ID;
            navItem.className = 'rong-nav-tab-item';
            navItem.style.position = 'relative';
            const iconColor = window.PluginTheme ? window.PluginTheme.getNavIconColor() : '#808CA4';
            navItem.innerHTML = `
                <em class="item-content" style="cursor: pointer;">
                    <span class="rong-nav-icon" style="
                        background-image: url('data:image/svg+xml;base64,${self._getNavIconBase64(iconColor)}');
                    "></span>
                    <span class="rong-nav-icon hover" style="
                        background-image: url('data:image/svg+xml;base64,${self._getNavIconBase64('#3A6EE7')}');
                    "></span>
                    <span class="rong-nav-text">消息标记</span>
                </em>
                <div class="memo-nav-badge"></div>
            `;

            // 点击切换面板
            navItem.addEventListener('click', (e) => {
                e.stopPropagation();
                self._togglePanel(instance);
            });

            // 插入到插件图标后面
            const pluginNavIcon = document.getElementById('plugin-manager-nav-icon');
            if (pluginNavIcon && pluginNavIcon.nextSibling) {
                navTab.insertBefore(navItem, pluginNavIcon.nextSibling);
            } else if (pluginNavIcon) {
                navTab.appendChild(navItem);
            } else {
                navTab.appendChild(navItem);
            }

            instance.navIcon = navItem;
            self._updateBadge(instance);
            console.log('[消息标记] ✅ 导航图标已添加');
        };

        checkAndAddIcon();
    },

    // ---- 点击外部关闭面板 ----
    _setupOutsideClick(instance) {
        const self = this;
        const handler = (e) => {
            if (!instance.isOpen) return;
            const panel = instance.panel;
            const navIcon = instance.navIcon;
            if (panel && !panel.contains(e.target) && navIcon && !navIcon.contains(e.target)) {
                self._togglePanel(instance, false);
            }
        };
        document.addEventListener('click', handler);
        instance._outsideClickHandler = handler;
    },

    // ---- 定时刷新（更新到期状态） ----
    _startRefreshTimer(instance) {
        const self = this;
        instance._refreshTimer = setInterval(() => {
            if (instance.isOpen) {
                self._renderList(instance);
            }
            self._updateBadge(instance);
        }, 60 * 1000); // 每分钟刷新一次
    },

    // ======================== 右键菜单：生成备忘 ========================

    /**
     * 获取全局服务器地址（同 group-ai-summary 的方式）
     */
    _getServerUrl() {
        try {
            if (window.PluginManager && typeof window.PluginManager.getServerUrl === 'function') {
                return window.PluginManager.getServerUrl() || null;
            }
        } catch (e) {
            console.warn('[消息标记] 获取服务器地址失败:', e);
        }
        return null;
    },

    /**
     * 获取当前登录用户ID
     */
    _getCurrentUserId() {
        try {
            if (window.RongIM && window.RongIM.instance) {
                const auth = window.RongIM.instance.auth;
                if (auth && auth.id) return auth.id;
            }
        } catch (e) {}
        try {
            const client = window.RongIMLib && window.RongIMLib.RongIMClient.getInstance();
            if (client && typeof client.getCurrentUserId === 'function') {
                return client.getCurrentUserId();
            }
        } catch (e) {}
        return null;
    },

    /**
     * 获取最近聊天记录作为上下文
     */
    _fetchContextMessages(conversationType, targetId) {
        return new Promise((resolve) => {
            try {
                const RongIMClient = window.RongIMLib && window.RongIMLib.RongIMClient;
                if (!RongIMClient) {
                    console.warn('[消息标记] RongIMClient 未找到，跳过上下文获取');
                    resolve([]);
                    return;
                }

                const count = this._settings.contextMessageCount;

                RongIMClient.getInstance().getHistoryMessages(
                    conversationType,
                    targetId,
                    0,
                    count,
                    {
                        onSuccess: (messageList) => {
                            console.log(`[消息标记] 获取到 ${messageList.length} 条上下文消息`);
                            resolve(messageList);
                        },
                        onError: (errorCode) => {
                            console.warn('[消息标记] 获取本地历史消息失败:', errorCode);
                            // 尝试从服务器获取
                            RongIMClient.getInstance().getRemoteHistoryMessages(
                                conversationType,
                                targetId,
                                0,
                                count,
                                {
                                    onSuccess: (messageList) => {
                                        console.log(`[消息标记] 从服务器获取到 ${messageList.length} 条上下文消息`);
                                        resolve(messageList);
                                    },
                                    onError: () => {
                                        resolve([]);
                                    }
                                }
                            );
                        }
                    }
                );
            } catch (e) {
                console.warn('[消息标记] 获取上下文消息异常:', e);
                resolve([]);
            }
        });
    },

    /**
     * 批量解析用户 ID 为真实姓名
     */
    async _resolveUserNames(messages) {
        const userIds = [...new Set(messages.map(m => m.senderUserId).filter(Boolean))];
        const nameMap = new Map();

        const RongIM = window.RongIM;
        if (!RongIM || !RongIM.dataModel || !RongIM.dataModel.User) {
            userIds.forEach(id => nameMap.set(id, id));
            return nameMap;
        }

        const resolveOne = (userId) => new Promise((resolve) => {
            try {
                RongIM.dataModel.User.get(userId, (err, user) => {
                    if (err || !user) {
                        resolve({ id: userId, name: userId });
                    } else {
                        resolve({ id: userId, name: user.name || user.alias || userId });
                    }
                });
            } catch (e) {
                resolve({ id: userId, name: userId });
            }
        });

        const results = await Promise.all(userIds.map(resolveOne));
        results.forEach(({ id, name }) => nameMap.set(id, name));
        return nameMap;
    },

    /**
     * 构建上下文消息文本（带真实姓名和时间）
     */
    _buildContextText(messages, userNameMap) {
        const textMessages = messages
            .filter(msg => {
                const textTypes = ['TextMessage', 'ReferenceMessage'];
                return textTypes.includes(msg.messageType) && msg.content;
            })
            .map(msg => {
                const sender = userNameMap.get(msg.senderUserId) || msg.senderUserId || '未知用户';
                const time = new Date(msg.sentTime).toLocaleString('zh-CN');
                let text = '';

                if (msg.messageType === 'TextMessage') {
                    text = msg.content.content || '';
                } else if (msg.messageType === 'ReferenceMessage') {
                    text = msg.content.text || '';
                }

                text = text.replace(/<[^>]+>/g, '').trim();
                if (!text) return null;

                return `[${time}] ${sender}: ${text}`;
            })
            .filter(Boolean);

        return textMessages.join('\n');
    },

    /**
     * 监听右键菜单出现，注入「生成标记」菜单项
     */
    _setupContextMenuObserver(instance) {
        const self = this;

        // 记录当前右键点击的消息元素
        document.addEventListener('contextmenu', (e) => {
            const msgEl = e.target.closest('.rong-conversation-one');
            if (msgEl) {
                const isTextMsg = msgEl.classList.contains('rong-textmessage') || msgEl.querySelector('.rong-textmessage') !== null;
                const isRefMsg = msgEl.classList.contains('rong-referencemessage') || msgEl.querySelector('.rong-referencemessage') !== null;
                if (isTextMsg || isRefMsg) {
                    instance._lastContextTarget = msgEl;
                } else {
                    instance._lastContextTarget = null;
                }
            } else {
                instance._lastContextTarget = null;
            }
        }, true);

        // 使用 MutationObserver 监听 .rong-menu 的出现
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType !== 1) continue;
                    const menu = node.classList?.contains('rong-menu') ? node : node.querySelector?.('.rong-menu');
                    if (menu) {
                        self._injectContextMenuItem(instance, menu);
                    }
                }
            }
        });

        observer.observe(document.body, { childList: true, subtree: true });
        instance._contextMenuObserver = observer;

        console.log('[消息标记] 🔍 右键菜单监听已启动');
    },

    /**
     * 在右键菜单中注入「生成标记」选项
     */
    _injectContextMenuItem(instance, menu) {
        if (!instance._lastContextTarget) return;
        if (menu.querySelector('.' + this.CONTEXT_MENU_ITEM_CLASS)) return;

        const self = this;

        // 找到菜单内的 <ul>，插入到里面
        const ul = menu.querySelector('ul');
        const container = ul || menu;

        // 分隔线 — 与原生分隔线结构一致
        const separator = document.createElement('li');
        separator.className = 'rong-menu-link';
        separator.innerHTML = '<span class="rong-menu-separator"></span>';

        // 菜单项 — 与原生菜单项结构一致：<li class="rong-menu-link"><a>文字</a></li>
        const menuItem = document.createElement('li');
        menuItem.className = 'rong-menu-link ' + this.CONTEXT_MENU_ITEM_CLASS;
        menuItem.innerHTML = '<a>标记</a>';

        menuItem.addEventListener('click', (e) => {
            e.stopPropagation();
            menu.style.display = 'none';
            setTimeout(() => { menu.remove(); }, 50);

            const messageData = self._extractMessageFromTarget(instance);
            if (messageData) {
                self._generateMemo(instance, messageData);
            } else {
                console.warn('[消息标记] 未能提取消息内容');
            }
        });

        container.appendChild(separator);
        container.appendChild(menuItem);
    },

    /**
     * 从右键点击目标提取消息内容
     */
    _extractMessageFromTarget(instance) {
        const msgEl = instance._lastContextTarget;
        if (!msgEl) return null;

        try {
            const msgBubble = msgEl.querySelector('.rong-conversation-one-message');
            let messageContent = '';

            if (msgBubble) {
                const textEl = msgBubble.querySelector('.ql-editor') || msgBubble;
                messageContent = textEl.innerText || textEl.textContent || '';
            }

            messageContent = messageContent.trim();
            if (!messageContent) return null;

            const usernameEl = msgEl.querySelector('.rong-conversation-one-username');
            let senderName = '';
            if (usernameEl) {
                senderName = usernameEl.innerText || usernameEl.textContent || '';
                senderName = senderName.trim();
            }

            return {
                messageContent,
                senderName,
            };
        } catch (e) {
            console.error('[消息标记] 提取消息失败:', e);
            return null;
        }
    },

    /**
     * 调用 AI 接口生成标记（含上下文聊天记录）
     */
    async _generateMemo(instance, messageData) {
        const self = this;

        // 显示确认弹框（加载状态）
        self._showConfirmDialog(instance, {
            loading: true,
            messageContent: messageData.messageContent,
        });

        try {
            // 获取当前会话的最近聊天记录作为上下文
            const route = self._parseRoute();
            let contextMessages = '';
            if (route) {
                try {
                    const messages = await self._fetchContextMessages(route.conversationType, route.targetId);
                    if (messages.length > 0) {
                        const userNameMap = await self._resolveUserNames(messages);
                        contextMessages = self._buildContextText(messages, userNameMap);
                        console.log(`[消息标记] 已构建 ${messages.length} 条上下文消息`);
                    }
                } catch (e) {
                    console.warn('[消息标记] 获取上下文失败，将仅使用目标消息:', e);
                }
            }

            // 将上下文附加到 messageData
            messageData.contextMessages = contextMessages;

            const result = await self._callMemoAPI(messageData);
            // 更新弹框为结果状态
            self._showConfirmDialog(instance, {
                loading: false,
                messageContent: messageData.messageContent,
                result: result,
                messageData: messageData,
            });
        } catch (error) {
            console.error('[消息标记] AI 标记生成失败:', error);
            self._showConfirmDialog(instance, {
                loading: false,
                error: error.message || '请求失败',
                messageContent: messageData.messageContent,
                messageData: messageData,
            });
        }
    },

    /**
     * 调用后端 AI 标记接口
     */
    async _callMemoAPI(messageData) {
        const serverUrl = this._getServerUrl();
        if (!serverUrl) {
            throw new Error('服务器地址未配置，请在插件管理中心 → 设置中配置服务器地址');
        }
        const apiEndpoint = serverUrl.replace(/\/+$/, '') + this._settings.apiPath;
        console.log('[消息标记] 请求 AI 标记接口:', apiEndpoint);

        const route = this._parseRoute();

        const response = await fetch(apiEndpoint, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                ...(this._getCurrentUserId() ? { 'X-User-Id': this._getCurrentUserId() } : {}),
            },
            body: JSON.stringify({
                messageContent: messageData.messageContent,
                senderName: messageData.senderName,
                contextMessages: messageData.contextMessages || '',
                conversationType: route?.conversationType || null,
                targetId: route?.targetId || null,
            }),
        });

        if (!response.ok) {
            const errData = await response.json().catch(() => ({}));
            throw new Error(errData.error || `接口返回错误: ${response.status}`);
        }

        return await response.json();
    },

    /**
     * 解析当前路由
     */
    _parseRoute() {
        const hash = window.location.hash || '';
        const match = hash.match(/conversation\/(\d+)\/([^/?]+)/);
        if (!match) return null;
        return {
            conversationType: parseInt(match[1], 10),
            targetId: match[2],
        };
    },

    /**
     * 显示确认弹框
     */
    _showConfirmDialog(instance, options) {
        const self = this;

        // 移除已有弹框
        const existing = document.getElementById(this.CONFIRM_DIALOG_ID);
        if (existing) existing.remove();

        // 创建遮罩 + 弹框
        const overlay = document.createElement('div');
        overlay.id = this.CONFIRM_DIALOG_ID;
        overlay.className = 'memo-confirm-overlay';

        const dialog = document.createElement('div');
        dialog.className = 'memo-confirm-dialog';

        if (options.loading) {
            // 加载状态
            dialog.innerHTML = `
                <div class="memo-confirm-header">
                    <span class="memo-confirm-header-icon">🤖</span>
                    <span class="memo-confirm-header-title">AI 生成标记中...</span>
                </div>
                <div class="memo-confirm-body">
                    <div class="memo-confirm-source">
                        <div class="memo-confirm-source-label">原始消息</div>
                        <div class="memo-confirm-source-text">${self._escapeHtml(options.messageContent).slice(0, 200)}</div>
                    </div>
                    <div class="memo-confirm-loading">
                        <div class="memo-confirm-spinner"></div>
                        <div class="memo-confirm-loading-text">AI 正在分析消息内容...</div>
                    </div>
                </div>
                <div class="memo-confirm-footer">
                    <button class="memo-confirm-btn memo-confirm-btn-cancel" id="memo-confirm-cancel">取消</button>
                </div>
            `;
        } else if (options.error) {
            // 错误状态
            dialog.innerHTML = `
                <div class="memo-confirm-header memo-confirm-header-error">
                    <span class="memo-confirm-header-icon">⚠️</span>
                    <span class="memo-confirm-header-title">生成失败</span>
                </div>
                <div class="memo-confirm-body">
                    <div class="memo-confirm-source">
                        <div class="memo-confirm-source-label">原始消息</div>
                        <div class="memo-confirm-source-text">${self._escapeHtml(options.messageContent).slice(0, 200)}</div>
                    </div>
                    <div class="memo-confirm-error">
                        <div class="memo-confirm-error-icon">❌</div>
                        <div class="memo-confirm-error-text">${self._escapeHtml(options.error)}</div>
                    </div>
                </div>
                <div class="memo-confirm-footer">
                    <button class="memo-confirm-btn memo-confirm-btn-cancel" id="memo-confirm-cancel">关闭</button>
                    <button class="memo-confirm-btn memo-confirm-btn-retry" id="memo-confirm-retry">🔄 重新生成</button>
                </div>
            `;
        } else {
            // 结果状态
            const result = options.result;
            const deadlineDisplay = result.deadline
                ? `<input type="datetime-local" class="memo-confirm-deadline-input" id="memo-confirm-deadline" value="${result.deadline}">`
                : `<input type="datetime-local" class="memo-confirm-deadline-input" id="memo-confirm-deadline" placeholder="无截止时间">`;

            dialog.innerHTML = `
                <div class="memo-confirm-header memo-confirm-header-success">
                    <span class="memo-confirm-header-icon">✨</span>
                    <span class="memo-confirm-header-title">AI 标记生成完成</span>
                </div>
                <div class="memo-confirm-body">
                    <div class="memo-confirm-source">
                        <div class="memo-confirm-source-label">原始消息</div>
                        <div class="memo-confirm-source-text">${self._escapeHtml(options.messageContent).slice(0, 200)}</div>
                    </div>
                    <div class="memo-confirm-result">
                        <div class="memo-confirm-result-label">📋 生成的标记内容</div>
                        <textarea class="memo-confirm-result-textarea" id="memo-confirm-content" rows="4">${result.content || ''}</textarea>
                    </div>
                    <div class="memo-confirm-meta-row">
                        <div class="memo-confirm-meta-item">
                            <span class="memo-confirm-meta-label">👤 发起人</span>
                            <input type="text" class="memo-confirm-meta-input" id="memo-confirm-initiator" value="${self._escapeHtml(result.initiator || '')}" placeholder="消息发送者">
                        </div>
                        <div class="memo-confirm-meta-item">
                            <span class="memo-confirm-meta-label">⏰ 截止时间</span>
                            ${deadlineDisplay}
                        </div>
                    </div>
                </div>
                <div class="memo-confirm-footer">
                    <button class="memo-confirm-btn memo-confirm-btn-cancel" id="memo-confirm-cancel">取消</button>
                    <button class="memo-confirm-btn memo-confirm-btn-retry" id="memo-confirm-retry">🔄 重新生成</button>
                    <button class="memo-confirm-btn memo-confirm-btn-confirm" id="memo-confirm-ok">✅ 确认保存</button>
                </div>
            `;
        }

        overlay.appendChild(dialog);
        document.body.appendChild(overlay);

        // 入场动画
        requestAnimationFrame(() => {
            overlay.classList.add('memo-confirm-visible');
        });

        // --- 绑定事件 ---

        // 取消按钮
        const cancelBtn = overlay.querySelector('#memo-confirm-cancel');
        if (cancelBtn) {
            cancelBtn.addEventListener('click', () => {
                self._closeConfirmDialog();
            });
        }

        // 重新生成按钮
        const retryBtn = overlay.querySelector('#memo-confirm-retry');
        if (retryBtn) {
            retryBtn.addEventListener('click', () => {
                self._closeConfirmDialog();
                if (options.messageData) {
                    self._generateMemo(instance, options.messageData);
                } else {
                    // 从原始消息重新构造
                    self._generateMemo(instance, {
                        messageContent: options.messageContent,
                        senderName: '',
                    });
                }
            });
        }

        // 确认保存按钮
        const okBtn = overlay.querySelector('#memo-confirm-ok');
        if (okBtn) {
            okBtn.addEventListener('click', () => {
                const contentEl = overlay.querySelector('#memo-confirm-content');
                const deadlineEl = overlay.querySelector('#memo-confirm-deadline');
                const initiatorEl = overlay.querySelector('#memo-confirm-initiator');
                const content = contentEl ? contentEl.value.trim() : '';
                const deadline = deadlineEl ? deadlineEl.value : null;
                const initiator = initiatorEl ? initiatorEl.value.trim() : '';

                if (!content) {
                    contentEl.style.borderColor = '#e74c3c';
                    contentEl.focus();
                    setTimeout(() => { contentEl.style.borderColor = ''; }, 1000);
                    return;
                }

                // 保存到标记列表
                self._addMemoDirectly(instance, { content, deadline, initiator });
                self._closeConfirmDialog();

                // 打开标记面板让用户看到新增的标记
                self._togglePanel(instance, true);
            });
        }

        // 点击遮罩关闭
        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) {
                self._closeConfirmDialog();
            }
        });

        // ESC 关闭
        const escHandler = (e) => {
            if (e.key === 'Escape') {
                self._closeConfirmDialog();
                document.removeEventListener('keydown', escHandler);
            }
        };
        document.addEventListener('keydown', escHandler);
    },

    /**
     * 关闭确认弹框
     */
    _closeConfirmDialog() {
        const overlay = document.getElementById(this.CONFIRM_DIALOG_ID);
        if (!overlay) return;
        overlay.classList.remove('memo-confirm-visible');
        setTimeout(() => {
            overlay.remove();
        }, 200);
    },

    // ========== 生命周期 ==========

    async init(config, pluginManager) {
        console.log('[消息标记] 🚀 初始化消息标记插件...');

        const instance = {
            config,
            memos: [],
            panel: null,
            navIcon: null,
            isOpen: false,
            _outsideClickHandler: null,
            _refreshTimer: null,
            _contextMenuObserver: null,
            _lastContextTarget: null,
        };

        // 加载已有数据
        instance.memos = this._loadMemos();
        console.log(`[消息标记] 📦 已加载 ${instance.memos.length} 条标记`);

        // 注入样式
        this._injectStyles();

        // 创建面板（初始隐藏）
        this._createPanel(instance);

        // 注册导航栏图标
        this._registerNavIcon(instance);

        // 点击外部关闭
        this._setupOutsideClick(instance);

        // 定时刷新到期状态
        this._startRefreshTimer(instance);

        // 启动右键菜单监听（生成标记功能）
        this._setupContextMenuObserver(instance);

        console.log('[消息标记] ✅ 插件已启动（含右键菜单生成标记功能）');
        return instance;
    },

    async destroy(instance) {
        console.log('[消息标记] 🔄 销毁消息标记插件...');

        if (instance._outsideClickHandler) {
            document.removeEventListener('click', instance._outsideClickHandler);
            instance._outsideClickHandler = null;
        }

        if (instance._refreshTimer) {
            clearInterval(instance._refreshTimer);
            instance._refreshTimer = null;
        }

        if (instance._contextMenuObserver) {
            instance._contextMenuObserver.disconnect();
            instance._contextMenuObserver = null;
        }

        // 关闭确认弹框
        this._closeConfirmDialog();

        if (instance.panel) {
            instance.panel.remove();
            instance.panel = null;
        }

        if (instance.navIcon) {
            instance.navIcon.remove();
            instance.navIcon = null;
        }

        this._removeStyles();

        console.log('[消息标记] ✅ 插件已销毁');
    }
};
