import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { Prisma } from '@prisma/client';
import { Observable, Subject } from 'rxjs';
import { LLMService } from '../llm/llm.service';
import { PromptService } from '../prompt/prompt.service';
import {
  CreateConversationDto,
  SendMessageDto,
  QueryConversationDto,
  ConversationStatus,
  ConversationCategory,
  MessageRole,
  MessageSource,
} from '../dto';
import {
  ConversationNotFoundException,
  ConversationAccessDeniedException,
  ConversationClosedException,
  MessageNotFoundException,
} from '../exceptions';
import { ChatMessage } from '../llm/interfaces/llm-provider.interface';

/**
 * 对话服务
 */
@Injectable()
export class ChatService {
  private readonly logger = new Logger(ChatService.name);
  private readonly CONTEXT_WINDOW_SIZE = 10; // 上下文窗口大小

  constructor(
    private readonly prisma: PrismaService,
    private readonly llmService: LLMService,
    private readonly promptService: PromptService,
  ) {}

  // ==================== 对话管理 ====================

  /**
   * 创建新对话
   */
  async createConversation(
    dto: CreateConversationDto,
    userId: string,
  ) {
    const conversation = await this.prisma.aIConversation.create({
      data: {
        userId,
        title: dto.title || '新对话',
        category: dto.category || 'GENERAL',
        status: 'ACTIVE',
        tags: [],
      },
    });

    this.logger.log(`创建对话: ${conversation.id}`);

    return this.formatConversation(conversation);
  }

  /**
   * 获取对话列表
   */
  async findConversations(
    query: QueryConversationDto,
    userId: string,
  ) {
    const {
      page = 1,
      limit = 20,
      status,
      category,
      keyword,
      startDate,
      endDate,
      sortBy = 'updatedAt',
      sortOrder = 'desc',
    } = query;

    const where: Prisma.AIConversationWhereInput = {
      userId,
    };

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

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

    if (keyword) {
      where.OR = [
        { title: { contains: keyword, mode: 'insensitive' } },
      ];
    }

    if (startDate || endDate) {
      where.createdAt = {};
      if (startDate) {
        where.createdAt.gte = new Date(startDate);
      }
      if (endDate) {
        where.createdAt.lte = new Date(endDate);
      }
    }

    const [total, conversations] = await Promise.all([
      this.prisma.aIConversation.count({ where }),
      this.prisma.aIConversation.findMany({
        where,
        orderBy: { [sortBy]: sortOrder },
        skip: (page - 1) * limit,
        take: limit,
        include: {
          messages: {
            take: 1,
            orderBy: { createdAt: 'desc' },
          },
          _count: {
            select: { messages: true },
          },
        },
      }),
    ]);

    const totalPages = Math.ceil(total / limit);

    return {
      items: conversations.map((conv) => ({
        id: conv.id,
        title: conv.title,
        category: conv.category,
        status: conv.status,
        tags: conv.tags,
        lastMessage: conv.messages[0]?.content?.substring(0, 100) || null,
        messageCount: conv._count.messages,
        createdAt: conv.createdAt,
        updatedAt: conv.updatedAt,
      })),
      total,
      page,
      limit,
      totalPages,
      hasNext: page < totalPages,
      hasPrev: page > 1,
    };
  }

  /**
   * 获取对话详情
   */
  async findConversation(id: string, userId: string) {
    const conversation = await this.prisma.aIConversation.findFirst({
      where: { id },
      include: {
        messages: {
          orderBy: { createdAt: 'asc' },
          include: {
            feedback: true,
          },
        },
      },
    });

    if (!conversation) {
      throw new ConversationNotFoundException(id);
    }

    if (conversation.userId !== userId) {
      throw new ConversationAccessDeniedException();
    }

    return this.formatConversationDetail(conversation);
  }

  /**
   * 删除对话
   */
  async deleteConversation(id: string, userId: string) {
    const conversation = await this.prisma.aIConversation.findFirst({
      where: { id },
    });

    if (!conversation) {
      throw new ConversationNotFoundException(id);
    }

    if (conversation.userId !== userId) {
      throw new ConversationAccessDeniedException();
    }

    // 软删除：更新状态为 CLOSED
    await this.prisma.aIConversation.update({
      where: { id },
      data: { status: 'CLOSED' },
    });

    this.logger.log(`删除对话: ${id}`);

    return { success: true };
  }

  // ==================== 消息管理 ====================

