/**
 * Zulip集成主服务
 * 
 * 功能描述：
 * - 作为Zulip集成系统的主要协调服务
 * - 整合各个子服务，提供统一的业务接口
 * - 处理游戏客户端与Zulip之间的核心业务逻辑
 * 
 * 职责分离：
 * - 业务协调：整合会话管理、消息过滤、事件处理等子服务
 * - 流程控制：管理玩家登录登出的完整业务流程
 * - 接口适配：在游戏协议和Zulip协议之间进行转换
 * - 错误处理：统一处理业务异常和降级策略
 * 
 * 主要方法：
 * - handlePlayerLogin(): 处理玩家登录和Zulip客户端初始化
 * - handlePlayerLogout(): 处理玩家登出和资源清理
 * - sendChatMessage(): 处理游戏聊天消息发送到Zulip
 * - processZulipMessage(): 处理从Zulip接收的消息
 * 
 * 使用场景：
 * - WebSocket网关调用处理消息路由
 * - 会话管理和状态维护
 * - 消息格式转换和过滤
 * 
 * 最近修改：
 * - 2026-01-07: 代码规范优化 - 注释规范检查和修正 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 拆分过长方法，提取validateLoginParams和createUserSession私有方法 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 完善文件头注释和修改记录 (修改者: moyin)
 * 
 * @author angjustinl
 * @version 1.2.0
 * @since 2026-01-06
 * @lastModified 2026-01-07
 */

import { Injectable, Logger, Inject } from '@nestjs/common';
import { randomUUID } from 'crypto';
import { SessionManagerService } from './services/session_manager.service';
import { MessageFilterService } from './services/message_filter.service';
import { ZulipEventProcessorService } from './services/zulip_event_processor.service';
import { 
  IZulipClientPoolService,
  IZulipConfigService,
  IApiKeySecurityService,
} from '../../core/zulip_core/zulip_core.interfaces';
import { LoginCoreService } from '../../core/login_core/login_core.service';

/**
 * 玩家登录请求接口
 */
export interface PlayerLoginRequest {
  token: string;
  socketId: string;
}

/**
 * 聊天消息请求接口
 */
export interface ChatMessageRequest {
  socketId: string;
  content: string;
  scope: string;
}

/**
 * 位置更新请求接口
 */
export interface PositionUpdateRequest {
  socketId: string;
  x: number;
  y: number;
  mapId: string;
}

/**
 * 登录响应接口
 */
export interface LoginResponse {
  success: boolean;
  sessionId?: string;
  userId?: string;
  username?: string;
  currentMap?: string;
  error?: string;
}

/**
 * 聊天消息响应接口
 */
export interface ChatMessageResponse {
  success: boolean;
  messageId?: number | string;
  error?: string;
}

/**
 * Zulip集成主服务类
 * 
 * 职责：
 * - 作为Zulip集成系统的主要协调服务
 * - 整合各个子服务，提供统一的业务接口
 * - 处理游戏客户端与Zulip之间的核心业务逻辑
 * - 管理玩家会话和消息路由
 * 
 * 主要方法：
 * - handlePlayerLogin(): 处理玩家登录和Zulip客户端初始化
 * - handlePlayerLogout(): 处理玩家登出和资源清理
 * - sendChatMessage(): 处理游戏聊天消息发送到Zulip
 * - updatePlayerPosition(): 更新玩家位置信息
 * 
 * 使用场景：
 * - WebSocket网关调用处理消息路由
 * - 会话管理和状态维护
 * - 消息格式转换和过滤
 * - 游戏与Zulip的双向通信桥梁
 */
@Injectable()
export class ZulipService {
  private readonly logger = new Logger(ZulipService.name);
  private readonly DEFAULT_MAP = 'whale_port';

