/**
 * Zulip账号关联服务（内存版本）
 * 
 * 功能描述：
 * - 提供Zulip账号关联的内存存储实现和完整业务逻辑
 * - 用于开发和测试环境，无需数据库依赖
 * - 实现与数据库版本相同的接口和功能特性
 * - 支持数据导入导出和测试数据管理
 * 
 * 职责分离：
 * - 业务逻辑：实现完整的账号关联业务流程和规则
 * - 内存存储：通过内存Repository提供数据持久化
 * - 异常处理：统一的错误处理和业务异常转换
 * - 接口兼容：与数据库版本保持完全一致的API接口
 * 
 * 最近修改：
 * - 2026-01-07: 代码规范优化 - 使用统一的常量文件，提高代码质量
 * - 2026-01-07: 代码规范优化 - 修复导入路径，完善方法三级注释
 * - 2026-01-07: 代码规范优化 - 完善文件头注释和方法三级注释
 * - 2026-01-07: 功能完善 - 优化异常处理逻辑和日志记录
 * - 2025-01-07: 架构优化 - 统一Service层的职责边界和接口设计
 * 
 * @author angjustinl
 * @version 1.1.1
 * @since 2025-01-07
 * @lastModified 2026-01-07
 */

import { Injectable, Inject, ConflictException, NotFoundException } from '@nestjs/common';
import { BaseZulipAccountsService } from './base_zulip_accounts.service';
import { ZulipAccountsMemoryRepository } from './zulip_accounts_memory.repository';
import { ZulipAccounts } from './zulip_accounts.entity';
import {
  DEFAULT_VERIFICATION_MAX_AGE,
  DEFAULT_MAX_RETRY_COUNT,
} from './zulip_accounts.constants';
import {
  CreateZulipAccountDto,
  UpdateZulipAccountDto,
  QueryZulipAccountDto,
  ZulipAccountResponseDto,
  ZulipAccountListResponseDto,
  ZulipAccountStatsResponseDto,
  BatchUpdateResponseDto,
  VerifyAccountResponseDto,
} from './zulip_accounts.dto';

@Injectable()
export class ZulipAccountsMemoryService extends BaseZulipAccountsService {
  constructor(
    @Inject('ZulipAccountsRepository')
    private readonly repository: ZulipAccountsMemoryRepository,
  ) {
    super();
    this.logger.log('ZulipAccountsMemoryService初始化完成');
  }

  /**
   * 创建Zulip账号关联
   * 
   * 业务逻辑：
   * 1. 接收创建请求数据并进行基础验证
   * 2. 将字符串类型的gameUserId转换为BigInt类型
   * 3. 调用内存Repository层创建账号关联记录
   * 4. Repository层会处理唯一性检查（内存版本）
   * 5. 捕获Repository层异常并转换为业务异常
   * 6. 记录操作日志和性能指标
   * 7. 将实体对象转换为响应DTO返回
   * 
   * @param createDto 创建数据，包含游戏用户ID、Zulip用户信息等
   * @returns Promise<ZulipAccountResponseDto> 创建的关联记录DTO
   * @throws ConflictException 当游戏用户已存在关联或Zulip账号已被占用时
   * @throws BadRequestException 当数据验证失败或系统异常时
   * 
   * @example
   * ```typescript
   * const result = await memoryService.create({
   *   gameUserId: '12345',
   *   zulipUserId: 67890,
   *   zulipEmail: 'user@example.com',
   *   zulipFullName: '张三',
   *   zulipApiKeyEncrypted: 'encrypted_key',
   *   status: 'active'
   * });
   * ```
   */
  async create(createDto: CreateZulipAccountDto): Promise<ZulipAccountResponseDto> {
    const startTime = Date.now();
    this.logStart('创建Zulip账号关联', { gameUserId: createDto.gameUserId });

    try {
      // Repository 层已经处理了唯一性检查
      const account = await this.repository.create({
        gameUserId: BigInt(createDto.gameUserId),
        zulipUserId: createDto.zulipUserId,
        zulipEmail: createDto.zulipEmail,
        zulipFullName: createDto.zulipFullName,
        zulipApiKeyEncrypted: createDto.zulipApiKeyEncrypted,
        status: createDto.status || 'active',
      });

      const duration = Date.now() - startTime;
      this.logSuccess('创建Zulip账号关联', { 
        gameUserId: createDto.gameUserId,
        accountId: account.id.toString()
      }, duration);

      return this.toResponseDto(account);

    } catch (error) {
      // 将 Repository 层的错误转换为业务异常
      if (error instanceof Error) {
        if (error.message.includes('already has a Zulip account')) {
          throw new ConflictException(`游戏用户 ${createDto.gameUserId} 已存在Zulip账号关联`);
        }
        if (error.message.includes('is already linked')) {
          if (error.message.includes('Zulip user')) {
            throw new ConflictException(`Zulip用户 ${createDto.zulipUserId} 已被关联到其他游戏账号`);
          }
          if (error.message.includes('Zulip email')) {
            throw new ConflictException(`Zulip邮箱 ${createDto.zulipEmail} 已被关联到其他游戏账号`);
          }
        }
      }
      
      this.handleServiceError(error, '创建Zulip账号关联', { gameUserId: createDto.gameUserId });
    }
  }

