import { prisma } from '../../config/database.js';
import { LLMFactory } from '../../common/llm/adapters/LLMFactory.js';
import { Message, ModelType, StreamChunk } from '../../common/llm/adapters/types.js';
import { agentService } from './agentService.js';
import * as knowledgeBaseService from './knowledgeBaseService.js';

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

/**
 * 提取文本片段（用于引用上下文）
 * @param text 完整文本
 * @param maxLength 最大长度（默认100字）
 * @returns 提取的片段
 */
function extractContextPreview(text: string, maxLength: number = 100): string {
  if (!text) return '';
  
  // 移除多余的空白字符
  const cleaned = text.replace(/\s+/g, ' ').trim();
  
  // 如果文本短于限制，直接返回
  if (cleaned.length <= maxLength) {
    return cleaned;
  }
  
  // 截取前maxLength个字符，并尝试在句号、问号、感叹号处截断
  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 + '...';
}

/**
 * 格式化引用清单
 * @param citations 引用列表
 * @returns 格式化的引用清单字符串
 */
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 CreateConversationData {
  userId: string;
  projectId: string;
  agentId: string;
  title?: string;
}

interface SendMessageData {
  conversationId: string;
  content: string;
  modelType: ModelType;
  knowledgeBaseIds?: string[];
}

export class ConversationService {
  /**
   * 创建新对话
   */
  async createConversation(data: CreateConversationData) {
    const { userId, projectId, agentId, title } = data;

    // 验证智能体是否存在
    const agent = agentService.getAgentById(agentId);
    if (!agent) {
      throw new Error('智能体不存在');
    }

    // 验证项目是否存在
    const project = await prisma.project.findFirst({
      where: {
        id: projectId,
        userId: userId,
        deletedAt: null,
      },
    });

    if (!project) {
      throw new Error('项目不存在或无权访问');
    }

    // 创建对话
    const conversation = await prisma.conversation.create({
      data: {
        userId,
        projectId,
        agentId,
        title: title || `与${agent.name}的对话`,
        metadata: {
          agentName: agent.name,
          agentCategory: agent.category,
        },
      },
    });

    return conversation;
  }

  /**
   * 获取对话列表
   */
  async getConversations(userId: string, projectId?: string) {
    const where: any = {
      userId,
      deletedAt: null,
    };

    if (projectId) {
      where.projectId = projectId;
    }

    const conversations = await prisma.conversation.findMany({
      where,
      include: {
        project: {
          select: {
            id: true,
            name: true,
          },
        },
        _count: {
          select: {
            messages: true,
          },
        },
      },
      orderBy: {
        updatedAt: 'desc',
      },
    });

    return conversations;
  }

  /**
   * 获取对话详情（包含消息）
   */
  async getConversationById(conversationId: string, userId: string) {
    const conversation = await prisma.conversation.findFirst({
      where: {
        id: conversationId,
        userId,
        deletedAt: null,
      },
      include: {
        project: {
          select: {
            id: true,
            name: true,
            background: true,
            researchType: true,
          },
        },
        messages: {
          orderBy: {
            createdAt: 'asc',
          },
        },
      },
    });

    if (!conversation) {
      throw new Error('对话不存在或无权访问');
    }

    return conversation;
  }