  /**
   * 发送消息
   */
  async sendMessage(
    conversationId: string,
    dto: SendMessageDto,
    userId: string,
  ) {
    // 验证对话
    const conversation = await this.prisma.aIConversation.findFirst({
      where: { id: conversationId },
    });

    if (!conversation) {
      throw new ConversationNotFoundException(conversationId);
    }

    if (conversation.userId !== userId) {
      throw new ConversationAccessDeniedException();
    }

    if (conversation.status === 'CLOSED') {
      throw new ConversationClosedException();
    }

    // 保存用户消息
    const userMessage = await this.prisma.aIMessage.create({
      data: {
        conversationId,
        role: 'USER',
        source: 'USER',
        content: dto.content,
      },
    });

    // 创建 AI 消息占位符
    const aiMessage = await this.prisma.aIMessage.create({
      data: {
        conversationId,
        role: 'ASSISTANT',
        source: 'AI',
        content: '', // 初始为空，流式更新
      },
    });

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

    return {
      userMessage: {
        id: userMessage.id,
        role: userMessage.role,
        source: userMessage.source,
        content: userMessage.content,
        createdAt: userMessage.createdAt,
      },
      streamUrl: `/api/v1/ai-assistant/conversations/${conversationId}/messages/stream?messageId=${aiMessage.id}`,
      aiMessageId: aiMessage.id,
    };
  }

  /**
   * 获取 AI 流式回复
   */
  async streamReply(
    conversationId: string,
    messageId: string,
    userId: string,
  ): Promise<Observable<MessageEvent>> {
    // 创建 Observable（必须立即创建并返回，以便SSE stream可以开始）
    const subject = new Subject<MessageEvent>();
    let fullContent = '';

    // 异步执行验证和流式响应（在Observable内部执行）
    (async () => {
      try {
        // 验证对话
        const conversation = await this.prisma.aIConversation.findFirst({
          where: { id: conversationId },
          include: {
            messages: {
              orderBy: { createdAt: 'desc' },
              take: this.CONTEXT_WINDOW_SIZE * 2,
            },
          },
        });

        if (!conversation) {
          throw new ConversationNotFoundException(conversationId);
        }

        if (conversation.userId !== userId) {
          throw new ConversationAccessDeniedException();
        }

        // 验证消息
        const aiMessage = await this.prisma.aIMessage.findFirst({
          where: { id: messageId, conversationId },
        });

        if (!aiMessage) {
          throw new MessageNotFoundException(messageId);
        }

        // 构建上下文
        const contextMessages = await this.buildContext(conversation);

        // 执行流式响应
        await this.executeStreamReply(
          contextMessages,
          messageId,
          subject,
          (content) => {
            fullContent = content;
          },
        );
      } catch (error) {
        this.logger.error('Stream reply error:', error);
        
        // 发送错误事件到流中（不使用 subject.error，避免触发异常处理）
        try {
          subject.next({
            data: JSON.stringify({
              type: 'error',
              error: error.message || 'Unknown error',
            }),
          } as MessageEvent);
        } catch (e) {
          this.logger.error('Failed to send error event:', e);
        } finally {
          // 始终 complete，不使用 subject.error
          subject.complete();
        }
      }
    })();

    return subject.asObservable();
  }

  /**
   * 执行流式回复
   */
  private async executeStreamReply(
    messages: ChatMessage[],
    messageId: string,
    subject: Subject<MessageEvent>,
    onContent: (content: string) => void,
  ): Promise<void> {
    try {
      const result = await this.llmService.streamChat(
        messages,
        {
          onToken: (token) => {
            subject.next({
              data: JSON.stringify({ content: token }),
            } as MessageEvent);
          },
          onComplete: async (content, usage) => {
            onContent(content);

            // 更新数据库中的消息
            await this.prisma.aIMessage.update({
              where: { id: messageId },
              data: {
                content,
                tokens: usage?.totalTokens,
              },
            });

            subject.next({
              data: JSON.stringify({
                type: 'done',
                messageId,
                totalTokens: usage?.totalTokens || 0,
              }),
            } as MessageEvent);

            subject.complete();
          },
          onError: (error) => {
            // 发送降级消息
            const fallbackMessage = this.llmService.getFallbackMessage();
            
            subject.next({
              data: JSON.stringify({
                type: 'fallback',
                content: fallbackMessage,
              }),
            } as MessageEvent);

            // 保存降级消息到数据库
            this.prisma.aIMessage.update({
              where: { id: messageId },
              data: {
                content: fallbackMessage,
                metadata: { isFallback: true },
              },
            }).catch((err) => {
              this.logger.error('Failed to save fallback message:', err);
            });

            subject.complete();
          },
        },
      );

      // 处理 PII 警告
      if (result.piiWarnings.length > 0) {
        this.logger.warn('PII warnings:', result.piiWarnings);
      }
    } catch (error) {
      this.logger.error('Execute stream reply error:', error);
      
      // 发送错误事件到流中（不抛出异常，避免触发headers修改）
      try {
        subject.next({
          data: JSON.stringify({
            type: 'error',
            error: error.message || 'Stream processing failed',
          }),
        } as MessageEvent);
      } catch (e) {
        this.logger.error('Failed to send error event in executeStreamReply:', e);
      } finally {
        // 始终 complete，即使发送错误消息失败
        subject.complete();
      }
    }
  }

