/**
 * Zulip账号关联内存数据访问层
 * 
 * 功能描述：
 * - 提供Zulip账号关联数据的内存存储实现和CRUD操作
 * - 用于开发和测试环境，无需数据库连接和配置
 * - 实现与数据库版本相同的接口和查询功能
 * - 支持数据导入导出、备份恢复和测试数据管理
 * 
 * 职责分离：
 * - 数据存储：使用Map结构提供高效的内存数据存储
 * - 查询实现：实现各种查询条件和过滤逻辑
 * - 约束检查：确保数据唯一性和完整性约束
 * - 测试支持：提供数据导入导出和清理功能
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修复findAccountsNeedingVerification方法的限制逻辑，与数据库版本保持一致 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 使用统一的常量文件，提高代码质量
 * - 2026-01-07: 代码规范优化 - 完善文件头注释和方法三级注释
 * - 2026-01-07: 功能完善 - 优化查询性能和数据管理功能
 * - 2025-01-07: 架构优化 - 统一Repository层的接口设计和实现
 * - 2025-01-05: 功能扩展 - 添加批量操作和统计查询功能
 * 
 * @author angjustinl
 * @version 1.1.2
 * @since 2025-01-05
 * @lastModified 2026-01-12
 */

import { Injectable } from '@nestjs/common';
import { ZulipAccounts } from './zulip_accounts.entity';
import {
  DEFAULT_VERIFICATION_MAX_AGE,
  DEFAULT_MAX_RETRY_COUNT,
  DEFAULT_ERROR_ACCOUNTS_LIMIT,
} from './zulip_accounts.constants';
import {
  CreateZulipAccountData,
  UpdateZulipAccountData,
  ZulipAccountQueryOptions,
  StatusStatistics,
  IZulipAccountsRepository,
} from './zulip_accounts.types';

@Injectable()
export class ZulipAccountsMemoryRepository implements IZulipAccountsRepository {
  private accounts: Map<bigint, ZulipAccounts> = new Map();
  private currentId: bigint = BigInt(1);

  /**
   * 创建新的Zulip账号关联（带唯一性检查）
   * 
   * @param createData 创建数据
   * @returns Promise<ZulipAccounts> 创建的关联记录
   */
  async create(createData: CreateZulipAccountData): Promise<ZulipAccounts> {
    // 检查唯一性约束
    const existingByGameUser = await this.findByGameUserId(createData.gameUserId);
    if (existingByGameUser) {
      throw new Error(`Game user ${createData.gameUserId} already has a Zulip account`);
    }

    const existingByZulipUser = await this.findByZulipUserId(createData.zulipUserId);
    if (existingByZulipUser) {
      throw new Error(`Zulip user ${createData.zulipUserId} is already linked`);
    }

    const existingByEmail = await this.findByZulipEmail(createData.zulipEmail);
    if (existingByEmail) {
      throw new Error(`Zulip email ${createData.zulipEmail} is already linked`);
    }

    const account = new ZulipAccounts();
    account.id = this.currentId++;
    account.gameUserId = createData.gameUserId;
    account.zulipUserId = createData.zulipUserId;
    account.zulipEmail = createData.zulipEmail;
    account.zulipFullName = createData.zulipFullName;
    account.zulipApiKeyEncrypted = createData.zulipApiKeyEncrypted;
    account.status = createData.status || 'active';
    account.lastVerifiedAt = null;
    account.lastSyncedAt = null;
    account.errorMessage = null;
    account.retryCount = 0;
    account.createdAt = new Date();
    account.updatedAt = new Date();

    this.accounts.set(account.id, account);
    return account;
  }

  /**
   * 根据游戏用户ID查找Zulip账号关联
   * 
   * @param gameUserId 游戏用户ID
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略）
   * @returns Promise<ZulipAccounts | null> 关联记录或null
   */
  async findByGameUserId(gameUserId: bigint, includeGameUser: boolean = false): Promise<ZulipAccounts | null> {
    for (const account of this.accounts.values()) {
      if (account.gameUserId === gameUserId) {
        return account;
      }
    }
    return null;
  }

  /**
   * 根据Zulip用户ID查找账号关联
   * 
   * @param zulipUserId Zulip用户ID
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略）
   * @returns Promise<ZulipAccounts | null> 关联记录或null
   */
  async findByZulipUserId(zulipUserId: number, includeGameUser: boolean = false): Promise<ZulipAccounts | null> {
    for (const account of this.accounts.values()) {
      if (account.zulipUserId === zulipUserId) {
        return account;
      }
    }
    return null;
  }

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

