/**
 * 纯文本格式导出器
 * 将聊天记录导出为易于阅读的纯文本格式
 * 支持多种文本布局和格式化选项
 */

import { ExportFormat } from '../../types/index.js';
import { BaseExporter, ExportOptions } from './BaseExporter.js';
import { RawMessage } from 'NapCatQQ/src/core/index.js';
import { NapCatCore } from 'NapCatQQ/src/core/index.js';
import { ParsedMessage } from '../parser/MessageParser.js';
import { SimpleMessageParser, CleanMessage } from '../parser/SimpleMessageParser.js';

/**
 * issue #128：把被引用消息时间戳渲染成 "MM-DD HH:MM" 标签。
 * 接受秒级 epoch / 毫秒级 epoch / 数字字符串，全都归一到毫秒后再 toLocaleString。
 * 老数据里 timestamp 字段缺失或为 0 时直接返回空串，调用方看到空串就跳过。
 */
function formatReplyTimeLabel(ts: number): string {
    if (!Number.isFinite(ts) || ts <= 0) return '';
    const ms = ts < 1e12 ? ts * 1000 : ts;
    const d = new Date(ms);
    if (Number.isNaN(d.getTime())) return '';
    const mm = String(d.getMonth() + 1).padStart(2, '0');
    const dd = String(d.getDate()).padStart(2, '0');
    const hh = String(d.getHours()).padStart(2, '0');
    const min = String(d.getMinutes()).padStart(2, '0');
    return `${mm}-${dd} ${hh}:${min}`;
}

/**
 * 文本格式选项接口
 */
interface TextFormatOptions {
    /** 消息之间的分隔符 */
    messageSeparator: string;
    /** 时间戳格式 */
    timestampFormat: 'full' | 'time-only' | 'date-only' | 'relative';
    /** 是否显示发送者信息 */
    showSender: boolean;
    /** 是否显示消息类型 */
    showMessageType: boolean;
    /** 是否显示资源统计 */
    showResourceStats: boolean;
    /** 行宽限制（0表示不限制） */
    lineWidth: number;
    /** 缩进字符 */
    indentChar: string;
    /** 是否显示消息序号 */
    showMessageNumber: boolean;
}

/**
 * 纯文本导出器类
 * 生成结构清晰、易于阅读的纯文本聊天记录
 */
export class TextExporter extends BaseExporter {
    private readonly textOptions: TextFormatOptions;

    /**
     * 构造函数
     * @param options 基础导出选项
     * @param textOptions 文本格式选项
     */
    constructor(options: ExportOptions, textOptions: Partial<TextFormatOptions> = {}, core?: NapCatCore) {
        super(ExportFormat.TXT, options, core);
        
        this.textOptions = {
            messageSeparator: '\n',
            timestampFormat: 'full',
            showSender: true,
            showMessageType: false,
            showResourceStats: true,
            lineWidth: 0,
            indentChar: '  ',
            showMessageNumber: false,
            ...textOptions
        };
    }

    /**
     * 实现导出方法
     */
    protected async generateContent(
        messages: RawMessage[], 
        chatInfo?: { name?: string; type?: string; avatar?: string; participantCount?: number }
    ): Promise<string> {
        let parsedMessages: ParsedMessage[] = [];
        
        // 尝试使用MessageParser解析消息
        if (this.core) {
            try {
                const parser = this.getMessageParser(this.core);
                parsedMessages = await parser.parseMessages(messages);
                console.log(`[TextExporter] MessageParser解析了 ${parsedMessages.length} 条消息`);
                
                // 如果MessageParser解析结果为空，使用fallback
                if (parsedMessages.length === 0 && messages.length > 0) {
                    console.log(`[TextExporter] MessageParser解析结果为空，使用SimpleMessageParser作为fallback`);
                    parsedMessages = await this.useFallbackParser(messages);
                }
            } catch (error) {
                console.error(`[TextExporter] MessageParser解析失败，使用SimpleMessageParser作为fallback:`, error);
                parsedMessages = await this.useFallbackParser(messages);
            }
        } else {
            // 没有NapCatCore实例，直接使用SimpleMessageParser
            console.log(`[TextExporter] 没有NapCatCore实例，使用SimpleMessageParser`);
            parsedMessages = await this.useFallbackParser(messages);
        }
        
        const lines: string[] = [];
        
        // 生成文件头部信息
        lines.push(...this.generateHeader(chatInfo, parsedMessages));
        lines.push('');
        
        // 生成消息内容
        for (let i = 0; i < parsedMessages.length; i++) {
            if (this.cancelled) break;
            
            const message = parsedMessages[i];
            if (message) {
                const messageLines = this.formatMessage(message, i + 1);
                lines.push(...messageLines);
                
                // 添加消息分隔符
                if (i < parsedMessages.length - 1) {
                    lines.push(this.textOptions.messageSeparator);
                }
            }
            
            // 更新进度
            if (i % 100 === 0) {
                this.updateProgress(
                    i, 
                    parsedMessages.length, 
                    `格式化消息 ${i + 1}/${parsedMessages.length}`
                );
            }
        }
        
        // 生成文件尾部信息
        lines.push('');
        lines.push(...this.generateFooter(parsedMessages));
        
        return lines.join('\n');
    }