  constructor(
    @Inject('ZULIP_CLIENT_POOL_SERVICE')
    private readonly zulipClientPool: IZulipClientPoolService,
    private readonly sessionManager: SessionManagerService,
    private readonly messageFilter: MessageFilterService,
    private readonly eventProcessor: ZulipEventProcessorService,
    @Inject('ZULIP_CONFIG_SERVICE')
    private readonly configManager: IZulipConfigService,
    @Inject('API_KEY_SECURITY_SERVICE')
    private readonly apiKeySecurityService: IApiKeySecurityService,
    private readonly loginCoreService: LoginCoreService,
  ) {
    this.logger.log('ZulipService初始化完成');
    
    // 启动事件处理
    this.initializeEventProcessing();
  }

  /**
   * 处理玩家登录
   * 
   * 功能描述：
   * 验证游戏Token，创建Zulip客户端，建立会话映射关系
   * 
   * 业务逻辑：
   * 1. 验证游戏Token的有效性
   * 2. 获取用户的Zulip API Key
   * 3. 创建用户专用的Zulip客户端实例
   * 4. 注册Zulip事件队列
   * 5. 建立Socket_ID与Zulip_Queue_ID的映射关系
   * 6. 返回登录成功确认
   * 
   * @param request 玩家登录请求数据
   * @returns Promise<LoginResponse>
   * 
   * @throws UnauthorizedException 当Token验证失败时
   * @throws InternalServerErrorException 当系统操作失败时
   * 
   * @example
   * ```typescript
   * const loginRequest: PlayerLoginRequest = {
   *   token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
   *   socketId: 'socket_12345'
   * };
   * const result = await zulipService.handlePlayerLogin(loginRequest);
   * if (result.success) {
   *   console.log(`用户 ${result.username} 登录成功`);
   * }
   * ```
   */
  async handlePlayerLogin(request: PlayerLoginRequest): Promise<LoginResponse> {
    const startTime = Date.now();
    
    this.logger.log('开始处理玩家登录', {
      operation: 'handlePlayerLogin',
      socketId: request.socketId,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 验证请求参数
      const paramValidation = this.validateLoginParams(request);
      if (!paramValidation.isValid) {
        return {
          success: false,
          error: paramValidation.error,
        };
      }

      // 2. 验证游戏Token并获取用户信息
      const userInfo = await this.validateGameToken(request.token);
      if (!userInfo) {
        this.logger.warn('登录失败：Token验证失败', {
          operation: 'handlePlayerLogin',
          socketId: request.socketId,
        });
        return {
          success: false,
          error: 'Token验证失败',
        };
      }

      // 3. 创建Zulip客户端和会话
      const sessionResult = await this.createUserSession(request.socketId, userInfo);
      
      const duration = Date.now() - startTime;
      
      this.logger.log('玩家登录处理完成', {
        operation: 'handlePlayerLogin',
        socketId: request.socketId,
        sessionId: sessionResult.sessionId,
        userId: userInfo.userId,
        username: userInfo.username,
        currentMap: sessionResult.currentMap,
        duration,
        timestamp: new Date().toISOString(),
      });

      return {
        success: true,
        sessionId: sessionResult.sessionId,
        userId: userInfo.userId,
        username: userInfo.username,
        currentMap: sessionResult.currentMap,
      };

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;
      
      this.logger.error('玩家登录处理失败', {
        operation: 'handlePlayerLogin',
        socketId: request.socketId,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        error: '登录失败，请稍后重试',
      };
    }
  }

  /**
   * 验证登录请求参数
   * 
   * @param request 登录请求
   * @returns 验证结果
   * @private
   */
  private validateLoginParams(request: PlayerLoginRequest): { isValid: boolean; error?: string } {
    if (!request.token || !request.token.trim()) {
      this.logger.warn('登录失败：Token为空', {
        operation: 'validateLoginParams',
        socketId: request.socketId,
      });
      return {
        isValid: false,
        error: 'Token不能为空',
      };
    }

    if (!request.socketId || !request.socketId.trim()) {
      this.logger.warn('登录失败：socketId为空', {
        operation: 'validateLoginParams',
      });
      return {
        isValid: false,
        error: 'socketId不能为空',
      };
    }

    return { isValid: true };
  }

  /**
   * 创建用户会话和Zulip客户端
   * 
   * @param socketId Socket连接ID
   * @param userInfo 用户信息
   * @returns 会话创建结果
   * @private
   */
  private async createUserSession(socketId: string, userInfo: any): Promise<{ sessionId: string; currentMap: string }> {
    // 生成会话ID
    const sessionId = randomUUID();

    // 调试日志：检查用户信息
    this.logger.log('用户信息检查', {
      operation: 'createUserSession',
      userId: userInfo.userId,
      hasZulipApiKey: !!userInfo.zulipApiKey,
      zulipApiKeyLength: userInfo.zulipApiKey?.length || 0,
      zulipEmail: userInfo.zulipEmail,
      email: userInfo.email,
    });

    // 创建Zulip客户端（如果有API Key）
    let zulipQueueId = `queue_${sessionId}`;
    
    if (userInfo.zulipApiKey) {
      try {
        const zulipConfig = this.configManager.getZulipConfig();
        const clientInstance = await this.zulipClientPool.createUserClient(userInfo.userId, {
          username: userInfo.zulipEmail || userInfo.email,
          apiKey: userInfo.zulipApiKey,
          realm: zulipConfig.zulipServerUrl,
        });
        
        if (clientInstance.queueId) {
          zulipQueueId = clientInstance.queueId;
        }
        
        this.logger.log('Zulip客户端创建成功', {
          operation: 'createUserSession',
          userId: userInfo.userId,
          queueId: zulipQueueId,
        });
      } catch (zulipError) {
        const err = zulipError as Error;
        this.logger.warn('Zulip客户端创建失败，使用本地模式', {
          operation: 'createUserSession',
          userId: userInfo.userId,
          error: err.message,
        });
        // Zulip客户端创建失败不影响登录，使用本地模式
      }
    }

    // 创建游戏会话
    const session = await this.sessionManager.createSession(
      socketId,
      userInfo.userId,
      zulipQueueId,
      userInfo.username,
      this.DEFAULT_MAP,
      { x: 400, y: 300 },
    );

    return {
      sessionId,
      currentMap: session.currentMap,
    };
  }

  /**
   * 验证游戏Token
   * 
   * 功能描述：
   * 验证游戏Token的有效性，返回用户信息
   * 
   * @param token 游戏Token (JWT)
   * @returns Promise<UserInfo | null> 用户信息，验证失败返回null
   * @private
   */
  private async validateGameToken(token: string): Promise<{
    userId: string;
    username: string;
    email: string;
    zulipEmail?: string;
    zulipApiKey?: string;
  } | null> {
    this.logger.debug('验证游戏Token', {
      operation: 'validateGameToken',
      tokenLength: token.length,
    });

    try {
      // 1. 使用LoginCoreService验证JWT token
      const payload = await this.loginCoreService.verifyToken(token, 'access');

      if (!payload || !payload.sub) {
        this.logger.warn('Token载荷无效', {
          operation: 'validateGameToken',
        });
        return null;
      }

      const userId = payload.sub;
      const username = payload.username || `user_${userId}`;
      const email = payload.email || `${userId}@example.com`;

      this.logger.debug('Token解析成功', {
        operation: 'validateGameToken',
        userId,
        username,
        email,
      });

      // 2. 从ApiKeySecurityService获取真实的Zulip API Key
      let zulipApiKey = undefined;
      let zulipEmail = undefined;
      
      try {
        // 尝试从Redis获取存储的API Key
        const apiKeyResult = await this.apiKeySecurityService.getApiKey(userId);
        
        if (apiKeyResult.success && apiKeyResult.apiKey) {
          zulipApiKey = apiKeyResult.apiKey;
          // 使用游戏账号的邮箱
          zulipEmail = email;
          
          this.logger.log('从存储获取到Zulip API Key', {
            operation: 'validateGameToken',
            userId,
            hasApiKey: true,
            apiKeyLength: zulipApiKey.length,
          });
        } else {
          this.logger.debug('用户没有存储的Zulip API Key', {
            operation: 'validateGameToken',
            userId,
            reason: apiKeyResult.message,
          });
        }
      } catch (error) {
        const err = error as Error;
        this.logger.warn('获取Zulip API Key失败', {
          operation: 'validateGameToken',
          userId,
          error: err.message,
        });
      }
      
      return {
        userId,
        username,
        email,
        zulipEmail,
        zulipApiKey,
      };

    } catch (error) {
      const err = error as Error;
      this.logger.warn('Token验证失败', {
        operation: 'validateGameToken',
        error: err.message,
      });
      return null;
    }
  }

  /**
   * 处理玩家登出
   * 
   * 功能描述：
   * 清理玩家会话，注销Zulip事件队列，释放相关资源
   * 
   * 业务逻辑：
   * 1. 获取会话信息
   * 2. 注销Zulip事件队列
   * 3. 清理Zulip客户端实例
   * 4. 删除会话映射关系
   * 5. 记录登出日志
   * 
   * @param socketId WebSocket连接ID
   * @returns Promise<void>
   */
  async handlePlayerLogout(socketId: string): Promise<void> {
    const startTime = Date.now();
    
    this.logger.log('开始处理玩家登出', {
      operation: 'handlePlayerLogout',
      socketId,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 获取会话信息
      const session = await this.sessionManager.getSession(socketId);
      
      if (!session) {
        this.logger.log('会话不存在，跳过登出处理', {
          operation: 'handlePlayerLogout',
          socketId,
        });
        return;
      }

      // 2. 清理Zulip客户端资源
      if (session.userId) {
        try {
          await this.zulipClientPool.destroyUserClient(session.userId);
          this.logger.log('Zulip客户端清理完成', {
            operation: 'handlePlayerLogout',
            userId: session.userId,
          });
        } catch (zulipError) {
          const err = zulipError as Error;
          this.logger.warn('Zulip客户端清理失败', {
            operation: 'handlePlayerLogout',
            userId: session.userId,
            error: err.message,
          });
          // 继续执行会话清理
        }
      }

      // 3. 删除会话映射
      await this.sessionManager.destroySession(socketId);
      
      const duration = Date.now() - startTime;
      
      this.logger.log('玩家登出处理完成', {
        operation: 'handlePlayerLogout',
        socketId,
        userId: session.userId,
        duration,
        timestamp: new Date().toISOString(),
      });

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;
      
      this.logger.error('玩家登出处理失败', {
        operation: 'handlePlayerLogout',
        socketId,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      // 登出失败不抛出异常，确保连接能够正常断开
    }
  }

  /**
   * 处理聊天消息发送
   * 
   * 功能描述：
   * 处理游戏客户端发送的聊天消息，转发到对应的Zulip Stream/Topic
   * 
   * 业务逻辑：
   * 1. 获取玩家当前位置和会话信息
   * 2. 根据位置确定目标Stream和Topic
   * 3. 进行消息内容过滤和频率检查
   * 4. 使用玩家的Zulip客户端发送消息
   * 5. 返回发送结果确认
   * 
   * @param request 聊天消息请求数据
   * @returns Promise<ChatMessageResponse>
   */
  async sendChatMessage(request: ChatMessageRequest): Promise<ChatMessageResponse> {
    const startTime = Date.now();
    
    this.logger.log('开始处理聊天消息发送', {
      operation: 'sendChatMessage',
      socketId: request.socketId,
      contentLength: request.content.length,
      scope: request.scope,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 获取会话信息
      const session = await this.sessionManager.getSession(request.socketId);
      if (!session) {
        this.logger.warn('发送消息失败：会话不存在', {
          operation: 'sendChatMessage',
          socketId: request.socketId,
        });
        return {
          success: false,
          error: '会话不存在，请重新登录',
        };
      }

      // 2. 上下文注入：根据位置确定目标Stream
      const context = await this.sessionManager.injectContext(request.socketId);
      const targetStream = context.stream;
      const targetTopic = context.topic || 'General';

      // 3. 消息验证（内容过滤、频率限制、权限验证）
      const validationResult = await this.messageFilter.validateMessage(
        session.userId,
        request.content,
        targetStream,
        session.currentMap,
      );

      if (!validationResult.allowed) {
        this.logger.warn('消息验证失败', {
          operation: 'sendChatMessage',
          socketId: request.socketId,
          userId: session.userId,
          reason: validationResult.reason,
        });
        return {
          success: false,
          error: validationResult.reason || '消息发送失败',
        };
      }

      // 使用过滤后的内容（如果有）
      const messageContent = validationResult.filteredContent || request.content;

      // 4. 发送消息到Zulip
      const sendResult = await this.zulipClientPool.sendMessage(
        session.userId,
        targetStream,
        targetTopic,
        messageContent,
      );

      if (!sendResult.success) {
        // Zulip发送失败，记录日志但不影响本地消息显示
        this.logger.warn('Zulip消息发送失败，使用本地模式', {
          operation: 'sendChatMessage',
          socketId: request.socketId,
          userId: session.userId,
          error: sendResult.error,
        });
        
        // 即使Zulip发送失败，也返回成功（本地模式）
        // 实际项目中可以根据需求决定是否返回失败
      }

      const duration = Date.now() - startTime;
      
      this.logger.log('聊天消息发送完成', {
        operation: 'sendChatMessage',
        socketId: request.socketId,
        userId: session.userId,
        targetStream,
        targetTopic,
        zulipSuccess: sendResult.success,
        messageId: sendResult.messageId,
        duration,
        timestamp: new Date().toISOString(),
      });

      return {
        success: true,
        messageId: sendResult.messageId,
      };

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;
      
      this.logger.error('聊天消息发送失败', {
        operation: 'sendChatMessage',
        socketId: request.socketId,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        error: '消息发送失败，请稍后重试',
      };
    }
  }

  /**
   * 更新玩家位置
   * 
   * 功能描述：
   * 更新玩家在游戏世界中的位置信息，用于消息路由和上下文注入
   * 
   * @param request 位置更新请求数据
   * @returns Promise<boolean> 是否更新成功
   */
  async updatePlayerPosition(request: PositionUpdateRequest): Promise<boolean> {
    this.logger.debug('更新玩家位置', {
      operation: 'updatePlayerPosition',
      socketId: request.socketId,
      mapId: request.mapId,
      position: { x: request.x, y: request.y },
      timestamp: new Date().toISOString(),
    });

    try {
      // 验证参数
      if (!request.socketId || !request.socketId.trim()) {
        this.logger.warn('更新位置失败：socketId为空', {
          operation: 'updatePlayerPosition',
        });
        return false;
      }

      if (!request.mapId || !request.mapId.trim()) {
        this.logger.warn('更新位置失败：mapId为空', {
          operation: 'updatePlayerPosition',
          socketId: request.socketId,
        });
        return false;
      }

      // 调用SessionManager更新位置信息
      const result = await this.sessionManager.updatePlayerPosition(
        request.socketId,
        request.mapId,
        request.x,
        request.y,
      );

      if (result) {
        this.logger.debug('玩家位置更新成功', {
          operation: 'updatePlayerPosition',
          socketId: request.socketId,
          mapId: request.mapId,
        });
      }

      return result;

    } catch (error) {
      const err = error as Error;
      this.logger.error('更新玩家位置失败', {
        operation: 'updatePlayerPosition',
        socketId: request.socketId,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return false;
    }
  }

  /**
   * 处理从Zulip接收的消息
   * 
   * 功能描述：
   * 处理Zulip事件队列推送的消息，转换格式后发送给相关的游戏客户端
   * 
   * @param zulipMessage Zulip消息对象
   * @returns Promise<{targetSockets: string[], message: any}>
   */
  async processZulipMessage(zulipMessage: any): Promise<{
    targetSockets: string[];
    message: {
      t: string;
      from: string;
      txt: string;
      bubble: boolean;
    };
  }> {
    this.logger.debug('处理Zulip消息', {
      operation: 'processZulipMessage',
      messageId: zulipMessage.id,
      stream: zulipMessage.stream_id,
      sender: zulipMessage.sender_email,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 根据Stream确定目标地图
      const streamName = zulipMessage.display_recipient || zulipMessage.stream_name;
      const mapId = this.configManager.getMapIdByStream(streamName);
      
      if (!mapId) {
        this.logger.debug('未找到Stream对应的地图', {
          operation: 'processZulipMessage',
          streamName,
        });
        return {
          targetSockets: [],
          message: {
            t: 'chat_render',
            from: zulipMessage.sender_full_name || 'Unknown',
            txt: zulipMessage.content || '',
            bubble: true,
          },
        };
      }

      // 2. 获取目标地图中的所有玩家Socket
      const targetSockets = await this.sessionManager.getSocketsInMap(mapId);

      // 3. 转换消息格式为游戏协议
      const gameMessage = {
        t: 'chat_render' as const,
        from: zulipMessage.sender_full_name || 'Unknown',
        txt: zulipMessage.content || '',
        bubble: true,
      };

      this.logger.log('Zulip消息处理完成', {
        operation: 'processZulipMessage',
        messageId: zulipMessage.id,
        mapId,
        targetCount: targetSockets.length,
      });

      return {
        targetSockets,
        message: gameMessage,
      };

    } catch (error) {
      const err = error as Error;
      this.logger.error('处理Zulip消息失败', {
        operation: 'processZulipMessage',
        messageId: zulipMessage.id,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        targetSockets: [],
        message: {
          t: 'chat_render',
          from: 'System',
          txt: '',
          bubble: false,
        },
      };
    }
  }

  /**
   * 获取会话信息
   * 
   * 功能描述：
   * 根据socketId获取会话信息
   * 
   * @param socketId WebSocket连接ID
   * @returns Promise<GameSession | null>
   */
  async getSession(socketId: string) {
    return this.sessionManager.getSession(socketId);
  }

  /**
   * 获取地图中的所有Socket
   * 
   * 功能描述：
   * 获取指定地图中所有在线玩家的Socket ID列表
   * 
   * @param mapId 地图ID
   * @returns Promise<string[]>
   */
  async getSocketsInMap(mapId: string): Promise<string[]> {
    return this.sessionManager.getSocketsInMap(mapId);
  }

  /**
   * 获取事件处理器实例
   * 
   * 功能描述：
   * 返回ZulipEventProcessorService实例，用于设置消息分发器
   * 
   * @returns ZulipEventProcessorService 事件处理器实例
   */
  getEventProcessor(): ZulipEventProcessorService {
    return this.eventProcessor;
  }

  /**
   * 初始化事件处理
   * 
   * 功能描述：
   * 启动Zulip事件处理循环，用于接收和处理从Zulip服务器返回的消息
   * 
   * @private
   */
  private async initializeEventProcessing(): Promise<void> {
    try {
      this.logger.log('开始初始化Zulip事件处理');
      
      // 启动事件处理循环
      await this.eventProcessor.startEventProcessing();
      
      this.logger.log('Zulip事件处理初始化完成');
    } catch (error) {
      const err = error as Error;
      this.logger.error('初始化Zulip事件处理失败', {
        operation: 'initializeEventProcessing',
        error: err.message,
      }, err.stack);
    }
  }
}

