import { FastifyRequest, FastifyReply } from 'fastify';
import { ModelType } from '../../common/llm/adapters/types.js';
import { LLMFactory } from '../../common/llm/adapters/LLMFactory.js';
import * as knowledgeBaseService from '../services/knowledgeBaseService.js';
import { prisma } from '../../config/database.js';

/**
 * 引用信息接口
 */
interface Citation {
  id: number;
  fileName: string;
  position: number;
  score: number;
  content: string;
}

/**
 * 提取文本片段（用于引用上下文）
 */
function extractContextPreview(text: string, maxLength: number = 100): string {
  if (!text) return '';
  
  const cleaned = text.replace(/\s+/g, ' ').trim();
  if (cleaned.length <= maxLength) {
    return cleaned;
  }
  
  const truncated = cleaned.substring(0, maxLength);
  const lastPunctuation = Math.max(
    truncated.lastIndexOf('。'),
    truncated.lastIndexOf('！'),
    truncated.lastIndexOf('？'),
    truncated.lastIndexOf('.'),
    truncated.lastIndexOf('!'),
    truncated.lastIndexOf('?')
  );
  
  if (lastPunctuation > maxLength * 0.5) {
    return truncated.substring(0, lastPunctuation + 1);
  }
  
  return truncated + '...';
}

/**
 * 格式化引用清单
 */
function formatCitations(citations: Citation[]): string {
  if (citations.length === 0) return '';
  
  let result = '\n\n---\n\n📚 **参考文献**\n\n';
  
  for (const cite of citations) {
    const scorePercent = (cite.score * 100).toFixed(0);
    const preview = extractContextPreview(cite.content, 100);
    
    // 使用HTML span标签给引用编号添加id，方便跳转
    result += `<span id="citation-detail-${cite.id}">[${cite.id}]</span> 📄 **${cite.fileName}** - 第${cite.position}段 (相关度${scorePercent}%)\n`;
    result += `    "${preview}"\n\n`;
  }
  
  return result;
}

interface SendChatMessageBody {
  content: string;
  modelType: ModelType;
  knowledgeBaseIds?: string[];
  documentIds?: string[]; // Phase 2: 逐篇精读模式 - 限定文档范围
  fullTextDocumentIds?: string[]; // Phase 2: 全文阅读模式 - 传递全文
  conversationId?: string; // 可选：续接已有对话
}

/**
 * 通用聊天Controller
 * 无需项目和智能体，纯大模型对话
 */