    /**
     * 使用SimpleMessageParser作为fallback解析器
     */
    private async useFallbackParser(messages: RawMessage[]): Promise<ParsedMessage[]> {
        const simpleParser = new SimpleMessageParser({
            preferGroupMemberName: this.options.preferGroupMemberName,
            senderTitleResolver: this.options.senderTitleResolver
        });
        const cleanMessages = await simpleParser.parseMessages(messages);
        
        // 将CleanMessage转换为ParsedMessage格式
        return cleanMessages.map((cleanMsg: CleanMessage): ParsedMessage => {
            // issue #128：从 cleanMsg.content.elements 里把 type=reply 的数据回挂到
            // content.reply，这样 formatMessage 能直接走"回复: 时间 名字 - 内容"那条路径。
            const replyEl = (cleanMsg.content.elements || []).find((el: any) => el?.type === 'reply');
            const reply = replyEl?.data && typeof replyEl.data === 'object' ? {
                messageId: String(replyEl.data.messageId ?? ''),
                referencedMessageId: replyEl.data.referencedMessageId,
                senderUin: replyEl.data.senderUin,
                senderName: replyEl.data.senderName,
                timestamp: typeof replyEl.data.timestamp === 'number' ? replyEl.data.timestamp : undefined,
                content: typeof replyEl.data.content === 'string' ? replyEl.data.content : '',
                elements: []
            } : undefined;

            return {
            messageId: cleanMsg.id,
            messageSeq: cleanMsg.seq,
            timestamp: new Date(cleanMsg.timestamp),
            sender: {
                uid: cleanMsg.sender.uid,
                uin: cleanMsg.sender.uin,
                name: cleanMsg.sender.name || cleanMsg.sender.uid,
                title: cleanMsg.sender.title
            } as ParsedMessage['sender'],
            receiver: {
                uid: 'unknown',
                type: 'unknown' as 'group' | 'private'
            },
            messageType: cleanMsg.type as any,
            isSystemMessage: cleanMsg.system,
            isRecalled: cleanMsg.recalled,
            isTempMessage: false,
            content: {
                text: cleanMsg.content.text,
                html: cleanMsg.content.html,
                raw: JSON.stringify(cleanMsg.content.elements),
                mentions: (cleanMsg.content.mentions || []).map(m => ({
                    uid: m.uid,
                    name: m.name,
                    type: m.type
                })),
                resources: cleanMsg.content.resources.map(r => ({
                    type: r.type as 'image' | 'video' | 'audio' | 'file',
                    fileName: r.filename,
                    fileSize: r.size,
                    originalUrl: r.url || '',
                    localPath: r.localPath,
                    md5: '',
                    mimeType: 'application/octet-stream',
                    status: 'downloaded' as any,
                    accessible: true,
                    checkedAt: new Date()
                })),
                emojis: [],
                reply,
                special: []
            },
            stats: {
                elementCount: cleanMsg.content.elements.length,
                resourceCount: cleanMsg.content.resources.length,
                textLength: cleanMsg.content.text.length,
                processingTime: 0
            },
            rawMessage: {} as any // 没有原始消息数据
            };
        });
    }

    /**
     * 生成文件头部信息
     */
    private generateHeader(
        chatInfo?: { name?: string; type?: string; avatar?: string; participantCount?: number },
        messages?: ParsedMessage[]
    ): string[] {
        const lines: string[] = [];
        
        // 软件信息
        lines.push('[QQChatExporter V5 / https://github.com/shuakami/qq-chat-exporter]');
        lines.push('[本软件是免费的开源项目~ 如果您是买来的，请立即退款！如果有帮助到您，欢迎给我点个Star~]');
        lines.push('');
        
        // 标题
        lines.push('===============================================');
        lines.push('           QQ聊天记录导出文件');
        lines.push('===============================================');
        lines.push('');
        
        // 聊天信息
        if (chatInfo) {
            lines.push(`聊天名称: ${chatInfo.name || '未知聊天'}`);
            lines.push(`聊天类型: ${this.getChatTypeDisplayName(chatInfo.type || 'unknown')}`);
            
            if (chatInfo.participantCount !== undefined) {
                lines.push(`参与人数: ${chatInfo.participantCount}`);
            }
        }
        
        // 导出信息
        lines.push(`导出时间: ${this.formatTimestamp(new Date())}`);
        if (messages && messages.length > 0) {
            lines.push(`消息总数: ${messages.length}`);
            
            // 计算实际的时间范围（防止消息排序问题）
            const timeRange = this.calculateTimeRange(messages);
            if (timeRange) {
                lines.push(`时间范围: ${timeRange}`);
            }
        }
        lines.push('');
        
        return lines;
    }

