/**
 * Zulip客户端核心服务
 *
 * 功能描述：
 * - 封装Zulip REST API调用
 * - 实现API Key验证和错误处理
 * - 提供消息发送、事件队列管理等核心功能
 *
 * 职责分离：
 * - API封装层：封装zulip-js库的底层调用
 * - 错误处理层：统一处理API调用异常和重试逻辑
 * - 实例管理层：管理客户端实例的生命周期
 *
 * 主要方法：
 * - initialize(): 初始化Zulip客户端并验证API Key
 * - sendMessage(): 发送消息到指定Stream/Topic
 * - registerQueue(): 注册事件队列
 * - deregisterQueue(): 注销事件队列
 * - getEvents(): 获取事件队列中的事件
 *
 * 使用场景：
 * - 用户登录时创建和验证Zulip客户端
 * - 消息发送和接收
 * - 事件队列管理
 *
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修正Core层注释措辞，将"业务逻辑"改为"技术实现" (修改者: moyin)
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 更新import路径和注释规范 (修改者: moyin)
 *
 * @author moyin
 * @version 1.0.3
 * @since 2025-12-25
 * @lastModified 2026-01-12
 */

import { Injectable, Logger } from '@nestjs/common';
import { ZulipAPI } from '../zulip.interfaces';

/**
 * Zulip客户端配置接口
 */
export interface ZulipClientConfig {
  username: string;
  apiKey: string;
  realm: string;
}

/**
 * Zulip客户端实例接口
 */
export interface ZulipClientInstance {
  userId: string;
  config: ZulipClientConfig;
  client: any; // zulip-js客户端实例
  queueId?: string;
  lastEventId: number;
  createdAt: Date;
  lastActivity: Date;
  isValid: boolean;
}

/**
 * 发送消息结果接口
 */
export interface SendMessageResult {
  success: boolean;
  messageId?: number;
  error?: string;
}

/**
 * 事件队列注册结果接口
 */
export interface RegisterQueueResult {
  success: boolean;
  queueId?: string;
  lastEventId?: number;
  error?: string;
}

/**
 * 获取事件结果接口
 */
export interface GetEventsResult {
  success: boolean;
  events?: ZulipAPI.Event[];
  error?: string;
}

/**
 * Zulip客户端服务类
 *
 * 职责：
 * - 封装Zulip REST API调用
 * - 处理Zulip客户端的创建和配置
 * - 管理事件队列的注册和轮询
 * - 提供消息发送和接收功能
 *
 * 主要方法：
 * - createClient(): 创建并初始化Zulip客户端
 * - registerQueue(): 注册Zulip事件队列
 * - sendMessage(): 发送消息到Zulip Stream
 * - getEvents(): 获取Zulip事件
 * - validateConfig(): 验证客户端配置
 *
 * 使用场景：
 * - 为每个用户创建独立的Zulip客户端
 * - 处理与Zulip服务器的所有通信
 * - 消息的发送和事件的接收
 * - API调用的错误处理和重试
 */
@Injectable()
export class ZulipClientService {
  private readonly logger = new Logger(ZulipClientService.name);

  constructor() {
    this.logger.log('ZulipClientService初始化完成');
  }