  /**
   * 根据ID查找Zulip账号关联
   * 
   * @param id 关联记录ID
   * @param includeGameUser 是否包含游戏用户信息（内存模式忽略）
   * @returns Promise<ZulipAccounts | null> 关联记录或null
   */
  async findById(id: bigint, includeGameUser: boolean = false): Promise<ZulipAccounts | null> {
    return this.accounts.get(id) || null;
  }

  /**
   * 更新Zulip账号关联
   * 
   * @param id 关联记录ID
   * @param updateData 更新数据
   * @returns Promise<ZulipAccounts | null> 更新后的记录或null
   */
  async update(id: bigint, updateData: UpdateZulipAccountData): Promise<ZulipAccounts | null> {
    const account = this.accounts.get(id);
    if (!account) {
      return null;
    }

    Object.assign(account, updateData);
    account.updatedAt = new Date();
    
    return account;
  }

  /**
   * 根据游戏用户ID更新Zulip账号关联
   * 
   * @param gameUserId 游戏用户ID
   * @param updateData 更新数据
   * @returns Promise<ZulipAccounts | null> 更新后的记录或null
   */
  async updateByGameUserId(gameUserId: bigint, updateData: UpdateZulipAccountData): Promise<ZulipAccounts | null> {
    const account = await this.findByGameUserId(gameUserId);
    if (!account) {
      return null;
    }

    Object.assign(account, updateData);
    account.updatedAt = new Date();
    
    return account;
  }

  /**
   * 删除Zulip账号关联
   * 
   * @param id 关联记录ID
   * @returns Promise<boolean> 是否删除成功
   */
  async delete(id: bigint): Promise<boolean> {
    return this.accounts.delete(id);
  }

  /**
   * 根据游戏用户ID删除Zulip账号关联
   * 
   * @param gameUserId 游戏用户ID
   * @returns Promise<boolean> 是否删除成功
   */
  async deleteByGameUserId(gameUserId: bigint): Promise<boolean> {
    for (const [id, account] of this.accounts.entries()) {
      if (account.gameUserId === gameUserId) {
        return this.accounts.delete(id);
      }
    }
    return false;
  }

  /**
   * 查询多个Zulip账号关联
   * 
   * @param options 查询选项
   * @returns Promise<ZulipAccounts[]> 关联记录列表
   */
  async findMany(options: ZulipAccountQueryOptions = {}): Promise<ZulipAccounts[]> {
    let results = Array.from(this.accounts.values());

    if (options.gameUserId) {
      results = results.filter(a => a.gameUserId === options.gameUserId);
    }
    if (options.zulipUserId) {
      results = results.filter(a => a.zulipUserId === options.zulipUserId);
    }
    if (options.zulipEmail) {
      results = results.filter(a => a.zulipEmail === options.zulipEmail);
    }
    if (options.status) {
      results = results.filter(a => a.status === options.status);
    }

    // 按创建时间降序排序
    results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());