  /**
   * 根据游戏用户ID查找关联
   * 
   * 业务逻辑：
   * 1. 记录查询操作开始日志
   * 2. 将字符串类型的gameUserId转换为BigInt类型
   * 3. 调用内存Repository层根据游戏用户ID查找记录
   * 4. 如果未找到记录，记录调试日志并返回null
   * 5. 如果找到记录，记录成功日志
   * 6. 将实体对象转换为响应DTO返回
   * 7. 捕获异常并进行统一的错误处理
   * 
   * @param gameUserId 游戏用户ID，字符串格式
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略），默认false
   * @returns Promise<ZulipAccountResponseDto | null> 关联记录DTO或null
   * @throws BadRequestException 当查询参数无效或系统异常时
   * 
   * @example
   * ```typescript
   * const account = await memoryService.findByGameUserId('12345', true);
   * if (account) {
   *   console.log('找到关联:', account.zulipEmail);
   * }
   * ```
   */
  async findByGameUserId(gameUserId: string, includeGameUser: boolean = false): Promise<ZulipAccountResponseDto | null> {
    this.logStart('根据游戏用户ID查找关联', { gameUserId });

    try {
      const account = await this.repository.findByGameUserId(BigInt(gameUserId), includeGameUser);
      
      if (!account) {
        this.logger.debug('未找到Zulip账号关联', { gameUserId });
        return null;
      }

      this.logSuccess('根据游戏用户ID查找关联', { gameUserId, found: true });
      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '根据游戏用户ID查找关联', { gameUserId });
    }
  }

  /**
   * 根据Zulip用户ID查找关联
   * 
   * 业务逻辑：
   * 1. 记录查询操作开始日志
   * 2. 调用内存Repository层根据Zulip用户ID查找记录
   * 3. 如果未找到记录，记录调试日志并返回null
   * 4. 如果找到记录，记录成功日志
   * 5. 将实体对象转换为响应DTO返回
   * 6. 捕获异常并进行统一的错误处理
   * 
   * @param zulipUserId Zulip用户ID，数字类型
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略），默认false
   * @returns Promise<ZulipAccountResponseDto | null> 关联记录DTO或null
   * @throws BadRequestException 当查询参数无效或系统异常时
   * 
   * @example
   * ```typescript
   * const account = await memoryService.findByZulipUserId(67890);
   * if (account) {
   *   console.log('关联的游戏用户:', account.gameUserId);
   * }
   * ```
   */
  async findByZulipUserId(zulipUserId: number, includeGameUser: boolean = false): Promise<ZulipAccountResponseDto | null> {
    this.logStart('根据Zulip用户ID查找关联', { zulipUserId });

    try {
      const account = await this.repository.findByZulipUserId(zulipUserId, includeGameUser);
      
      if (!account) {
        this.logger.debug('未找到Zulip账号关联', { zulipUserId });
        return null;
      }

      this.logSuccess('根据Zulip用户ID查找关联', { zulipUserId, found: true });
      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '根据Zulip用户ID查找关联', { zulipUserId });
    }
  }

  /**
   * 根据Zulip邮箱查找关联
   * 
   * @param zulipEmail Zulip邮箱
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略）
   * @returns Promise<ZulipAccountResponseDto | null> 关联记录或null
   */
  async findByZulipEmail(zulipEmail: string, includeGameUser: boolean = false): Promise<ZulipAccountResponseDto | null> {
    this.logStart('根据Zulip邮箱查找关联', { zulipEmail });

    try {
      const account = await this.repository.findByZulipEmail(zulipEmail, includeGameUser);
      
      if (!account) {
        this.logger.debug('未找到Zulip账号关联', { zulipEmail });
        return null;
      }

      this.logSuccess('根据Zulip邮箱查找关联', { zulipEmail, found: true });
      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '根据Zulip邮箱查找关联', { zulipEmail });
    }
  }

  /**
   * 根据ID查找关联
   * 
   * @param id 关联记录ID
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略）
   * @returns Promise<ZulipAccountResponseDto> 关联记录
   */
  async findById(id: string, includeGameUser: boolean = false): Promise<ZulipAccountResponseDto> {
    this.logStart('根据ID查找关联', { id });

    try {
      const account = await this.repository.findById(BigInt(id), includeGameUser);
      
      if (!account) {
        throw new NotFoundException(`Zulip账号关联记录 ${id} 不存在`);
      }

      this.logSuccess('根据ID查找关联', { id, found: true });
      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '根据ID查找关联', { id });
    }
  }

  /**
   * 更新Zulip账号关联
   * 
   * @param id 关联记录ID
   * @param updateDto 更新数据
   * @returns Promise<ZulipAccountResponseDto> 更新后的记录
   */
  async update(id: string, updateDto: UpdateZulipAccountDto): Promise<ZulipAccountResponseDto> {
    const startTime = Date.now();
    this.logStart('更新Zulip账号关联', { id });

    try {
      const account = await this.repository.update(BigInt(id), updateDto);
      
      if (!account) {
        throw new NotFoundException(`Zulip账号关联记录 ${id} 不存在`);
      }

      const duration = Date.now() - startTime;
      this.logSuccess('更新Zulip账号关联', { id }, duration);

      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '更新Zulip账号关联', { id });
    }
  }

  /**
   * 根据游戏用户ID更新关联
   * 
   * @param gameUserId 游戏用户ID
   * @param updateDto 更新数据
   * @returns Promise<ZulipAccountResponseDto> 更新后的记录
   */
  async updateByGameUserId(gameUserId: string, updateDto: UpdateZulipAccountDto): Promise<ZulipAccountResponseDto> {
    const startTime = Date.now();
    this.logStart('根据游戏用户ID更新关联', { gameUserId });

    try {
      const account = await this.repository.updateByGameUserId(BigInt(gameUserId), updateDto);
      
      if (!account) {
        throw new NotFoundException(`游戏用户 ${gameUserId} 的Zulip账号关联不存在`);
      }

      const duration = Date.now() - startTime;
      this.logSuccess('根据游戏用户ID更新关联', { gameUserId }, duration);

      return this.toResponseDto(account);

    } catch (error) {
      this.handleServiceError(error, '根据游戏用户ID更新关联', { gameUserId });
    }
  }

  /**
   * 删除Zulip账号关联
   * 
   * @param id 关联记录ID
   * @returns Promise<boolean> 是否删除成功
   */
  async delete(id: string): Promise<boolean> {
    const startTime = Date.now();
    this.logStart('删除Zulip账号关联', { id });

    try {
      const result = await this.repository.delete(BigInt(id));
      
      if (!result) {
        throw new NotFoundException(`Zulip账号关联记录 ${id} 不存在`);
      }

      const duration = Date.now() - startTime;
      this.logSuccess('删除Zulip账号关联', { id }, duration);

      return true;

    } catch (error) {
      this.handleServiceError(error, '删除Zulip账号关联', { id });
    }
  }

  /**
   * 根据游戏用户ID删除关联
   * 
   * @param gameUserId 游戏用户ID
   * @returns Promise<boolean> 是否删除成功
   */
  async deleteByGameUserId(gameUserId: string): Promise<boolean> {
    const startTime = Date.now();
    this.logStart('根据游戏用户ID删除关联', { gameUserId });

    try {
      const result = await this.repository.deleteByGameUserId(BigInt(gameUserId));
      
      if (!result) {
        throw new NotFoundException(`游戏用户 ${gameUserId} 的Zulip账号关联不存在`);
      }

      const duration = Date.now() - startTime;
      this.logSuccess('根据游戏用户ID删除关联', { gameUserId }, duration);

      return true;

    } catch (error) {
      this.handleServiceError(error, '根据游戏用户ID删除关联', { gameUserId });
    }
  }

  /**
   * 查询多个Zulip账号关联
   * 
   * @param queryDto 查询条件
   * @returns Promise<ZulipAccountListResponseDto> 关联记录列表
   */
  async findMany(queryDto: QueryZulipAccountDto = {}): Promise<ZulipAccountListResponseDto> {
    this.logStart('查询多个Zulip账号关联', queryDto);

    try {
      const options = {
        gameUserId: queryDto.gameUserId ? BigInt(queryDto.gameUserId) : undefined,
        zulipUserId: queryDto.zulipUserId,
        zulipEmail: queryDto.zulipEmail,
        status: queryDto.status,
        includeGameUser: queryDto.includeGameUser || false,
      };

      const accounts = await this.repository.findMany(options);
      
      const responseAccounts = accounts.map(account => this.toResponseDto(account));

      this.logSuccess('查询多个Zulip账号关联', { 
        count: accounts.length,
        conditions: queryDto 
      });

      return {
        accounts: responseAccounts,
        total: responseAccounts.length,
        count: responseAccounts.length,
      };

    } catch (error) {
      return {
        accounts: this.handleSearchError(error, '查询多个Zulip账号关联', queryDto),
        total: 0,
        count: 0,
      };
    }
  }

  /**
   * 获取需要验证的账号列表
   * 
   * @param maxAge 最大验证间隔（毫秒），默认24小时
   * @returns Promise<ZulipAccountListResponseDto> 需要验证的账号列表
   */
  async findAccountsNeedingVerification(maxAge: number = DEFAULT_VERIFICATION_MAX_AGE): Promise<ZulipAccountListResponseDto> {
    this.logStart('获取需要验证的账号列表', { maxAge });

    try {
      const accounts = await this.repository.findAccountsNeedingVerification(maxAge);
      
      const responseAccounts = accounts.map(account => this.toResponseDto(account));

      this.logSuccess('获取需要验证的账号列表', { count: accounts.length });

      return {
        accounts: responseAccounts,
        total: responseAccounts.length,
        count: responseAccounts.length,
      };

    } catch (error) {
      return {
        accounts: this.handleSearchError(error, '获取需要验证的账号列表', { maxAge }),
        total: 0,
        count: 0,
      };
    }
  }

  /**
   * 获取错误状态的账号列表
   * 
   * @param maxRetryCount 最大重试次数，默认3次
   * @returns Promise<ZulipAccountListResponseDto> 错误状态的账号列表
   */
  async findErrorAccounts(maxRetryCount: number = DEFAULT_MAX_RETRY_COUNT): Promise<ZulipAccountListResponseDto> {
    this.logStart('获取错误状态的账号列表', { maxRetryCount });

    try {
      const accounts = await this.repository.findErrorAccounts(maxRetryCount);
      
      const responseAccounts = accounts.map(account => this.toResponseDto(account));

      this.logSuccess('获取错误状态的账号列表', { count: accounts.length });

      return {
        accounts: responseAccounts,
        total: responseAccounts.length,
        count: responseAccounts.length,
      };

    } catch (error) {
      return {
        accounts: this.handleSearchError(error, '获取错误状态的账号列表', { maxRetryCount }),
        total: 0,
        count: 0,
      };
    }
  }

  /**
   * 批量更新账号状态
   * 
   * @param ids 账号ID列表
   * @param status 新状态
   * @returns Promise<BatchUpdateResponseDto> 批量更新结果
   */
  async batchUpdateStatus(ids: string[], status: 'active' | 'inactive' | 'suspended' | 'error'): Promise<BatchUpdateResponseDto> {
    const startTime = Date.now();
    this.logStart('批量更新账号状态', { count: ids.length, status });

    try {
      const bigintIds = ids.map(id => BigInt(id));
      const updatedCount = await this.repository.batchUpdateStatus(bigintIds, status);

      const duration = Date.now() - startTime;
      this.logSuccess('批量更新账号状态', { 
        requestCount: ids.length,
        updatedCount,
        status 
      }, duration);

      return {
        success: true,
        updatedCount,
      };

    } catch (error) {
      this.logger.error('批量更新账号状态失败', {
        operation: 'batchUpdateStatus',
        error: this.formatError(error),
        count: ids.length,
        status,
      });

      return {
        success: false,
        updatedCount: 0,
        error: this.formatError(error),
      };
    }
  }

  /**
   * 获取账号状态统计
   * 
   * @returns Promise<ZulipAccountStatsResponseDto> 状态统计
   */
  async getStatusStatistics(): Promise<ZulipAccountStatsResponseDto> {
    this.logStart('获取账号状态统计');

    try {
      const statistics = await this.repository.getStatusStatistics();

      const result = {
        active: statistics.active || 0,
        inactive: statistics.inactive || 0,
        suspended: statistics.suspended || 0,
        error: statistics.error || 0,
        total: (statistics.active || 0) + (statistics.inactive || 0) + 
               (statistics.suspended || 0) + (statistics.error || 0),
      };

      this.logSuccess('获取账号状态统计', result);

      return result;

    } catch (error) {
      this.handleServiceError(error, '获取账号状态统计');
    }
  }

  /**
   * 验证账号有效性
   * 
   * @param gameUserId 游戏用户ID
   * @returns Promise<VerifyAccountResponseDto> 验证结果
   */
  async verifyAccount(gameUserId: string): Promise<VerifyAccountResponseDto> {
    const startTime = Date.now();
    this.logStart('验证账号有效性', { gameUserId });

    try {
      // 1. 查找账号关联
      const account = await this.repository.findByGameUserId(BigInt(gameUserId));
      
      if (!account) {
        return {
          success: false,
          isValid: false,
          error: '账号关联不存在',
        };
      }

      // 2. 检查账号状态
      if (account.status !== 'active') {
        return {
          success: true,
          isValid: false,
          error: `账号状态为 ${account.status}`,
        };
      }

      // 3. 更新验证时间
      await this.repository.updateByGameUserId(BigInt(gameUserId), {
        lastVerifiedAt: new Date(),
      });

      const duration = Date.now() - startTime;
      this.logSuccess('验证账号有效性', { gameUserId, isValid: true }, duration);

      return {
        success: true,
        isValid: true,
        verifiedAt: new Date().toISOString(),
      };

    } catch (error) {
      this.logger.error('验证账号有效性失败', {
        operation: 'verifyAccount',
        gameUserId,
        error: this.formatError(error),
      });

      return {
        success: false,
        isValid: false,
        error: this.formatError(error),
      };
    }
  }

  /**
   * 检查邮箱是否已存在
   * 
   * @param zulipEmail Zulip邮箱
   * @param excludeId 排除的记录ID
   * @returns Promise<boolean> 是否已存在
   */
  async existsByEmail(zulipEmail: string, excludeId?: string): Promise<boolean> {
    try {
      const excludeBigintId = excludeId ? BigInt(excludeId) : undefined;
      return await this.repository.existsByEmail(zulipEmail, excludeBigintId);
    } catch (error) {
      this.logger.warn('检查邮箱存在性失败', {
        operation: 'existsByEmail',
        zulipEmail,
        error: this.formatError(error),
      });
      return false;
    }
  }

  /**
   * 检查Zulip用户ID是否已存在
   * 
   * @param zulipUserId Zulip用户ID
   * @param excludeId 排除的记录ID
   * @returns Promise<boolean> 是否已存在
   */
  async existsByZulipUserId(zulipUserId: number, excludeId?: string): Promise<boolean> {
    try {
      const excludeBigintId = excludeId ? BigInt(excludeId) : undefined;
      return await this.repository.existsByZulipUserId(zulipUserId, excludeBigintId);
    } catch (error) {
      this.logger.warn('检查Zulip用户ID存在性失败', {
        operation: 'existsByZulipUserId',
        zulipUserId,
        error: this.formatError(error),
      });
      return false;
    }
  }

  /**
   * 将实体转换为响应DTO
   * 
   * @param account 账号关联实体
   * @returns ZulipAccountResponseDto 响应DTO
   * @private
   */
  private toResponseDto(account: ZulipAccounts): ZulipAccountResponseDto {
    return {
      id: account.id.toString(),
      gameUserId: account.gameUserId.toString(),
      zulipUserId: account.zulipUserId,
      zulipEmail: account.zulipEmail,
      zulipFullName: account.zulipFullName,
      status: account.status,
      lastVerifiedAt: account.lastVerifiedAt?.toISOString(),
      lastSyncedAt: account.lastSyncedAt?.toISOString(),
      errorMessage: account.errorMessage,
      retryCount: account.retryCount,
      createdAt: account.createdAt.toISOString(),
      updatedAt: account.updatedAt.toISOString(),
      gameUser: account.gameUser,
    };
  }
}