  /**
   * 组装上下文消息
   */
  private async assembleContext(
    conversationId: string,
    agentId: string,
    projectBackground: string,
    userInput: string,
    knowledgeBaseContext?: string
  ): Promise<Message[]> {
    console.log('🔧 [assembleContext] 开始组装上下文', {
      conversationId,
      agentId,
      hasKnowledgeBaseContext: !!knowledgeBaseContext,
      knowledgeBaseContextLength: knowledgeBaseContext?.length || 0
    });

    // 获取系统Prompt
    const systemPrompt = agentService.getSystemPrompt(agentId);

    // 获取历史消息（最近100条，约50轮对话）
    // DeepSeek-V3支持64K tokens，实际可容纳100-200轮对话
    const historyMessages = await prisma.message.findMany({
      where: {
        conversationId,
      },
      orderBy: {
        createdAt: 'desc',
      },
      take: 100,
    });

    // 反转顺序（最早的在前）
    historyMessages.reverse();

    // 判断是否是第一条消息
    const isFirstMessage = historyMessages.length === 0;
    console.log(`📜 [assembleContext] 历史消息数: ${historyMessages.length}, 是否首次: ${isFirstMessage}`);

    // 渲染用户Prompt
    let userPromptContent: string;
    
    if (isFirstMessage) {
      // 第一条消息：使用完整模板（包含项目背景）
      userPromptContent = agentService.renderUserPrompt(agentId, {
        projectBackground,
        userInput,
        knowledgeBaseContext,
      });
      console.log(`📝 [assembleContext] 首次消息，使用完整模板，长度: ${userPromptContent.length}`);
      console.log(`📋 [assembleContext] userPromptContent完整内容:\n${userPromptContent}`);
      console.log(`🔍 [assembleContext] 是否包含"参考文献": ${userPromptContent.includes('参考文献')}`);
      console.log(`🔍 [assembleContext] 是否包含知识库内容: ${userPromptContent.includes('阿尔兹海默症')}`);
    } else {
      // 后续消息：只发送用户输入和知识库上下文（如果有）
      if (knowledgeBaseContext) {
        userPromptContent = `${userInput}\n\n## 参考文献（来自知识库）\n\n**重要提示**：下面提供的文献片段已经用[来源N]进行了标记。请在回答中引用具体来源时使用对应的编号，如"根据[来源1]..."或"研究表明[来源3][来源5]..."。系统会在你回答结束后自动显示完整的引用清单。\n\n${knowledgeBaseContext}`;
        console.log(`📝 [assembleContext] 后续消息+知识库，总长度: ${userPromptContent.length}`);
        console.log(`📋 [assembleContext] userPromptContent预览:\n${userPromptContent.substring(0, 300)}...`);
      } else {
        userPromptContent = userInput;
        console.log(`📝 [assembleContext] 后续消息，仅用户输入: ${userPromptContent}`);
      }
    }

    // 组装消息数组
    const messages: Message[] = [
      {
        role: 'system',
        content: systemPrompt,
      },
    ];

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

    // 添加当前用户输入
    messages.push({
      role: 'user',
      content: userPromptContent,
    });

    console.log(`✅ [assembleContext] 组装完成，消息总数: ${messages.length}`);
    return messages;
  }

  /**
   * 发送消息（非流式）
   */
  async sendMessage(data: SendMessageData, userId: string) {
    const { conversationId, content, modelType, knowledgeBaseIds } = data;

    // 获取对话信息
    const conversation = await this.getConversationById(conversationId, userId);

    // 获取知识库上下文（如果有@知识库）
    let knowledgeBaseContext = '';
    const allCitations: Citation[] = []; // 存储所有引用信息
    let citationCounter = 1; // 全局引用计数器
    
    if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
      const knowledgeResults: string[] = [];
      
      // 对每个知识库进行检索
      for (const kbId of knowledgeBaseIds) {
        try {
          const searchResult = await knowledgeBaseService.searchKnowledgeBase(
            userId,
            kbId,
            content,
            15 // Phase 1优化：从3增加到15个最相关的段落
          );

          // 格式化检索结果
          if (searchResult.records && searchResult.records.length > 0) {
            const kbInfo = await prisma.knowledgeBase.findUnique({
              where: { id: kbId },
              select: { name: true },
            });

            // 优化格式：使用[来源N]标记，便于AI引用
            const formattedResult = `【知识库：${kbInfo?.name || '未命名'}】\n` +
              searchResult.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(`Failed to search knowledge base ${kbId}:`, error);
          // 检索失败不阻止对话，继续处理
        }
      }

      if (knowledgeResults.length > 0) {
        knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
      }
    }

    // 组装上下文
    const messages = await this.assembleContext(
      conversationId,
      conversation.agentId,
      conversation.project?.background || '',
      content,
      knowledgeBaseContext
    );

    // 获取LLM适配器
    const adapter = LLMFactory.getAdapter(modelType);

    // 获取智能体配置的模型参数
    const agent = agentService.getAgentById(conversation.agentId);
    const modelConfig = agent?.models?.[modelType];

    // 调用LLM
    const response = await adapter.chat(messages, {
      temperature: modelConfig?.temperature,
      maxTokens: modelConfig?.maxTokens,
      topP: modelConfig?.topP,
    });

    // AI回答完毕后，追加引用清单
    let finalContent = response.content;
    if (allCitations.length > 0) {
      const citationsText = formatCitations(allCitations);
      finalContent += citationsText;
    }

    // 保存用户消息
    const userMessage = await prisma.message.create({
      data: {
        conversationId,
        role: 'user',
        content,
        metadata: {
          knowledgeBaseIds,
        },
      },
    });

    // 保存助手回复
    const assistantMessage = await prisma.message.create({
      data: {
        conversationId,
        role: 'assistant',
        content: finalContent,
        model: response.model,
        tokens: response.usage?.totalTokens,
        metadata: {
          usage: response.usage,
          finishReason: response.finishReason,
        },
      },
    });

    // 更新对话的最后更新时间
    await prisma.conversation.update({
      where: { id: conversationId },
      data: { updatedAt: new Date() },
    });

    return {
      userMessage,
      assistantMessage,
      usage: response.usage,
    };
  }