  /**
   * 构建对话上下文
   */
  private async buildContext(conversation: any): Promise<ChatMessage[]> {
    const messages: ChatMessage[] = [];

    // 获取 System Prompt
    const systemPrompt = await this.promptService.getActivePrompt(
      conversation.category,
    );

    if (systemPrompt) {
      messages.push({
        role: 'system',
        content: systemPrompt,
      });
    } else {
      // 默认 System Prompt
      messages.push({
        role: 'system',
        content: this.getDefaultSystemPrompt(conversation.category),
      });
    }

    // 添加历史消息
    const historyMessages = conversation.messages
      .reverse() // 按时间正序
      .slice(-this.CONTEXT_WINDOW_SIZE * 2)
      .filter((m: any) => m.content) // 过滤空消息
      .map((m: any) => ({
        role: m.role.toLowerCase() as 'user' | 'assistant',
        content: m.content,
      }));

    messages.push(...historyMessages);

    return messages;
  }

  /**
   * 获取默认 System Prompt
   */
  private getDefaultSystemPrompt(category: string): string {
    const categoryPrompts: Record<string, string> = {
      IT: `你是企业 IT 支持助手。你的职责是帮助员工解决 IT 相关问题，包括但不限于：
- 密码重置和账户问题
- VPN 连接和网络问题
- 软件安装和使用
- 邮箱配置和问题

请提供清晰、步骤化的解决方案。如果问题超出你的能力范围，请建议用户使用"转人工"功能。`,

      HR: `你是企业 HR 咨询助手。你的职责是帮助员工了解公司政策和人事相关事宜，包括但不限于：
- 请假和考勤政策
- 福利和社保查询
- 报销流程和规定
- 入离职流程

请根据公司政策提供准确的信息。如果不确定，请建议用户咨询 HR 部门。`,

      ADMIN: `你是企业行政服务助手。你的职责是帮助员工处理行政相关事务，包括但不限于：
- 会议室预约
- 办公用品申请
- 访客登记
- 快递收发

请提供清晰的流程指引。`,

      GENERAL: `你是企业智能助手。你的职责是帮助员工解答各类问题，提供信息查询和服务指引。

如果问题涉及特定部门（IT、HR、行政），请提供基本信息并建议用户联系相关部门获取详细支持。`,
    };

    return categoryPrompts[category] || categoryPrompts.GENERAL;
  }

  // ==================== 数据格式化 ====================

  private formatConversation(conversation: any) {
    return {
      id: conversation.id,
      userId: conversation.userId,
      title: conversation.title,
      category: conversation.category,
      status: conversation.status,
      tags: conversation.tags,
      createdAt: conversation.createdAt,
      updatedAt: conversation.updatedAt,
    };
  }

  private formatConversationDetail(conversation: any) {
    return {
      id: conversation.id,
      userId: conversation.userId,
      title: conversation.title,
      category: conversation.category,
      status: conversation.status,
      tags: conversation.tags,
      messages: conversation.messages.map((m: any) => ({
        id: m.id,
        role: m.role,
        source: m.source,
        content: m.content,
        feedback: m.feedback
          ? {
              type: m.feedback.type,
            }
          : null,
        createdAt: m.createdAt,
      })),
      createdAt: conversation.createdAt,
      updatedAt: conversation.updatedAt,
    };
  }
}

/**
 * 消息事件类型
 */
interface MessageEvent {
  data: string;
}
