/**
 * 聊天记录 AI 总结插件
 * 在群聊和单聊会话的 rong-tools 工具栏最左侧添加「AI总结」按钮
 * 支持按周切换日期，获取当天消息并调用外部 AI 接口进行总结
 * 面板下方提供「AI 总结」和「消息记录」两个 Tab
 */

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

module.exports = {
    // 插件元信息
    name: '聊天记录总结',
    description: '在聊天工具栏添加AI总结按钮，支持群聊和单聊，可选择日期获取当天消息生成摘要',
    version: 'dev',
    author: 'zfeng',
    defaultEnabled: false,

    defaultConfig: {},

    _settings: {
        apiPath: '/api/ai/summary',
        apiKey: '',
        messageCount: 200,
        cacheExpiry: 5 * 60 * 1000,
    },

    /**
     * 初始化插件
     */
    async init(config, pluginManager) {
        console.log('[AISummary] 🚀 初始化聊天记录总结插件...');

        const settings = this._settings;

        const instance = {
            config: settings,
            widget: null,
            toolbarBtn: null,
            currentTargetId: null,
            currentConversationType: null,
            summaryCache: new Map(),
            isLoading: false,
            selectedDate: null,
            weekStartDate: null,
            messageDatesCache: new Map(),
            _lastRawMessages: '',
            _lastFormattedRecords: '',
            activeTab: 'summary',
        };

        const self = this;
        const initDOM = () => {
            self.createSummaryWidget(instance);
            self.injectStyles();
            self.observeConversationChange(instance);
            console.log('[AISummary] ✅ 聊天记录总结插件已启动');
        };

        if (document.body) {
            initDOM();
        } else {
            const onReady = () => {
                initDOM();
                document.removeEventListener('DOMContentLoaded', onReady);
            };
            document.addEventListener('DOMContentLoaded', onReady);
            setTimeout(() => {
                if (!instance.widget && document.body) {
                    initDOM();
                }
            }, 3000);
        }

        return instance;
    },

    /**
     * 注入全局样式
     */
    injectStyles() {
        if (document.querySelector('#ai-summary-styles')) return;
        try {
            const cssPath = path.join(__dirname, 'styles.css');
            const cssContent = fs.readFileSync(cssPath, 'utf-8');
            const style = document.createElement('style');
            style.id = 'ai-summary-styles';
            style.textContent = cssContent;
            document.head.appendChild(style);
        } catch (e) {
            console.error('[AISummary] 加载样式文件失败:', e);
        }
    },

    /**
     * 监听会话切换
     */
    observeConversationChange(instance) {
        const self = this;
        const hashHandler = () => { self.syncToolbarButton(instance); };
        window.addEventListener('hashchange', hashHandler);
        instance._hashHandler = hashHandler;

        const observer = new MutationObserver(() => { self.syncToolbarButton(instance); });
        instance._observer = observer;

        const startObserve = () => {
            const app = document.querySelector('#app') || document.body;
            observer.observe(app, { childList: true, subtree: true });
            self.syncToolbarButton(instance);
        };
        setTimeout(startObserve, 2000);
        setTimeout(() => self.syncToolbarButton(instance), 4000);
    },

    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],
        };
    },

    syncToolbarButton(instance) {
        const route = this.parseRoute();
        const toolbar = document.querySelector('.rong-tools');
        if (!toolbar) return;

        const existingBtn = toolbar.querySelector('#rong-tools-ai-summary-btn');

        if (!route || (route.conversationType !== 1 && route.conversationType !== 3)) {
            if (existingBtn) existingBtn.remove();
            instance.currentTargetId = null;
            instance.currentConversationType = null;
            return;
        }

        instance.currentTargetId = route.targetId;
        instance.currentConversationType = route.conversationType;

        if (existingBtn) return;

        const btn = document.createElement('button');
        btn.id = 'rong-tools-ai-summary-btn';
        btn.title = 'AI 聊天总结';

        const makeSvg = (color) => `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="${color}"><path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z"/></svg>`;
        const defaultIcon = btoa(makeSvg(window.PluginTheme ? window.PluginTheme.getNavIconColor() : '#808CA4'));
        const hoverIcon = btoa(makeSvg('#3A6EE7'));

        btn.style.backgroundImage = `url("data:image/svg+xml;base64,${defaultIcon}")`;
        btn.addEventListener('mouseenter', function () {
            this.style.backgroundImage = `url("data:image/svg+xml;base64,${hoverIcon}")`;
            this.style.transform = 'scale(1.15)';
        });
        btn.addEventListener('mouseleave', function () {
            this.style.backgroundImage = `url("data:image/svg+xml;base64,${defaultIcon}")`;
            this.style.transform = 'scale(1)';
        });
        btn.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            this.onButtonClick(instance);
        });

        toolbar.insertBefore(btn, toolbar.firstChild);
        instance.toolbarBtn = btn;
        console.log('[AISummary] 📌 已注入AI总结按钮到工具栏');
    },

    onButtonClick(instance) {
        const widget = instance.widget;
        if (!widget) return;

        if (widget.style.display === 'block') {
            widget.style.display = 'none';
            return;
        }

        widget.style.display = 'block';

        const today = new Date();
        instance.selectedDate = today;
        // 计算本周起始日（周日）
        instance.weekStartDate = this.getWeekStart(today);
        this.updateDateInput(instance);
        this.renderWeekPicker(instance);
        this.switchTab(instance, 'summary');

        if (instance.currentTargetId && instance.currentConversationType) {
            this.loadMessageDates(instance);
        }
    },

    // ======================== UI 面板 ========================

    createSummaryWidget(instance) {
        const widget = document.createElement('div');
        widget.id = 'group-ai-summary-widget';

        widget.innerHTML = `
            <div id="ai-summary-header">
                <div class="ai-summary-header-left">
                    <span class="ai-summary-header-title">聊天记录总结</span>
                </div>
                <div class="ai-summary-header-actions">
                    <button id="ai-summary-close" class="ai-summary-header-btn" title="关闭">✕</button>
                </div>
            </div>
            <div id="ai-summary-body">
                <div id="ai-summary-toolbar">
                    <input type="text" id="ai-summary-date-input" readonly placeholder="选择日期" />
                    <button id="ai-summary-do-summary" class="ai-summary-action-btn ai-summary-action-primary">总结</button>
                    <button id="ai-summary-copy-btn" class="ai-summary-action-btn">复制</button>
                </div>
                <div id="ai-summary-week-picker"></div>
                <div id="ai-summary-calendar-hint">
                    <span class="ai-summary-hint-dot"></span> 绿色表示当天有聊天记录
                </div>
                <div id="ai-summary-hint-text">选择日期后点击"总结"，会读取当前聊天在当天的文本消息。</div>
                <div id="ai-summary-tabs">
                    <div class="ai-summary-tab ai-summary-tab-active" data-tab="summary">AI 总结</div>
                    <div class="ai-summary-tab" data-tab="records">消息记录</div>
                </div>
                <div id="ai-summary-tab-content">
                    <div id="ai-summary-panel-summary" class="ai-summary-panel">
                        <div id="ai-summary-group-info">
                            <div id="ai-summary-group-name"></div>
                            <div id="ai-summary-msg-count"></div>
                        </div>
                        <div id="ai-summary-content">
                            <div class="ai-summary-placeholder">
                                <div class="ai-summary-placeholder-icon">💬</div>
                                <div>选择日期并点击"总结"开始</div>
                            </div>
                        </div>
                        <div id="ai-summary-time"></div>
                    </div>
                    <div id="ai-summary-panel-records" class="ai-summary-panel" style="display:none;">
                        <div id="ai-summary-records-content">
                            <div class="ai-summary-placeholder">
                                <div class="ai-summary-placeholder-icon">📋</div>
                                <div>点击"总结"后可查看当天消息记录</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        `;

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

        this.makeDraggable(widget, widget.querySelector('#ai-summary-header'));
        this.bindWidgetEvents(instance);
    },

    bindWidgetEvents(instance) {
        const widget = instance.widget;
        const self = this;

        // 总结按钮
        widget.querySelector('#ai-summary-do-summary').addEventListener('click', () => {
            if (instance.currentTargetId && instance.currentConversationType && instance.selectedDate) {
                const cacheKey = self.getCacheKey(instance.currentTargetId, instance.selectedDate);
                instance.summaryCache.delete(cacheKey);
                self.triggerSummary(instance, instance.currentConversationType, instance.currentTargetId);
            }
        });

        // 复制按钮（根据当前 tab 复制对应内容）
        widget.querySelector('#ai-summary-copy-btn').addEventListener('click', () => {
            if (instance.activeTab === 'summary') {
                const content = widget.querySelector('#ai-summary-content');
                if (content) {
                    const text = content.innerText || content.textContent;
                    self.copyToClipboard(text, '总结内容已复制到剪贴板');
                }
            } else {
                if (instance._lastRawMessages) {
                    self.copyToClipboard(instance._lastRawMessages, '消息记录已复制到剪贴板');
                } else {
                    self.showToast('暂无消息记录可复制，请先执行总结');
                }
            }
        });

        // 关闭按钮
        widget.querySelector('#ai-summary-close').addEventListener('click', () => {
            widget.style.display = 'none';
        });

        // Tab 切换
        widget.querySelectorAll('.ai-summary-tab').forEach(tab => {
            tab.addEventListener('click', () => {
                self.switchTab(instance, tab.dataset.tab);
            });
        });
    },

    /**
     * 切换 Tab
     */
    switchTab(instance, tabName) {
        instance.activeTab = tabName;
        const widget = instance.widget;

        widget.querySelectorAll('.ai-summary-tab').forEach(t => {
            t.classList.toggle('ai-summary-tab-active', t.dataset.tab === tabName);
        });

        widget.querySelector('#ai-summary-panel-summary').style.display = tabName === 'summary' ? 'block' : 'none';
        widget.querySelector('#ai-summary-panel-records').style.display = tabName === 'records' ? 'block' : 'none';
    },

    copyToClipboard(text, successMsg) {
        if (!text || !text.trim()) {
            this.showToast('暂无内容可复制');
            return;
        }
        try {
            const { clipboard } = require('electron');
            clipboard.writeText(text);
            this.showToast(successMsg || '已复制到剪贴板');
        } catch (e) {
            const textarea = document.createElement('textarea');
            textarea.value = text;
            textarea.style.position = 'fixed';
            textarea.style.opacity = '0';
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            textarea.remove();
            this.showToast(successMsg || '已复制到剪贴板');
        }
    },

    showToast(msg) {
        let toast = document.querySelector('#ai-summary-toast');
        if (!toast) {
            toast = document.createElement('div');
            toast.id = 'ai-summary-toast';
            document.body.appendChild(toast);
        }
        toast.textContent = msg;
        toast.classList.add('ai-summary-toast-show');
        setTimeout(() => {
            toast.classList.remove('ai-summary-toast-show');
        }, 2000);
    },

    // ======================== 周日期选择器 ========================

    /**
     * 获取某日所在周的周日（一周起始）
     */
    getWeekStart(date) {
        const d = new Date(date);
        d.setDate(d.getDate() - d.getDay());
        d.setHours(0, 0, 0, 0);
        return d;
    },

    formatDateStr(d) {
        return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
    },

    getCacheKey(targetId, date) {
        return `${targetId}_${this.formatDateStr(date || new Date())}`;
    },

    updateDateInput(instance) {
        const input = instance.widget.querySelector('#ai-summary-date-input');
        if (input && instance.selectedDate) {
            input.value = this.formatDateStr(instance.selectedDate);
        }
    },

    /**
     * 渲染按周切换的日期选择器
     */
    renderWeekPicker(instance) {
        const container = instance.widget.querySelector('#ai-summary-week-picker');
        if (!container) return;

        const weekStart = instance.weekStartDate || this.getWeekStart(new Date());
        const today = new Date();
        today.setHours(23, 59, 59, 999);
        const todayStr = this.formatDateStr(today);
        const selectedStr = instance.selectedDate ? this.formatDateStr(instance.selectedDate) : '';

        const msgDates = instance.messageDatesCache.get(instance.currentTargetId) || new Set();

        // 周标题：显示月份范围
        const weekEnd = new Date(weekStart);
        weekEnd.setDate(weekEnd.getDate() + 6);
        let titleText = '';
        if (weekStart.getMonth() === weekEnd.getMonth()) {
            titleText = `${weekStart.getFullYear()}年${String(weekStart.getMonth() + 1).padStart(2, '0')}月`;
        } else {
            titleText = `${String(weekStart.getMonth() + 1).padStart(2, '0')}月 - ${String(weekEnd.getMonth() + 1).padStart(2, '0')}月`;
        }

        let html = `
            <div class="ai-week-header">
                <button class="ai-cal-nav" id="ai-week-prev">&lsaquo;</button>
                <span class="ai-cal-title">${titleText}</span>
                <button class="ai-cal-nav" id="ai-week-next">&rsaquo;</button>
            </div>
            <div class="ai-cal-weekdays">
                <span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
            </div>
            <div class="ai-week-days">
        `;

        for (let i = 0; i < 7; i++) {
            const d = new Date(weekStart);
            d.setDate(d.getDate() + i);
            const dateStr = this.formatDateStr(d);
            const isToday = dateStr === todayStr;
            const isSelected = dateStr === selectedStr;
            const hasMsg = msgDates.has(dateStr);
            const isFuture = d > today;

            let cls = 'ai-cal-day';
            if (isToday) cls += ' ai-cal-day-today';
            if (isSelected) cls += ' ai-cal-day-selected';
            if (isFuture) cls += ' ai-cal-day-future';

            html += `<span class="${cls}" data-date="${dateStr}">${d.getDate()}${hasMsg ? '<i class="ai-cal-dot"></i>' : ''}</span>`;
        }

        html += `</div>`;
        container.innerHTML = html;

        // 绑定事件
        const self = this;
        container.querySelector('#ai-week-prev').addEventListener('click', () => {
            const newStart = new Date(weekStart);
            newStart.setDate(newStart.getDate() - 7);
            instance.weekStartDate = newStart;
            self.renderWeekPicker(instance);
            self.loadMessageDates(instance);
        });
        container.querySelector('#ai-week-next').addEventListener('click', () => {
            const newStart = new Date(weekStart);
            newStart.setDate(newStart.getDate() + 7);
            instance.weekStartDate = newStart;
            self.renderWeekPicker(instance);
            self.loadMessageDates(instance);
        });

        container.querySelectorAll('.ai-cal-day[data-date]').forEach(el => {
            if (el.classList.contains('ai-cal-day-future')) return;
            el.addEventListener('click', () => {
                const parts = el.dataset.date.split('-');
                instance.selectedDate = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
                self.updateDateInput(instance);
                self.renderWeekPicker(instance);
            });
        });
    },

    /**
     * 加载当前周有消息的日期
     */
    async loadMessageDates(instance) {
        if (!instance.currentTargetId || !instance.currentConversationType) return;

        const targetId = instance.currentTargetId;
        const conversationType = instance.currentConversationType;
        const weekStart = instance.weekStartDate || this.getWeekStart(new Date());

        const startTime = weekStart.getTime();
        const weekEnd = new Date(weekStart);
        weekEnd.setDate(weekEnd.getDate() + 6);
        weekEnd.setHours(23, 59, 59, 999);
        const endTime = weekEnd.getTime();

        try {
            const messages = await this.fetchMessagesByTimeRange(instance, conversationType, targetId, startTime, endTime);
            // 合并到已有缓存（跨周时保留其他周的绿点数据）
            const existing = instance.messageDatesCache.get(targetId) || new Set();
            messages.forEach(msg => {
                const d = new Date(msg.sentTime);
                existing.add(this.formatDateStr(d));
            });
            instance.messageDatesCache.set(targetId, existing);
            this.renderWeekPicker(instance);
        } catch (e) {
            console.warn('[AISummary] 加载消息日期失败:', e);
        }
    },

    fetchMessagesByTimeRange(instance, conversationType, targetId, startTime, endTime) {
        return new Promise((resolve, reject) => {
            try {
                const RongIMClient = window.RongIMLib && window.RongIMLib.RongIMClient;
                if (!RongIMClient) {
                    reject(new Error('RongIMClient 未找到'));
                    return;
                }

                const count = instance.config.messageCount || 200;

                RongIMClient.getInstance().getRemoteHistoryMessages(
                    conversationType,
                    targetId,
                    endTime + 1,
                    count,
                    {
                        onSuccess: (messageList, hasMore) => {
                            const filtered = (messageList || []).filter(m =>
                                m.sentTime >= startTime && m.sentTime <= endTime
                            );
                            console.log(`[AISummary] 时间范围查询获取到 ${filtered.length} 条消息`);
                            resolve(filtered);
                        },
                        onError: (errorCode) => {
                            console.error('[AISummary] 获取远程历史消息失败, 错误码:', errorCode);
                            reject(new Error(`获取消息失败 (${errorCode})`));
                        }
                    }
                );
            } catch (error) {
                reject(error);
            }
        });
    },

    // ======================== 总结流程 ========================

    async triggerSummary(instance, conversationType, targetId) {
        if (!instance.selectedDate) {
            this.showToast('请先选择日期');
            return;
        }

        const cacheKey = this.getCacheKey(targetId, instance.selectedDate);
        const cached = instance.summaryCache.get(cacheKey);
        if (cached && (Date.now() - cached.timestamp) < instance.config.cacheExpiry) {
            console.log('[AISummary] 使用缓存总结');
            this.showSummary(instance, cached.summary, cached.name, cached.msgCount);
            this.showRecords(instance, cached.rawMessages);
            return;
        }

        this.showLoading(instance);

        try {
            const selDate = instance.selectedDate;
            const dayStart = new Date(selDate.getFullYear(), selDate.getMonth(), selDate.getDate()).getTime();
            const dayEnd = new Date(selDate.getFullYear(), selDate.getMonth(), selDate.getDate(), 23, 59, 59, 999).getTime();

            const messages = await this.fetchMessagesByTimeRange(instance, conversationType, targetId, dayStart, dayEnd);

            if (!messages || messages.length === 0) {
                this.showEmpty(instance);
                return;
            }

            const chatName = await this.getChatName(conversationType, targetId);
            const summary = await this.requestAISummary(instance, messages, chatName, targetId, conversationType);

            // 显示消息记录
            this.showRecords(instance, instance._lastRawMessages);

            instance.summaryCache.set(cacheKey, {
                summary,
                name: chatName,
                msgCount: messages.length,
                rawMessages: instance._lastRawMessages,
                timestamp: Date.now()
            });

            this.showSummary(instance, summary, chatName, messages.length);

        } catch (error) {
            console.error('[AISummary] ❌ 总结失败:', error);
            this.showError(instance, error.message);
        }
    },

    getChatName(conversationType, targetId) {
        return new Promise((resolve) => {
            try {
                const RongIM = window.RongIM;
                if (conversationType === 3) {
                    if (RongIM && RongIM.dataModel && RongIM.dataModel.Group) {
                        RongIM.dataModel.Group.getGroup(targetId, (err, group) => {
                            resolve((!err && group) ? (group.name || targetId) : targetId);
                        });
                    } else { resolve(targetId); }
                } else if (conversationType === 1) {
                    if (RongIM && RongIM.dataModel && RongIM.dataModel.User) {
                        RongIM.dataModel.User.get(targetId, (err, user) => {
                            resolve((!err && user) ? (user.name || user.alias || targetId) : targetId);
                        });
                    } else { resolve(targetId); }
                } else { resolve(targetId); }
            } catch (e) { resolve(targetId); }
        });
    },

    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) => {
                    resolve((!err && user) ? { id: userId, name: user.name || user.alias || userId } : { id: userId, name: 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;
    },

    buildMessageText(messages, userNameMap) {
        const validMessages = messages
            .filter(msg => {
                const textTypes = ['TextMessage', 'ReferenceMessage'];
                return textTypes.includes(msg.messageType) && msg.content;
            })
            .map(msg => {
                const sender = userNameMap.get(msg.senderUserId) || msg.senderUserId || '未知用户';
                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 { sender, text, sentTime: msg.sentTime };
            })
            .filter(Boolean);

        if (validMessages.length === 0) return '';

        const mergedMessages = [];
        let currentMsg = null;
        for (const msg of validMessages) {
            if (!currentMsg) {
                currentMsg = { ...msg, texts: [msg.text] };
            } else {
                const timeDiff = msg.sentTime - currentMsg.sentTime;
                if (currentMsg.sender === msg.sender && timeDiff < 3 * 60 * 1000) {
                    currentMsg.texts.push(msg.text);
                    currentMsg.sentTime = msg.sentTime;
                } else {
                    mergedMessages.push(currentMsg);
                    currentMsg = { ...msg, texts: [msg.text] };
                }
            }
        }
        if (currentMsg) mergedMessages.push(currentMsg);

        const formatTime = (ts) => {
            const d = new Date(ts);
            return `${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
        };

        return mergedMessages.map(msg => {
            return `[${formatTime(msg.sentTime)}] ${msg.sender}: ${msg.texts.join('  ')}`;
        }).join('\n');
    },

    async requestAISummary(instance, messages, chatName, targetId, conversationType) {
        const config = instance.config;
        const userNameMap = await this.resolveUserNames(messages);
        const messageText = this.buildMessageText(messages, userNameMap);

        instance._lastRawMessages = messageText;

        if (!messageText) return '最近没有文本消息可以总结。';

        const serverUrl = this.getServerUrl();
        if (!serverUrl) return '⚠️ 服务器地址未配置，请在插件管理中心 → 设置中配置服务器地址。';

        const apiEndpoint = serverUrl.replace(/\/+$/, '') + (config.apiPath || '/api/ai/summary');
        console.log('[AISummary] 请求AI接口:', apiEndpoint);

        try {
            const headers = { 'Content-Type': 'application/json' };
            if (config.apiKey) headers['Authorization'] = `Bearer ${config.apiKey}`;
            const currentUserId = this.getCurrentUserId();
            if (currentUserId) headers['X-User-Id'] = currentUserId;

            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 60000);

            const isGroup = conversationType === 3;
            const response = await fetch(apiEndpoint, {
                method: 'POST',
                headers,
                body: JSON.stringify({
                    groupId: isGroup ? targetId : undefined,
                    groupName: isGroup ? chatName : undefined,
                    userId: !isGroup ? targetId : undefined,
                    userName: !isGroup ? chatName : undefined,
                    conversationType,
                    messageCount: messages.length,
                    rawMessages: messageText,
                }),
                signal: controller.signal
            });
            clearTimeout(timeoutId);

            if (!response.ok) throw new Error(`AI接口返回错误: ${response.status} ${response.statusText}`);

            const result = await response.json();
            return result.summary || result.content || result.data?.summary || result.data?.content
                || result.choices?.[0]?.message?.content || result.result || result.output || JSON.stringify(result);
        } catch (error) {
            console.error('[AISummary] AI 接口调用失败:', error);
            if (error.name === 'AbortError') throw new Error('客户端请求超时（等待超过 60 秒），请稍后再试。');
            return this.generateLocalSummary(messages, chatName);
        }
    },

    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;
    },

    getServerUrl() {
        try {
            if (window.PluginManager && typeof window.PluginManager.getServerUrl === 'function') {
                return window.PluginManager.getServerUrl() || null;
            }
        } catch (e) {}
        return null;
    },

    generateLocalSummary(messages, chatName) {
        const textMessages = messages.filter(m => m.messageType === 'TextMessage' && m.content?.content);
        const senders = new Set(messages.map(m => m.senderUserId));
        const timeRange = messages.length > 0 ? {
            start: new Date(Math.min(...messages.map(m => m.sentTime))).toLocaleString('zh-CN'),
            end: new Date(Math.max(...messages.map(m => m.sentTime))).toLocaleString('zh-CN')
        } : null;

        let summary = `⚠️ AI接口暂不可用，以下为本地统计：\n\n`;
        summary += `📋 聊天名称：${chatName}\n💬 消息总数：${messages.length} 条\n📝 文本消息：${textMessages.length} 条\n👥 参与人数：${senders.size} 人\n`;
        if (timeRange) summary += `⏰ 时间范围：\n  ${timeRange.start}\n  ~ ${timeRange.end}`;
        return summary;
    },

    // ======================== UI 显示方法 ========================

    showLoading(instance) {
        if (!instance.widget) return;
        instance.isLoading = true;
        instance.widget.style.display = 'block';

        // 切换到总结 tab
        this.switchTab(instance, 'summary');

        const content = instance.widget.querySelector('#ai-summary-content');
        content.innerHTML = `
            <div class="ai-summary-loading">
                <div class="ai-summary-spinner"></div>
                <div class="ai-summary-loading-text">正在分析聊天消息... <span id="ai-summary-wait-time">(0s)</span></div>
                <div class="ai-summary-loading-subtext">AI 正在总结中，请稍候</div>
            </div>
        `;

        instance.widget.querySelector('#ai-summary-group-info').style.display = 'none';
        instance.widget.querySelector('#ai-summary-time').style.display = 'none';

        if (instance._loadingTimer) clearInterval(instance._loadingTimer);
        let waitTime = 0;
        instance._loadingTimer = setInterval(() => {
            waitTime++;
            const timeEl = instance.widget.querySelector('#ai-summary-wait-time');
            if (timeEl) timeEl.textContent = `(${waitTime}s)`;
        }, 1000);
    },

    showSummary(instance, summary, chatName, msgCount) {
        if (!instance.widget) return;
        instance.isLoading = false;
        instance.widget.style.display = 'block';

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

        const groupInfo = instance.widget.querySelector('#ai-summary-group-info');
        groupInfo.style.display = 'block';
        instance.widget.querySelector('#ai-summary-group-name').textContent = `📌 ${chatName}`;
        instance.widget.querySelector('#ai-summary-msg-count').textContent = `基于 ${msgCount} 条消息分析`;

        const content = instance.widget.querySelector('#ai-summary-content');
        content.innerHTML = this.formatSummary(summary);

        const timeEl = instance.widget.querySelector('#ai-summary-time');
        timeEl.style.display = 'block';
        timeEl.textContent = `更新于 ${new Date().toLocaleTimeString('zh-CN')}`;
    },

    /**
     * 显示消息记录到"消息记录"tab
     */
    showRecords(instance, rawMessages) {
        const recordsEl = instance.widget.querySelector('#ai-summary-records-content');
        if (!recordsEl) return;

        if (!rawMessages || !rawMessages.trim()) {
            recordsEl.innerHTML = `
                <div class="ai-summary-placeholder">
                    <div class="ai-summary-placeholder-icon">📋</div>
                    <div>该日期暂无文本消息记录</div>
                </div>
            `;
            return;
        }

        // 将原始消息格式化为 HTML
        const escaped = rawMessages
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');

        const lines = escaped.split('\n').map(line => {
            // 高亮时间和发送者  [MM-DD HH:mm] 用户名:
            return line.replace(
                /^\[(\d{2}-\d{2}\s\d{2}:\d{2})\]\s(.+?):\s/,
                '<span class="ai-record-time">[$1]</span> <span class="ai-record-sender">$2:</span> '
            );
        });

        recordsEl.innerHTML = `<div class="ai-records-formatted">${lines.join('<br>')}</div>`;
    },

    formatSummary(summary) {
        if (!summary) return '<p style="color: #999;">暂无总结内容</p>';

        let text = summary
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');

        text = text.replace(/\n{3,}/g, '\n\n').trim();

        let html = text
            .replace(/^([\u{1F300}-\u{1F9FF}].*?)$/gmu, '<div class="ai-summary-section-title">$1</div>')
            .replace(/^(\d+[\.、].*)$/gm, '<div class="ai-summary-numbered-item">$1</div>')
            .replace(/^[-•]\s(.*)$/gm, '<div class="ai-summary-sub-item">· $1</div>')
            .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');

        html = html.replace(/<\/div>\n+<div/g, '</div><div');
        html = html.replace(/\n\n/g, '<div class="ai-summary-paragraph-gap"></div>');
        html = html.replace(/\n/g, '<br>');

        return `<div class="ai-summary-formatted">${html}</div>`;
    },

    showEmpty(instance) {
        if (!instance.widget) return;
        instance.isLoading = false;
        instance.widget.style.display = 'block';

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

        const content = instance.widget.querySelector('#ai-summary-content');
        content.innerHTML = `
            <div class="ai-summary-empty">
                <div class="ai-summary-empty-icon">📭</div>
                <div>该日期暂无聊天消息</div>
            </div>
        `;

        // 清空消息记录 tab
        const recordsEl = instance.widget.querySelector('#ai-summary-records-content');
        if (recordsEl) {
            recordsEl.innerHTML = `
                <div class="ai-summary-placeholder">
                    <div class="ai-summary-placeholder-icon">📋</div>
                    <div>该日期暂无文本消息记录</div>
                </div>
            `;
        }
    },

    showError(instance, errorMsg) {
        if (!instance.widget) return;
        instance.isLoading = false;
        instance.widget.style.display = 'block';

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

        const content = instance.widget.querySelector('#ai-summary-content');
        content.innerHTML = `
            <div class="ai-summary-error">
                <div class="ai-summary-error-icon">⚠️</div>
                <div class="ai-summary-error-text">总结失败</div>
                <div class="ai-summary-error-detail">${errorMsg || '未知错误'}</div>
                <button class="ai-summary-retry-btn" onclick="document.querySelector('#ai-summary-do-summary').click()">重试</button>
            </div>
        `;
    },

    // ======================== 通用工具方法 ========================

    makeDraggable(element, handle) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        (handle || element).onmousedown = dragMouseDown;

        function dragMouseDown(e) {
            if (e.target.tagName === 'BUTTON') return;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }
        function elementDrag(e) {
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            element.style.top = (element.offsetTop - pos2) + 'px';
            element.style.left = (element.offsetLeft - pos1) + 'px';
            element.style.right = 'auto';
        }
        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    },

    async destroy(instance) {
        console.log('[AISummary] 🔄 销毁聊天记录总结插件...');
        if (instance._hashHandler) window.removeEventListener('hashchange', instance._hashHandler);
        if (instance._observer) instance._observer.disconnect();
        if (instance._loadingTimer) { clearInterval(instance._loadingTimer); instance._loadingTimer = null; }

        const btn = document.querySelector('#rong-tools-ai-summary-btn');
        if (btn) btn.remove();
        if (instance.widget) instance.widget.remove();

        const style = document.querySelector('#ai-summary-styles');
        if (style) style.remove();
        const toast = document.querySelector('#ai-summary-toast');
        if (toast) toast.remove();

        console.log('[AISummary] ✅ 已销毁');
    }
};