    return results;
  }

  /**
   * 获取需要验证的账号列表
   * 
   * 业务逻辑：
   * 1. 计算验证截止时间，基于当前时间减去最大验证间隔
   * 2. 筛选状态为active且需要验证的账号记录
   * 3. 包含从未验证过的账号（lastVerifiedAt为null）
   * 4. 包含验证时间超过最大间隔的账号
   * 5. 按验证时间升序排序，优先处理最久未验证的账号
   * 
   * @param maxAge 最大验证间隔（毫秒），默认24小时
   * @returns Promise<ZulipAccounts[]> 需要验证的账号列表，按验证时间升序排序
   * 
   * @example
   * // 获取需要验证的账号（默认24小时）
   * const accounts = await repository.findAccountsNeedingVerification();
   * 
   * @example
   * // 获取需要验证的账号（自定义12小时）
   * const accounts = await repository.findAccountsNeedingVerification(12 * 60 * 60 * 1000);
   */
  async findAccountsNeedingVerification(maxAge: number = DEFAULT_VERIFICATION_MAX_AGE): Promise<ZulipAccounts[]> {
    const cutoffTime = new Date(Date.now() - maxAge);
    
    return Array.from(this.accounts.values())
      .filter(account => 
        account.status === 'active' &&
        (!account.lastVerifiedAt || account.lastVerifiedAt < cutoffTime)
      )
      .sort((a, b) => {
        if (!a.lastVerifiedAt) return -1;
        if (!b.lastVerifiedAt) return 1;
        return a.lastVerifiedAt.getTime() - b.lastVerifiedAt.getTime();
      })
      .slice(0, 100); // 应用默认限制，与数据库版本保持一致
  }

  /**
   * 获取错误状态的账号列表（可重试的）
   * 
   * 业务逻辑：
   * 1. 筛选状态为error的账号记录
   * 2. 过滤重试次数小于最大重试次数的账号
   * 3. 按更新时间升序排序，优先处理最早出错的账号
   * 4. 限制返回数量，避免一次处理过多错误账号
   * 5. 为错误恢复和重试机制提供数据支持
   * 
   * @param maxRetryCount 最大重试次数，默认3次
   * @returns Promise<ZulipAccounts[]> 错误状态的账号列表，限制50条记录
   * 
   * @example
   * // 获取可重试的错误账号（默认3次重试限制）
   * const errorAccounts = await repository.findErrorAccounts();
   * 
   * @example
   * // 获取可重试的错误账号（自定义5次重试限制）
   * const errorAccounts = await repository.findErrorAccounts(5);
   */
  async findErrorAccounts(maxRetryCount: number = DEFAULT_MAX_RETRY_COUNT): Promise<ZulipAccounts[]> {
    return Array.from(this.accounts.values())
      .filter(account => account.status === 'error' && account.retryCount < maxRetryCount)
      .sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime())
      .slice(0, DEFAULT_ERROR_ACCOUNTS_LIMIT); // 限制返回数量
  }

  /**
   * 批量更新账号状态
   * 
   * @param ids 账号ID列表
   * @param status 新状态
   * @returns Promise<number> 更新的记录数
   */
  async batchUpdateStatus(ids: bigint[], status: 'active' | 'inactive' | 'suspended' | 'error'): Promise<number> {
    let count = 0;
    for (const id of ids) {
      const account = this.accounts.get(id);
      if (account) {
        account.status = status;
        account.updatedAt = new Date();
        count++;
      }
    }
    return count;
  }

  /**
   * 统计各状态的账号数量
   * 
   * @returns Promise<StatusStatistics> 状态统计
   */
  async getStatusStatistics(): Promise<StatusStatistics> {
    const statistics: StatusStatistics = {
      active: 0,
      inactive: 0,
      suspended: 0,
      error: 0,
    };
    
    for (const account of this.accounts.values()) {
      const status = account.status;
      statistics[status] = (statistics[status] || 0) + 1;
    }

    return statistics;
  }

  /**
   * 检查邮箱是否已存在
   * 
   * @param zulipEmail Zulip邮箱
   * @param excludeId 排除的记录ID（用于更新时检查）
   * @returns Promise<boolean> 是否已存在
   */
  async existsByEmail(zulipEmail: string, excludeId?: bigint): Promise<boolean> {
    for (const [id, account] of this.accounts.entries()) {
      if (account.zulipEmail === zulipEmail && (!excludeId || id !== excludeId)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 检查Zulip用户ID是否已存在
   * 
   * @param zulipUserId Zulip用户ID
   * @param excludeId 排除的记录ID（用于更新时检查）
   * @returns Promise<boolean> 是否已存在
   */
  async existsByZulipUserId(zulipUserId: number, excludeId?: bigint): Promise<boolean> {
    for (const [id, account] of this.accounts.entries()) {
      if (account.zulipUserId === zulipUserId && (!excludeId || id !== excludeId)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 检查游戏用户ID是否已存在
   * 
   * @param gameUserId 游戏用户ID
   * @param excludeId 排除的记录ID（用于更新时检查）
   * @returns Promise<boolean> 是否已存在
   */
  async existsByGameUserId(gameUserId: bigint, excludeId?: bigint): Promise<boolean> {
    for (const [id, account] of this.accounts.entries()) {
      if (account.gameUserId === gameUserId && (!excludeId || id !== excludeId)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 导出所有数据（用于测试和备份）
   * 
   * @returns Promise<ZulipAccounts[]> 所有账号数据
   */
  async exportData(): Promise<ZulipAccounts[]> {
    return Array.from(this.accounts.values());
  }

  /**
   * 导入数据（用于测试数据初始化）
   * 
   * @param accounts 账号数据列表
   * @returns Promise<void>
   */
  async importData(accounts: ZulipAccounts[]): Promise<void> {
    this.accounts.clear();
    let maxId = BigInt(0);
    
    for (const account of accounts) {
      this.accounts.set(account.id, account);
      if (account.id > maxId) {
        maxId = account.id;
      }
    }
    
    this.currentId = maxId + BigInt(1);
  }

  /**
   * 清空所有数据（用于测试）
   * 
   * @returns Promise<void>
   */
  async clearAll(): Promise<void> {
    this.accounts.clear();
    this.currentId = BigInt(1);
  }

  /**
   * 获取数据统计信息
   * 
   * @returns Promise<{ total: number; nextId: string }> 统计信息
   */
  async getDataInfo(): Promise<{ total: number; nextId: string }> {
    return {
      total: this.accounts.size,
      nextId: this.currentId.toString(),
    };
  }
}