    /**
     * 生成文件尾部信息
     */
    private generateFooter(messages: ParsedMessage[]): string[] {
        const lines: string[] = [];
        
        lines.push('===============================================');
        lines.push('              导出完成');
        lines.push('===============================================');
        lines.push(`总计导出 ${messages.length} 条消息`);
        lines.push(`导出时间: ${this.formatTimestamp(new Date())}`);
        
        return lines;
    }

    /**
     * 格式化单条消息
     */
    private formatMessage(message: ParsedMessage, messageNumber: number): string[] {
        const lines: string[] = [];
        
        // 消息序号（可选）
        if (this.textOptions.showMessageNumber) {
            lines.push(`[${messageNumber}]`);
        }
        
        // 发送者信息
        if (this.textOptions.showSender) {
            const senderName = message.sender.name || message.sender.uid;
            // 群头衔（issue #331）：当 senderTitleResolver 命中时，加在名字前
            const title = (message.sender as { title?: string }).title;
            const senderLabel = title ? `[${title}] ${senderName}` : senderName;
            lines.push(`${senderLabel}:`);
        }
        
        // 时间戳
        lines.push(`时间: ${this.formatTimestamp(message.timestamp)}`);
        
        // 消息类型（可选）
        if (this.textOptions.showMessageType) {
            lines.push(`类型: ${message.messageType}`);
        }
        
        // 消息内容
        const content = message.content.text.trim();
        if (content) {
            lines.push(`内容: ${content}`);
        } else if (message.content.resources.length > 0) {
            // 如果没有文本但有资源，显示资源类型
            const resourceTypes = message.content.resources.map(r => r.type).join('、');
            lines.push(`内容: [${resourceTypes}消息]`);
        } else if (message.isSystemMessage) {
            // 系统消息
            lines.push(`内容: [系统消息]`);
        } else if (message.content.emojis.length > 0) {
            // 表情消息
            lines.push(`内容: [表情消息]`);
        } else {
            // 其他无内容消息
            lines.push(`内容: [无文本内容]`);
        }
        
        // 资源信息（可选）
        if (this.textOptions.showResourceStats && message.content.resources.length > 0) {
            lines.push(`资源: ${message.content.resources.length} 个文件`);
            message.content.resources.forEach(resource => {
                lines.push(`  - ${resource.type}: ${resource.fileName}`);
            });
        }
        
        // 特殊元素信息
        if (message.content.mentions.length > 0) {
            const mentions = message.content.mentions.map(m => m.name || m.uid).join(', ');
            lines.push(`提及: ${mentions}`);
        }
        
        if (message.content.reply) {
            // issue #128：被引用消息的时间戳如果拿到，就在前面加一个"MM-DD HH:MM"，
            // 让纯文本导出也能看出引用的是几点几分的消息。
            const reply = message.content.reply;
            const ts = typeof reply.timestamp === 'number' && reply.timestamp > 0 ? reply.timestamp : 0;
            const tsLabel = ts ? formatReplyTimeLabel(ts) : '';
            const sender = reply.senderName || '';
            const head = tsLabel ? `${tsLabel} ${sender}`.trim() : sender;
            lines.push(`回复: ${head} - ${reply.content}`);
        }
        
        return lines.map(line => this.wrapLine(line));
    }

    /**
     * 换行处理
     */
    private wrapLine(line: string): string {
        if (this.textOptions.lineWidth <= 0 || line.length <= this.textOptions.lineWidth) {
            return line;
        }
        
        // 简单的换行处理
        const chunks: string[] = [];
        for (let i = 0; i < line.length; i += this.textOptions.lineWidth) {
            chunks.push(line.substring(i, i + this.textOptions.lineWidth));
        }
        return chunks.join('\n' + this.textOptions.indentChar);
    }

    /**
     * 计算消息的实际时间范围
     * 遍历所有消息，找到真正的最早和最晚时间
     */
    private calculateTimeRange(messages: ParsedMessage[]): string | null {
        if (!messages || messages.length === 0) {
            return null;
        }
        
        let earliestTime: Date | null = null;
        let latestTime: Date | null = null;
        
        // 遍历所有消息，找到真正的时间范围
        for (const message of messages) {
            if (!message || !message.timestamp) continue;
            
            const messageTime = message.timestamp;
            
            if (!earliestTime || messageTime < earliestTime) {
                earliestTime = messageTime;
            }
            
            if (!latestTime || messageTime > latestTime) {
                latestTime = messageTime;
            }
        }
        
        if (!earliestTime || !latestTime) {
            return null;
        }
        
        // 格式化时间范围
        const startTime = this.formatTimestamp(earliestTime);
        const endTime = this.formatTimestamp(latestTime);
        
        console.log(`[TextExporter] 计算时间范围: ${startTime} 到 ${endTime}`);
        return `${startTime} - ${endTime}`;
    }

    /**
     * 获取聊天类型显示名称
     */
    private getChatTypeDisplayName(type: string): string {
        switch (type) {
            case 'group':
                return '群聊';
            case 'private':
                return '私聊';
            case 'temp':
                return '临时会话';
            default:
                return '未知类型';
        }
    }
}