export class ChatController {
  /**
   * 发送消息（流式输出）
   */
  async sendMessageStream(
    request: FastifyRequest<{ Body: SendChatMessageBody }>,
    reply: FastifyReply
  ) {
    try {
      // TODO: 从JWT token获取userId
      const userId = 'user-mock-001';

      const { content, modelType, knowledgeBaseIds, documentIds, fullTextDocumentIds, conversationId } = request.body;

      console.log('💬 [ChatController] 收到通用对话请求', {
        content,
        modelType,
        knowledgeBaseIds: knowledgeBaseIds || [],
        documentIds: documentIds || [],
        fullTextDocumentIds: fullTextDocumentIds || [],
        conversationId,
      });

      // 验证modelType
      if (modelType !== 'deepseek-v3' && modelType !== 'qwen3-72b' && modelType !== 'qwen-long' && modelType !== 'gemini-pro') {
        reply.code(400).send({
          success: false,
          message: `不支持的模型类型: ${modelType}`,
        });
        return;
      }

      // 获取或创建对话记录
      let conversation;
      if (conversationId) {
        // 验证对话是否存在且属于当前用户
        conversation = await prisma.generalConversation.findFirst({
          where: {
            id: conversationId,
            userId,
            deletedAt: null,
          },
        });

        if (!conversation) {
          reply.code(404).send({
            success: false,
            message: '对话不存在',
          });
          return;
        }
      } else {
        // 创建新对话
        conversation = await prisma.generalConversation.create({
          data: {
            userId,
            title: content.substring(0, 50), // 用第一条消息的前50字作为标题
            modelName: modelType,
          },
        });
        console.log('✅ [ChatController] 创建新对话', { conversationId: conversation.id });
      }

      // 检索知识库上下文
      let knowledgeBaseContext = '';
      const allCitations: Citation[] = []; // 存储所有引用信息
      let citationCounter = 1; // 全局引用计数器
      
      // Phase 2: 全文阅读模式 - 传递完整文献全文
      if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
        console.log('📚 [ChatController] 全文阅读模式 - 加载文献全文', {
          documentCount: fullTextDocumentIds.length,
        });

        try {
          // 获取所有选中文档的全文
          const documents = await prisma.document.findMany({
            where: {
              id: { in: fullTextDocumentIds },
            },
            select: {
              id: true,
              filename: true,
              extractedText: true,
              tokensCount: true,
            },
            orderBy: {
              filename: 'asc', // 按文件名排序
            },
          });

          console.log(`📄 [ChatController] 加载了 ${documents.length} 篇文献全文`);

          // 过滤掉没有extractedText的文档
          const validDocuments = documents.filter(doc => doc.extractedText && doc.extractedText.trim().length > 0);
          
          if (validDocuments.length === 0) {
            console.warn('⚠️ [ChatController] 所有文档都没有提取文本，无法使用全文模式');
          } else if (validDocuments.length < documents.length) {
            console.warn(`⚠️ [ChatController] ${documents.length - validDocuments.length} 篇文档没有提取文本，已跳过`);
          }

          // 组装全文上下文，每篇文献用明确的标记分隔
          const fullTextParts: string[] = [];
          
          for (let i = 0; i < validDocuments.length; i++) {
            const doc = validDocuments[i];
            const docNumber = i + 1;
            
            // 为每篇文献添加引用信息
            allCitations.push({
              id: docNumber,
              fileName: doc.filename,
              position: 0, // 全文没有position概念
              score: 1.0, // 全文模式相关度100%
              content: doc.extractedText?.substring(0, 200) || '（无内容）',
            });

            // 格式：【文献N：文件名】\n全文内容
            fullTextParts.push(
              `【文献${docNumber}：${doc.filename}】\n\n${doc.extractedText}`
            );
          }

          knowledgeBaseContext = fullTextParts.join('\n\n---\n\n');
          
          const totalTokens = validDocuments.reduce((sum, doc) => sum + (doc.tokensCount || 0), 0);
          
          console.log(`📚 [ChatController] 全文上下文已组装`, {
            totalDocuments: validDocuments.length,
            totalCharacters: knowledgeBaseContext.length,
            totalTokens: totalTokens,
            estimatedTokens: Math.round(knowledgeBaseContext.length / 2.5), // 粗略估算
          });

          // ⚠️ 检查Token限制（Qwen-Long输入限制：1M tokens）
          const QWEN_LONG_INPUT_LIMIT = 1000000;
          const SYSTEM_OVERHEAD = 10000; // 系统提示、格式等开销
          const SAFE_INPUT_LIMIT = QWEN_LONG_INPUT_LIMIT - SYSTEM_OVERHEAD;

          if (totalTokens > SAFE_INPUT_LIMIT) {
            const errorMsg = `输入Token数量 (${totalTokens}) 超出Qwen-Long模型限制 (${SAFE_INPUT_LIMIT})。请减少文献数量后重试。`;
            console.error(`❌ [ChatController] ${errorMsg}`);
            
            // 返回错误信息给前端
            reply.raw.write(`data: ${JSON.stringify({
              content: `\n\n⚠️ **Token数量超限**\n\n${errorMsg}\n\n**建议**：\n- 当前选中 ${validDocuments.length} 篇文献，共 ${totalTokens.toLocaleString()} tokens\n- 请减少到 ${Math.floor(validDocuments.length * SAFE_INPUT_LIMIT / totalTokens)} 篇以内\n- 或使用"逐篇精读"模式深入分析单篇文献`,
              role: 'assistant',
              error: true,
            })}\n\n`);
            reply.raw.write('data: [DONE]\n\n');
            return reply.raw.end();
          }

          // 警告：如果接近限制
          if (totalTokens > SAFE_INPUT_LIMIT * 0.8) {
            console.warn(`⚠️ [ChatController] Token数量接近限制 (${totalTokens}/${SAFE_INPUT_LIMIT}), 建议减少文献数量`);
          }

        } catch (error) {
          console.error('❌ [ChatController] 加载文献全文失败:', error);
          // 不throw错误，继续执行（可能没有全文也能正常对话）
        }
      }
      // RAG检索模式（逐篇精读或通用对话）
      else if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
        console.log('📚 [ChatController] 开始检索知识库');
        const knowledgeResults: string[] = [];

        // Phase 2: 如果指定了文档ID（逐篇精读模式），需要更多结果用于过滤
        const topK = documentIds && documentIds.length > 0 ? 50 : 15;

        for (const kbId of knowledgeBaseIds) {
          try {
            const searchResult = await knowledgeBaseService.searchKnowledgeBase(
              userId,
              kbId,
              content,
              topK
            );

            if (searchResult.records && searchResult.records.length > 0) {
              let records = searchResult.records;

              // Phase 2: 逐篇精读模式 - 过滤出指定文档的结果
              if (documentIds && documentIds.length > 0) {
                console.log(`🔍 [ChatController] 逐篇精读模式 - 过滤文档`, { documentIds });
                
                // 获取文档的Dify ID映射
                const documents = await prisma.document.findMany({
                  where: {
                    id: { in: documentIds },
                    knowledgeBase: {
                      id: kbId,
                    },
                  },
                  select: {
                    id: true,
                    filename: true,
                    difyDocumentId: true,
                  },
                });

                const difyDocIds = documents.map(d => d.difyDocumentId).filter(Boolean);
                console.log(`📄 [ChatController] 目标Dify文档ID:`, difyDocIds);

                // 过滤结果
                const beforeCount = records.length;
                records = records.filter((record: any) => {
                  const docId = record.segment?.document?.id || record.document_id;
                  return docId && difyDocIds.includes(docId);
                });

                console.log(`✂️ [ChatController] 过滤结果: ${beforeCount} → ${records.length}`);

                // 如果过滤后结果太少，警告
                if (records.length === 0) {
                  console.warn('⚠️ [ChatController] 过滤后没有结果，可能是文档ID不匹配');
                }

                // 只取前15个
                records = records.slice(0, 15);
              }

              if (records.length > 0) {
                const kbInfo = await prisma.knowledgeBase.findUnique({
                  where: { id: kbId },
                  select: { name: true },
                });

                // 优化格式：使用[来源N]标记，便于AI引用
                const formattedResult = `【知识库：${kbInfo?.name || '未命名'}】\n` +
                  records
                    .map((record: any) => {
                      const citationId = citationCounter++;
                      const score = (record.score * 100).toFixed(1);
                      
                      // 保存引用信息
                      allCitations.push({
                        id: citationId,
                        fileName: record.segment?.document?.name || record.document_name || '未知文档',
                        position: record.segment?.position || record.segment_position || 0,
                        score: record.score,
                        content: record.segment?.content || record.content || '',
                      });
                      
                      return `[来源${citationId}] [相关度${score}%]\n${record.segment?.content || record.content}`;
                    })
                    .join('\n\n');
                
                knowledgeResults.push(formattedResult);
              }
            }
          } catch (error) {
            console.error(`❌ [ChatController] 检索知识库失败 ${kbId}:`, error);
          }
        }

        if (knowledgeResults.length > 0) {
          knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
          console.log(`💾 [ChatController] 知识库上下文: ${knowledgeBaseContext.length} 字符`);
          console.log(`📚 [ChatController] 收集到 ${allCitations.length} 个引用`);
        }
      }

