import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { LangChainProvider } from './providers/langchain.provider';
import { MemoryService } from './memory/memory.service';
import { PIIService } from '../security/pii.service';
import { PromptGuardService } from '../security/prompt-guard.service';
import { OutputFilterService } from '../security/output-filter.service';
import {
  ChatMessage,
  ChatOptions,
  StreamCallbacks,
} from './interfaces/llm-provider.interface';
import {
  LLMServiceException,
  LLMRateLimitException,
  PromptInjectionDetectedException,
} from '../exceptions';

/**
 * LLM 服务
 * 
 * 使用 LangChain 统一管理 LLM 调用，集成安全防护和对话记忆
 * 
 * 特性:
 * - 多模型支持 (OpenAI, 通义千问, Mock)
 * - 对话记忆管理
 * - 安全防护 (PII 脱敏, Prompt 注入检测)
 * - 输出过滤
 * - 失败重试和降级
 * 
 * 环境变量配置:
 * - LLM_PROVIDER: openai | qwen | mock | auto (默认 auto)
 * - LLM_USE_MOCK: true 强制使用 mock
 * - OPENAI_API_KEY: OpenAI API Key
 * - DASHSCOPE_API_KEY: 通义千问 API Key
 */
@Injectable()
export class LLMService implements OnModuleInit {
  private readonly logger = new Logger(LLMService.name);
  private consecutiveFailures = 0;
  private readonly MAX_FAILURES = 3;
  private lastAlertTime: Date | null = null;
  private readonly ALERT_COOLDOWN = 5 * 60 * 1000; // 5分钟

  /**
   * Fallback 消息模板
   */
  private readonly fallbackMessage = `抱歉，智能助手服务暂时不可用，请稍后重试。

如问题紧急，请通过以下方式联系支持：
- IT 问题：发送邮件至 it-support@company.com
- HR 问题：发送邮件至 hr@company.com
- 或直接创建工单获取人工支持`;

  constructor(
    private readonly configService: ConfigService,
    private readonly langchainProvider: LangChainProvider,
    private readonly memoryService: MemoryService,
    private readonly piiService: PIIService,
    private readonly promptGuardService: PromptGuardService,
    private readonly outputFilterService: OutputFilterService,
  ) {}

  /**
   * 模块初始化后记录 Provider 信息
   */
  async onModuleInit() {
    // 等待 LangChainProvider 初始化完成后再打印日志
    this.logger.log(
      `LLM Service 使用: ${this.langchainProvider.getProviderType()} (${this.langchainProvider.getModelName()})`,
    );
  }

  /**
   * 获取当前使用的 Provider 名称
   */
  getProviderName(): string {
    return `${this.langchainProvider.getProviderType()} (${this.langchainProvider.getModelName()})`;
  }

  /**
   * 发送聊天消息（安全增强版）
   * 
   * @param messages 消息列表
   * @param options 选项
   * @returns 响应
   */
  async chat(
    messages: ChatMessage[],
    options?: ChatOptions & { skipSecurity?: boolean },
  ): Promise<LLMChatResult> {
    const piiWarnings: string[] = [];

    // 1. 安全检查（用户消息）
    if (!options?.skipSecurity) {
      const userMessage = messages.find((m) => m.role === 'user');
      if (userMessage) {
        // 检测 Prompt 注入
        const injectionResult = this.promptGuardService.detectInjection(
          userMessage.content,
        );
        if (injectionResult.isAttack && injectionResult.riskLevel !== 'low') {
          throw new PromptInjectionDetectedException();
        }

        // PII 脱敏
        const piiResult = this.piiService.sanitize(userMessage.content);
        if (piiResult.wasSanitized) {
          userMessage.content = piiResult.sanitized;
          piiWarnings.push(...piiResult.warnings);
        }
      }

      // 增强 System Prompt
      const systemMessage = messages.find((m) => m.role === 'system');
      if (systemMessage) {
        systemMessage.content = this.promptGuardService.getSecureSystemPrompt(
          systemMessage.content,
        );
      }
    }

    // 2. 调用 LLM (使用 LangChain)
    try {
      const response = await this.langchainProvider.chat(messages, options);

      // 重置失败计数
      this.consecutiveFailures = 0;

      // 3. 输出过滤
      const filteredResult = this.outputFilterService.filter(response.content);

      return {
        content: filteredResult.filtered,
        usage: response.usage,
        piiWarnings,
        wasFiltered: filteredResult.wasFiltered,
      };
    } catch (error) {
      return this.handleError(error);
    }
  }

  /**
   * 带上下文记忆的聊天
   * 
   * @param conversationId 对话 ID
   * @param systemPrompt 系统提示词
   * @param userMessage 用户消息
   * @param options 选项
   */
  async chatWithMemory(
    conversationId: string,
    systemPrompt: string,
    userMessage: string,
    options?: ChatOptions & { skipSecurity?: boolean; contextSize?: number },
  ): Promise<LLMChatResult> {
    const contextSize = options?.contextSize || 10;

    // 获取带上下文的消息
    const messages = await this.memoryService.getContextMessages(
      conversationId,
      systemPrompt,
      userMessage,
      contextSize,
    );

    return this.chat(messages, options);
  }