  /**
   * 发送消息（流式）
   */
  async *sendMessageStream(
    data: SendMessageData,
    userId: string
  ): AsyncGenerator<StreamChunk, void, unknown> {
    const { conversationId, content, modelType, knowledgeBaseIds } = data;

    // 获取对话信息
    const conversation = await this.getConversationById(conversationId, userId);

    // 获取知识库上下文（如果有@知识库）
    console.log('📚 [sendMessageStream] 开始处理知识库', { knowledgeBaseIds });
    let knowledgeBaseContext = '';
    const allCitations: Citation[] = []; // 存储所有引用信息
    let citationCounter = 1; // 全局引用计数器
    
    if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
      const knowledgeResults: string[] = [];
      
      // 对每个知识库进行检索
      for (const kbId of knowledgeBaseIds) {
        try {
          console.log(`🔎 [sendMessageStream] 检索知识库 ${kbId}`);
          const searchResult = await knowledgeBaseService.searchKnowledgeBase(
            userId,
            kbId,
            content,
            15 // Phase 1优化：从3增加到15个最相关的段落
          );

          console.log(`✅ [sendMessageStream] 检索结果`, { 
            kbId,
            recordCount: searchResult.records?.length || 0 
          });

          // 格式化检索结果
          if (searchResult.records && searchResult.records.length > 0) {
            const kbInfo = await prisma.knowledgeBase.findUnique({
              where: { id: kbId },
              select: { name: true },
            });

            // 优化格式：使用[来源N]标记，便于AI引用
            const formattedResult = `【知识库：${kbInfo?.name || '未命名'}】\n` +
              searchResult.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');

            console.log(`📄 [sendMessageStream] 格式化结果长度: ${formattedResult.length} 字符`);
            knowledgeResults.push(formattedResult);
          } else {
            console.warn(`⚠️ [sendMessageStream] 知识库 ${kbId} 没有检索到记录`);
          }
        } catch (error) {
          console.error(`❌ [sendMessageStream] 检索知识库失败 ${kbId}:`, error);
          // 检索失败不阻止对话，继续处理
        }
      }

      if (knowledgeResults.length > 0) {
        knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
        console.log(`💾 [sendMessageStream] 知识库上下文总长度: ${knowledgeBaseContext.length} 字符`);
        console.log(`📚 [sendMessageStream] 收集到 ${allCitations.length} 个引用`);
      } else {
        console.warn('⚠️ [sendMessageStream] 没有构建任何知识库上下文');
      }
    } else {
      console.log('ℹ️ [sendMessageStream] 未选择知识库');
    }

    // 组装上下文
    const messages = await this.assembleContext(
      conversationId,
      conversation.agentId,
      conversation.project?.background || '',
      content,
      knowledgeBaseContext
    );

    // 获取LLM适配器
    const adapter = LLMFactory.getAdapter(modelType);

    // 获取智能体配置的模型参数
    const agent = agentService.getAgentById(conversation.agentId);
    const modelConfig = agent?.models?.[modelType];

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

    // 用于累积完整的回复内容
    let fullContent = '';
    let usage: any = null;

    // 流式调用LLM
    for await (const chunk of adapter.chatStream(messages, {
      temperature: modelConfig?.temperature,
      maxTokens: modelConfig?.maxTokens,
      topP: modelConfig?.topP,
    })) {
      fullContent += chunk.content;
      
      if (chunk.usage) {
        usage = chunk.usage;
      }

      yield chunk;
    }

    // AI回答完毕后，追加引用清单
    if (allCitations.length > 0) {
      console.log(`📚 [sendMessageStream] 追加 ${allCitations.length} 个引用清单`);
      const citationsText = formatCitations(allCitations);
      fullContent += citationsText;
      
      // 将引用清单也流式输出
      yield {
        content: citationsText,
        done: false,
      };
    }

    // 流式输出完成后，保存助手回复
    await prisma.message.create({
      data: {
        conversationId,
        role: 'assistant',
        content: fullContent,
        model: modelType,
        tokens: usage?.totalTokens,
        metadata: {
          usage,
        },
      },
    });

    // 更新对话的最后更新时间
    await prisma.conversation.update({
      where: { id: conversationId },
      data: { updatedAt: new Date() },
    });
  }

  /**
   * 删除对话（软删除）
   */
  async deleteConversation(conversationId: string, userId: string) {
    const conversation = await prisma.conversation.findFirst({
      where: {
        id: conversationId,
        userId,
        deletedAt: null,
      },
    });

    if (!conversation) {
      throw new Error('对话不存在或无权访问');
    }

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

    return { success: true };
  }
}

export const conversationService = new ConversationService();