  /**
   * 创建并初始化Zulip客户端
   *
   * 功能描述：
   * 使用提供的配置创建zulip-js客户端实例，并验证API Key的有效性
   *
   * 技术实现：
   * 1. 验证配置参数的完整性
   * 2. 创建zulip-js客户端实例
   * 3. 调用API验证凭证有效性
   * 4. 返回初始化后的客户端实例
   *
   * @param userId 用户ID
   * @param config Zulip客户端配置
   * @returns Promise<ZulipClientInstance> 初始化后的客户端实例
   *
   * @throws Error 当配置无效或API Key验证失败时
   */
  async createClient(userId: string, config: ZulipClientConfig): Promise<ZulipClientInstance> {
    const startTime = Date.now();

    this.logger.log('开始创建Zulip客户端', {
      operation: 'createClient',
      userId,
      realm: config.realm,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 验证配置参数
      this.validateConfig(config);

      // 2. 动态导入zulip-js
      const zulipInit = await this.loadZulipModule();

      // 3. 创建zulip-js客户端实例
      const client = await zulipInit({
        username: config.username,
        apiKey: config.apiKey,
        realm: config.realm,
      });

      // 4. 验证API Key有效性 - 通过获取用户信息
      const profile = await client.users.me.getProfile();

      if (profile.result !== 'success') {
        throw new Error(`API Key验证失败: ${profile.msg || '未知错误'}`);
      }

      const clientInstance: ZulipClientInstance = {
        userId,
        config,
        client,
        lastEventId: -1,
        createdAt: new Date(),
        lastActivity: new Date(),
        isValid: true,
      };

      const duration = Date.now() - startTime;

      this.logger.log('Zulip客户端创建成功', {
        operation: 'createClient',
        userId,
        realm: config.realm,
        userEmail: profile.email,
        duration,
        timestamp: new Date().toISOString(),
      });

      return clientInstance;

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;

      this.logger.error('创建Zulip客户端失败', {
        operation: 'createClient',
        userId,
        realm: config.realm,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      throw new Error(`创建Zulip客户端失败: ${err.message}`);
    }
  }

  /**
   * 验证API Key有效性
   *
   * 功能描述：
   * 通过调用Zulip API验证API Key是否有效
   *
   * @param clientInstance Zulip客户端实例
   * @returns Promise<boolean> API Key是否有效
   */
  async validateApiKey(clientInstance: ZulipClientInstance): Promise<boolean> {
    this.logger.log('验证API Key有效性', {
      operation: 'validateApiKey',
      userId: clientInstance.userId,
      timestamp: new Date().toISOString(),
    });

    try {
      const profile = await clientInstance.client.users.me.getProfile();
      const isValid = profile.result === 'success';

      clientInstance.isValid = isValid;
      clientInstance.lastActivity = new Date();

      this.logger.log('API Key验证完成', {
        operation: 'validateApiKey',
        userId: clientInstance.userId,
        isValid,
        timestamp: new Date().toISOString(),
      });

      return isValid;

    } catch (error) {
      const err = error as Error;

      this.logger.error('API Key验证失败', {
        operation: 'validateApiKey',
        userId: clientInstance.userId,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      clientInstance.isValid = false;
      return false;
    }
  }

  /**
   * 发送消息到指定Stream/Topic
   *
   * 功能描述：
   * 使用Zulip客户端发送消息到指定的Stream和Topic
   *
   * 技术实现：
   * 1. 验证客户端实例有效性
   * 2. 构建消息请求参数
   * 3. 调用Zulip API发送消息
   * 4. 处理响应并返回结果
   *
   * @param clientInstance Zulip客户端实例
   * @param stream 目标Stream名称
   * @param topic 目标Topic名称
   * @param content 消息内容
   * @returns Promise<SendMessageResult> 发送结果
   */
  async sendMessage(
    clientInstance: ZulipClientInstance,
    stream: string,
    topic: string,
    content: string,
  ): Promise<SendMessageResult> {
    const startTime = Date.now();

    this.logger.log('发送消息到Zulip', {
      operation: 'sendMessage',
      userId: clientInstance.userId,
      stream,
      topic,
      contentLength: content.length,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 验证客户端有效性
      if (!clientInstance.isValid) {
        throw new Error('Zulip客户端无效');
      }

      // 2. 构建消息参数
      const params = {
        type: 'stream',
        to: stream,
        subject: topic,
        content: content,
      };

      // 3. 发送消息
      const response = await clientInstance.client.messages.send(params);

      // 4. 更新最后活动时间
      clientInstance.lastActivity = new Date();

      const duration = Date.now() - startTime;

      if (response.result === 'success') {
        this.logger.log('消息发送成功', {
          operation: 'sendMessage',
          userId: clientInstance.userId,
          stream,
          topic,
          messageId: response.id,
          duration,
          timestamp: new Date().toISOString(),
        });

        return {
          success: true,
          messageId: response.id,
        };
      } else {
        this.logger.warn('消息发送失败', {
          operation: 'sendMessage',
          userId: clientInstance.userId,
          stream,
          topic,
          error: response.msg,
          duration,
          timestamp: new Date().toISOString(),
        });

        return {
          success: false,
          error: response.msg || '消息发送失败',
        };
      }

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;

      this.logger.error('发送消息异常', {
        operation: 'sendMessage',
        userId: clientInstance.userId,
        stream,
        topic,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        error: err.message,
      };
    }
  }

  /**
   * 注册事件队列
   *
   * 功能描述：
   * 向Zulip服务器注册事件队列，用于接收消息通知
   *
   * 技术实现：
   * 1. 验证客户端实例有效性
   * 2. 构建队列注册参数
   * 3. 调用Zulip API注册队列
   * 4. 保存队列ID到客户端实例
   *
   * @param clientInstance Zulip客户端实例
   * @param eventTypes 要订阅的事件类型列表
   * @returns Promise<RegisterQueueResult> 注册结果
   */
  async registerQueue(
    clientInstance: ZulipClientInstance,
    eventTypes: string[] = ['message'],
  ): Promise<RegisterQueueResult> {
    const startTime = Date.now();

    this.logger.log('注册Zulip事件队列', {
      operation: 'registerQueue',
      userId: clientInstance.userId,
      eventTypes,
      timestamp: new Date().toISOString(),
    });

    try {
      // 1. 验证客户端有效性
      if (!clientInstance.isValid) {
        throw new Error('Zulip客户端无效');
      }

      // 2. 构建注册参数
      const params = {
        event_types: eventTypes,
      };

      // 3. 注册队列
      const response = await clientInstance.client.queues.register(params);

      const duration = Date.now() - startTime;

      if (response.result === 'success') {
        // 4. 保存队列信息
        clientInstance.queueId = response.queue_id;
        clientInstance.lastEventId = response.last_event_id;
        clientInstance.lastActivity = new Date();

        this.logger.log('事件队列注册成功', {
          operation: 'registerQueue',
          userId: clientInstance.userId,
          queueId: response.queue_id,
          lastEventId: response.last_event_id,
          duration,
          timestamp: new Date().toISOString(),
        });

        return {
          success: true,
          queueId: response.queue_id,
          lastEventId: response.last_event_id,
        };
      } else {
        this.logger.warn('事件队列注册失败', {
          operation: 'registerQueue',
          userId: clientInstance.userId,
          error: response.msg,
          duration,
          timestamp: new Date().toISOString(),
        });

        return {
          success: false,
          error: response.msg || '事件队列注册失败',
        };
      }

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;

      this.logger.error('注册事件队列异常', {
        operation: 'registerQueue',
        userId: clientInstance.userId,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        error: err.message,
      };
    }
  }

  /**
   * 注销事件队列
   *
   * 功能描述：
   * 注销已注册的Zulip事件队列
   *
   * @param clientInstance Zulip客户端实例
   * @returns Promise<boolean> 是否成功注销
   */
  async deregisterQueue(clientInstance: ZulipClientInstance): Promise<boolean> {
    this.logger.log('注销Zulip事件队列', {
      operation: 'deregisterQueue',
      userId: clientInstance.userId,
      queueId: clientInstance.queueId,
      timestamp: new Date().toISOString(),
    });

    try {
      if (!clientInstance.queueId) {
        this.logger.log('无事件队列需要注销', {
          operation: 'deregisterQueue',
          userId: clientInstance.userId,
        });
        return true;
      }

      const response = await clientInstance.client.queues.deregister({
        queue_id: clientInstance.queueId,
      });

      if (response.result === 'success') {
        clientInstance.queueId = undefined;
        clientInstance.lastEventId = -1;

        this.logger.log('事件队列注销成功', {
          operation: 'deregisterQueue',
          userId: clientInstance.userId,
          timestamp: new Date().toISOString(),
        });

        return true;
      } else {
        this.logger.warn('事件队列注销失败', {
          operation: 'deregisterQueue',
          userId: clientInstance.userId,
          error: response.msg,
          timestamp: new Date().toISOString(),
        });

        return false;
      }

    } catch (error) {
      const err = error as Error;

      // 如果是JSON解析错误，说明队列可能已经过期或被删除，这是正常的
      if (err.message.includes('invalid json response') || err.message.includes('Unexpected token')) {
        this.logger.debug('事件队列可能已过期，跳过注销', {
          operation: 'deregisterQueue',
          userId: clientInstance.userId,
          queueId: clientInstance.queueId,
        });

        // 清理本地状态
        clientInstance.queueId = undefined;
        clientInstance.lastEventId = -1;
        return true;
      }

      this.logger.error('注销事件队列异常', {
        operation: 'deregisterQueue',
        userId: clientInstance.userId,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      // 即使注销失败，也清理本地状态
      clientInstance.queueId = undefined;
      clientInstance.lastEventId = -1;

      return false;
    }
  }

  /**
   * 获取事件队列中的事件
   *
   * 功能描述：
   * 从Zulip事件队列中获取新事件
   *
   * @param clientInstance Zulip客户端实例
   * @param dontBlock 是否不阻塞等待新事件
   * @returns Promise<GetEventsResult> 获取结果
   */
  async getEvents(
    clientInstance: ZulipClientInstance,
    dontBlock: boolean = false,
  ): Promise<GetEventsResult> {
    this.logger.debug('获取Zulip事件', {
      operation: 'getEvents',
      userId: clientInstance.userId,
      queueId: clientInstance.queueId,
      lastEventId: clientInstance.lastEventId,
      dontBlock,
      timestamp: new Date().toISOString(),
    });

    try {
      if (!clientInstance.queueId) {
        throw new Error('事件队列未注册');
      }

      const params = {
        queue_id: clientInstance.queueId,
        last_event_id: clientInstance.lastEventId,
        dont_block: dontBlock,
      };

      const response = await clientInstance.client.events.retrieve(params);

      if (response.result === 'success') {
        // 更新最后事件ID
        if (response.events && response.events.length > 0) {
          const lastEvent = response.events[response.events.length - 1];
          clientInstance.lastEventId = lastEvent.id;
        }

        clientInstance.lastActivity = new Date();

        this.logger.debug('获取事件成功', {
          operation: 'getEvents',
          userId: clientInstance.userId,
          eventCount: response.events?.length || 0,
          timestamp: new Date().toISOString(),
        });

        return {
          success: true,
          events: response.events || [],
        };
      } else {
        this.logger.warn('获取事件失败', {
          operation: 'getEvents',
          userId: clientInstance.userId,
          error: response.msg,
          timestamp: new Date().toISOString(),
        });

        return {
          success: false,
          error: response.msg || '获取事件失败',
        };
      }

    } catch (error) {
      const err = error as Error;

      this.logger.error('获取事件异常', {
        operation: 'getEvents',
        userId: clientInstance.userId,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        error: err.message,
      };
    }
  }

  /**
   * 销毁客户端实例
   *
   * 功能描述：
   * 清理客户端资源，注销事件队列
   *
   * @param clientInstance Zulip客户端实例
   * @returns Promise<void>
   */
  async destroyClient(clientInstance: ZulipClientInstance): Promise<void> {
    this.logger.log('销毁Zulip客户端', {
      operation: 'destroyClient',
      userId: clientInstance.userId,
      queueId: clientInstance.queueId,
      timestamp: new Date().toISOString(),
    });

    try {
      // 注销事件队列
      if (clientInstance.queueId) {
        await this.deregisterQueue(clientInstance);
      }

      // 标记客户端为无效
      clientInstance.isValid = false;
      clientInstance.client = null;

      this.logger.log('Zulip客户端销毁完成', {
        operation: 'destroyClient',
        userId: clientInstance.userId,
        timestamp: new Date().toISOString(),
      });

    } catch (error) {
      const err = error as Error;

      this.logger.error('销毁Zulip客户端异常', {
        operation: 'destroyClient',
        userId: clientInstance.userId,
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);

      // 即使出错也标记为无效
      clientInstance.isValid = false;
      clientInstance.client = null;
    }
  }

  /**
   * 验证配置参数
   *
   * @param config Zulip客户端配置
   * @throws Error 当配置无效时
   * @private
   */
  private validateConfig(config: ZulipClientConfig): void {
    if (!config.username || typeof config.username !== 'string') {
      throw new Error('无效的username配置');
    }

    if (!config.apiKey || typeof config.apiKey !== 'string') {
      throw new Error('无效的apiKey配置');
    }

    if (!config.realm || typeof config.realm !== 'string') {
      throw new Error('无效的realm配置');
    }

    // 验证realm是否为有效URL
    try {
      new URL(config.realm);
    } catch {
      throw new Error('realm必须是有效的URL');
    }
  }

  /**
   * 动态加载zulip-js模块
   *
   * @returns Promise<any> zulip-js初始化函数
   * @private
   */
  private async loadZulipModule(): Promise<any> {
    try {
      // 使用动态导入加载zulip-js
      const zulipModule = await import('zulip-js');
      return zulipModule.default || zulipModule;
    } catch (error) {
      const err = error as Error;
      this.logger.error('加载zulip-js模块失败', {
        operation: 'loadZulipModule',
        error: err.message,
        timestamp: new Date().toISOString(),
      }, err.stack);
      throw new Error(`加载zulip-js模块失败: ${err.message}`);
    }
  }
}