  /**
   * 流式聊天（安全增强版）
   */
  async streamChat(
    messages: ChatMessage[],
    callbacks: StreamCallbacks,
    options?: ChatOptions & { skipSecurity?: boolean },
  ): Promise<{ piiWarnings: string[] }> {
    const piiWarnings: string[] = [];

    // 1. 安全检查
    if (!options?.skipSecurity) {
      const userMessage = messages.find((m) => m.role === 'user');
      if (userMessage) {
        const injectionResult = this.promptGuardService.detectInjection(
          userMessage.content,
        );
        if (injectionResult.isAttack && injectionResult.riskLevel !== 'low') {
          throw new PromptInjectionDetectedException();
        }

        const piiResult = this.piiService.sanitize(userMessage.content);
        if (piiResult.wasSanitized) {
          userMessage.content = piiResult.sanitized;
          piiWarnings.push(...piiResult.warnings);
        }
      }

      const systemMessage = messages.find((m) => m.role === 'system');
      if (systemMessage) {
        systemMessage.content = this.promptGuardService.getSecureSystemPrompt(
          systemMessage.content,
        );
      }
    }

    // 2. 流式调用 (使用 LangChain)
    const wrappedCallbacks: StreamCallbacks = {
      onToken: (token) => {
        callbacks.onToken(token);
      },
      onComplete: (content, usage) => {
        this.consecutiveFailures = 0;

        // 输出过滤
        const filteredResult = this.outputFilterService.filter(content);
        callbacks.onComplete(filteredResult.filtered, usage);
      },
      onError: (error) => {
        this.handleStreamError(error, callbacks);
      },
    };

    try {
      await this.langchainProvider.streamChat(messages, wrappedCallbacks, options);
    } catch (error) {
      this.handleStreamError(error as Error, callbacks);
    }

    return { piiWarnings };
  }

  /**
   * 带上下文记忆的流式聊天
   */
  async streamChatWithMemory(
    conversationId: string,
    systemPrompt: string,
    userMessage: string,
    callbacks: StreamCallbacks,
    options?: ChatOptions & { skipSecurity?: boolean; contextSize?: number },
  ): Promise<{ piiWarnings: string[] }> {
    const contextSize = options?.contextSize || 10;

    // 获取带上下文的消息
    const messages = await this.memoryService.getContextMessages(
      conversationId,
      systemPrompt,
      userMessage,
      contextSize,
    );

    return this.streamChat(messages, callbacks, options);
  }

  /**
   * 检查服务是否可用
   */
  async isAvailable(): Promise<boolean> {
    return this.langchainProvider.isAvailable();
  }

  /**
   * 获取 Fallback 消息
   */
  getFallbackMessage(): string {
    return this.fallbackMessage;
  }

  /**
   * 处理错误
   */
  private handleError(error: any): never {
    this.consecutiveFailures++;
    this.logger.error('LLM call failed:', error);

    // 检查是否需要告警
    this.checkAndAlert();

    // 根据错误类型抛出对应异常
    if (error?.status === 429) {
      throw new LLMRateLimitException();
    }

    throw new LLMServiceException(
      this.consecutiveFailures >= this.MAX_FAILURES
        ? this.fallbackMessage
        : undefined,
    );
  }

  /**
   * 处理流式错误
   */
  private handleStreamError(error: Error, callbacks: StreamCallbacks): void {
    this.consecutiveFailures++;
    this.logger.error('LLM stream failed:', error);

    // 检查是否需要告警
    this.checkAndAlert();

    // 返回 Fallback 消息
    if (this.consecutiveFailures >= this.MAX_FAILURES) {
      callbacks.onError(new Error(this.fallbackMessage));
    } else {
      callbacks.onError(error);
    }
  }

  /**
   * 检查并发送告警
   */
  private checkAndAlert(): void {
    if (this.consecutiveFailures >= this.MAX_FAILURES) {
      const now = new Date();

      // 检查告警冷却
      if (
        !this.lastAlertTime ||
        now.getTime() - this.lastAlertTime.getTime() > this.ALERT_COOLDOWN
      ) {
        this.lastAlertTime = now;

        this.logger.error(
          `[CRITICAL] AI Assistant LLM Service Down - 连续失败 ${this.consecutiveFailures} 次`,
        );

        // TODO: 集成告警系统（如 Alertmanager）
      }
    }
  }
}

/**
 * LLM 聊天结果
 */
export interface LLMChatResult {
  content: string;
  usage: {
    promptTokens: number;
    completionTokens: number;
    totalTokens: number;
  };
  piiWarnings: string[];
  wasFiltered: boolean;
}
