import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { ChatMessage } from '../interfaces/llm-provider.interface';

/**
 * 对话记忆服务
 * 
 * 功能：
 * 1. 从数据库加载历史消息
 * 2. 管理上下文窗口大小
 * 3. 支持消息摘要（后续可扩展）
 */
@Injectable()
export class MemoryService {
  private readonly logger = new Logger(MemoryService.name);
  
  /**
   * 默认上下文窗口大小（消息条数）
   * 包含用户消息和 AI 回复
   */
  private readonly DEFAULT_CONTEXT_SIZE = 10;
  
  /**
   * 最大 token 限制（粗略估计）
   */
  private readonly MAX_CONTEXT_TOKENS = 4000;

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 获取对话历史消息
   * 
   * @param conversationId 对话 ID
   * @param limit 获取的消息数量（默认 10 条）
   * @returns ChatMessage 数组
   */
  async getConversationHistory(
    conversationId: string,
    limit: number = this.DEFAULT_CONTEXT_SIZE,
  ): Promise<ChatMessage[]> {
    try {
      const messages = await this.prisma.aIMessage.findMany({
        where: { conversationId },
        orderBy: { createdAt: 'desc' },
        take: limit,
        select: {
          role: true,
          content: true,
          createdAt: true,
        },
      });

      // 反转顺序（从旧到新）
      const orderedMessages = messages.reverse();

      return orderedMessages.map((msg) => ({
        role: msg.role.toLowerCase() as 'user' | 'assistant' | 'system',
        content: msg.content,
      }));
    } catch (error) {
      this.logger.error(`获取对话历史失败: ${conversationId}`, error);
      return [];
    }
  }

  /**
   * 获取格式化的上下文消息
   * 包含系统提示词
   * 
   * @param conversationId 对话 ID
   * @param systemPrompt 系统提示词
   * @param currentMessage 当前用户消息
   * @param limit 历史消息数量
   * @returns 完整的消息列表
   */
  async getContextMessages(
    conversationId: string,
    systemPrompt: string,
    currentMessage: string,
    limit: number = this.DEFAULT_CONTEXT_SIZE,
  ): Promise<ChatMessage[]> {
    const history = await this.getConversationHistory(conversationId, limit);
    
    const messages: ChatMessage[] = [
      { role: 'system', content: systemPrompt },
      ...history,
      { role: 'user', content: currentMessage },
    ];

    // 简单的 token 限制（粗略估计：1 个字符 ≈ 0.5 token）
    return this.trimToTokenLimit(messages, this.MAX_CONTEXT_TOKENS);
  }

  /**
   * 裁剪消息到 token 限制内
   * 保留系统消息和最近的对话
   */
  private trimToTokenLimit(
    messages: ChatMessage[],
    maxTokens: number,
  ): ChatMessage[] {
    // 粗略估计 token 数
    const estimateTokens = (text: string): number => {
      // 中文：1 字符 ≈ 1.5 tokens
      // 英文：1 字符 ≈ 0.25 tokens
      const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
      const otherChars = text.length - chineseChars;
      return Math.ceil(chineseChars * 1.5 + otherChars * 0.25);
    };

    let totalTokens = 0;
    const result: ChatMessage[] = [];

    // 首先添加系统消息（必须保留）
    const systemMessage = messages.find((m) => m.role === 'system');
    if (systemMessage) {
      totalTokens += estimateTokens(systemMessage.content);
      result.push(systemMessage);
    }

    // 从后往前添加消息，确保最近的对话优先
    const nonSystemMessages = messages.filter((m) => m.role !== 'system');
    const reversedMessages = [...nonSystemMessages].reverse();

    const messagesToAdd: ChatMessage[] = [];
    for (const msg of reversedMessages) {
      const msgTokens = estimateTokens(msg.content);
      if (totalTokens + msgTokens > maxTokens) {
        break;
      }
      totalTokens += msgTokens;
      messagesToAdd.unshift(msg);
    }

    result.push(...messagesToAdd);
    return result;
  }

  /**
   * 获取对话摘要（用于长对话）
   * 后续可以使用 LLM 生成摘要
   */
  async getConversationSummary(conversationId: string): Promise<string | null> {
    try {
      const messages = await this.prisma.aIMessage.findMany({
        where: { conversationId },
        orderBy: { createdAt: 'asc' },
        take: 20,
        select: {
          role: true,
          content: true,
        },
      });

      if (messages.length < 5) {
        return null; // 对话太短，不需要摘要
      }

      // 简单摘要：提取关键问题
      const userMessages = messages.filter((m) => m.role === 'USER');
      const topics = userMessages
        .map((m) => m.content.substring(0, 50))
        .join('; ');

      return `对话主题: ${topics}`;
    } catch (error) {
      this.logger.error(`获取对话摘要失败: ${conversationId}`, error);
      return null;
    }
  }

  /**
   * 清除对话记忆（软删除）
   */
  async clearMemory(conversationId: string): Promise<void> {
    try {
      await this.prisma.aIConversation.update({
        where: { id: conversationId },
        data: { status: 'CLOSED' },
      });
      this.logger.log(`清除对话记忆: ${conversationId}`);
    } catch (error) {
      this.logger.error(`清除对话记忆失败: ${conversationId}`, error);
    }
  }
}