      // 获取历史消息（最近20条）
      const historyMessages = await prisma.generalMessage.findMany({
        where: {
          conversationId: conversation.id,
        },
        orderBy: {
          createdAt: 'desc',
        },
        take: 20,
      });
      historyMessages.reverse();
      console.log(`📜 [ChatController] 历史消息数: ${historyMessages.length}`);

      // 组装消息上下文
      let systemPrompt = '你是一个专业、友好的AI助手。当用户提供参考资料时，请优先基于参考资料回答。';
      
      // 全文阅读模式的系统提示
      if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
        systemPrompt = '你是一个专业的学术文献分析助手。用户会提供多篇文献的完整全文，每篇文献用【文献N：文件名】标记。请认真阅读所有文献，进行深入的综合分析。在回答时请引用具体文献，使用【文献N】格式。你的优势是能够看到所有文献的全貌，进行跨文献的比较、归纳和总结。';
      }
      
      const messages: any[] = [
        {
          role: 'system',
          content: systemPrompt,
        },
      ];

      // 添加历史消息
      for (const msg of historyMessages) {
        messages.push({
          role: msg.role,
          content: msg.content,
        });
      }

      // 添加当前用户消息
      let userContent = content;
      if (knowledgeBaseContext) {
        // 全文阅读模式的提示
        if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
          userContent = `${content}\n\n## 参考资料（文献全文）\n\n**重要提示**：下面提供的是完整的文献全文。每篇文献用【文献N：文件名】标记。请在回答时引用文献，格式如"根据【文献1】..."或"研究表明【文献2】【文献3】..."。你可以综合分析所有文献，进行跨文献的比较和总结。\n\n${knowledgeBaseContext}`;
        }
        // RAG检索模式的提示
        else {
          userContent = `${content}\n\n## 参考资料（来自知识库）\n\n**重要提示**：下面提供的文献片段已经用[来源N]进行了标记。请在回答中引用具体来源时使用对应的编号，如"根据[来源1]..."或"研究表明[来源3][来源5]..."。系统会在你回答结束后自动显示完整的引用清单。\n\n${knowledgeBaseContext}`;
        }
      }
      messages.push({
        role: 'user',
        content: userContent,
      });

      // 设置SSE响应头
      reply.raw.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        Connection: 'keep-alive',
        'Access-Control-Allow-Origin': '*',
      });

      // 保存用户消息
      await prisma.generalMessage.create({
        data: {
          conversationId: conversation.id,
          role: 'user',
          content,
          metadata: {
            knowledgeBaseIds,
          },
        },
      });

      // 流式输出
      const adapter = LLMFactory.getAdapter(modelType);
      let fullContent = '';
      let usage: any = null;

      // Phase 2: 全文阅读模式需要更大的输出空间（用于综合分析、引用等）
      const maxOutputTokens = fullTextDocumentIds && fullTextDocumentIds.length > 0 
        ? 6000  // 全文模式：需要更长的回答空间
        : 2000; // 其他模式：常规长度

      console.log(`🤖 [ChatController] 开始调用LLM`, {
        model: modelType,
        maxOutputTokens,
        mode: fullTextDocumentIds && fullTextDocumentIds.length > 0 ? '全文阅读' : '其他',
      });

      for await (const chunk of adapter.chatStream(messages, {
        temperature: 0.7,
        maxTokens: maxOutputTokens,
      })) {
        fullContent += chunk.content;

        if (chunk.usage) {
          usage = chunk.usage;
        }

        // 发送SSE数据
        reply.raw.write(`data: ${JSON.stringify(chunk)}\n\n`);
      }

      // AI回答完毕后，追加引用清单
      if (allCitations.length > 0) {
        console.log(`📚 [ChatController] 追加 ${allCitations.length} 个引用清单`);
        const citationsText = formatCitations(allCitations);
        fullContent += citationsText;
        
        // 将引用清单也流式输出
        const citationChunk = {
          content: citationsText,
          role: 'assistant' as const,
        };
        reply.raw.write(`data: ${JSON.stringify(citationChunk)}\n\n`);
      }

      // 保存助手消息
      await prisma.generalMessage.create({
        data: {
          conversationId: conversation.id,
          role: 'assistant',
          content: fullContent,
          model: modelType,
          tokens: usage?.totalTokens,
          metadata: {
            usage,
          },
        },
      });

      // 更新对话
      await prisma.generalConversation.update({
        where: { id: conversation.id },
        data: {
          updatedAt: new Date(),
        },
      });

      // 发送完成信号
      reply.raw.write(`data: [DONE]\n\n`);
      reply.raw.end();

      console.log('✅ [ChatController] 对话完成');
    } catch (error: any) {
      console.error('❌ [ChatController] 错误:', error);
      reply.code(500).send({
        success: false,
        message: error.message || '服务器错误',
      });
    }
  }

  /**
   * 获取对话列表
   */
  async getConversations(
    _request: FastifyRequest,
    reply: FastifyReply
  ) {
    try {
      const userId = 'user-mock-001';

      const conversations = await prisma.generalConversation.findMany({
        where: {
          userId,
          deletedAt: null,
        },
        orderBy: {
          updatedAt: 'desc',
        },
        take: 50,
      });

      reply.send({
        success: true,
        data: conversations,
      });
    } catch (error: any) {
      reply.code(500).send({
        success: false,
        message: error.message || '获取对话列表失败',
      });
    }
  }

  /**
   * 删除对话
   */
  async deleteConversation(
    request: FastifyRequest<{ Params: { id: string } }>,
    reply: FastifyReply
  ) {
    try {
      const userId = 'user-mock-001';
      const { id } = request.params;

      await prisma.generalConversation.update({
        where: {
          id,
          userId,
        },
        data: {
          deletedAt: new Date(),
        },
      });

      reply.send({
        success: true,
        message: '删除成功',
      });
    } catch (error: any) {
      reply.code(500).send({
        success: false,
        message: error.message || '删除失败',
      });
    }
  }
}

export const chatController = new ChatController();


