/**
 * 用户档案内存服务类
 *
 * 功能描述：
 * - 提供用户档案数据的内存存储实现
 * - 使用Map数据结构进行高性能数据管理
 * - 支持完整的CRUD操作和位置信息管理
 * - 为开发测试环境提供零依赖的数据存储方案
 *
 * 职责分离：
 * - 数据存储：使用Map进行内存数据管理
 * - ID生成：线程安全的自增ID生成机制
 * - 数据验证：数据完整性和唯一性约束检查
 * - 性能监控：操作耗时统计和日志记录
 *
 * 技术特点：
 * - 高性能：直接内存访问，无IO开销
 * - 零依赖：无需数据库连接，快速启动
 * - 完整功能：实现与数据库服务相同的接口
 * - 易测试：便于单元测试和集成测试
 *
 * 使用场景：
 * - 开发环境快速启动和调试
 * - 单元测试和集成测试
 * - 演示和原型开发
 * - 数据库故障时的降级方案
 *
 * 最近修改：
 * - 2026-01-08: 功能新增 - 创建用户档案内存服务，支持位置广播系统 (修改者: moyin)
 *
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Injectable, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common';
import { UserProfiles } from './user_profiles.entity';
import { CreateUserProfileDto, UpdateUserProfileDto, UpdatePositionDto, QueryUserProfileDto } from './user_profiles.dto';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
import { BaseUserProfilesService } from './base_user_profiles.service';

@Injectable()
export class UserProfilesMemoryService extends BaseUserProfilesService {
  /**
   * 内存数据存储
   *
   * 数据结构：
   * - Key: bigint类型的档案ID
   * - Value: UserProfiles实体对象
   * - 特点：支持快速查找和更新操作
   */
  private profiles: Map<bigint, UserProfiles> = new Map();

  /**
   * 用户ID到档案ID的映射
   *
   * 数据结构：
   * - Key: bigint类型的用户ID
   * - Value: bigint类型的档案ID
   * - 用途：支持根据用户ID快速查找档案
   */
  private userIdToProfileId: Map<bigint, bigint> = new Map();

  /**
   * 当前ID计数器
   *
   * 功能：
   * - 生成唯一的档案ID
   * - 自增机制，确保ID唯一性
   * - 线程安全的ID生成
   */
  private CURRENT_ID: bigint = BigInt(1);

  /**
   * ID生成锁
   *
   * 功能：
   * - 防止并发ID生成冲突
   * - 简单的锁机制实现
   * - 确保ID生成的原子性
   */
  private readonly ID_LOCK = new Set<string>();

  /**
   * 创建新用户档案
   *
   * 技术实现：
   * 1. 验证输入数据的格式和完整性
   * 2. 检查用户ID的唯一性约束
   * 3. 生成唯一的档案ID
   * 4. 创建用户档案实体对象
   * 5. 存储到内存Map中
   * 6. 建立用户ID到档案ID的映射
   * 7. 记录操作日志和性能指标
   *
   * @param createUserProfileDto 创建用户档案的数据传输对象
   * @returns 创建成功的用户档案实体
   * @throws BadRequestException 当数据验证失败时
   * @throws ConflictException 当用户ID已存在档案时
   */
  async create(createUserProfileDto: CreateUserProfileDto): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logStart('创建用户档案', {
      userId: createUserProfileDto.user_id.toString(),
      currentMap: createUserProfileDto.current_map
    });

    try {
      // 验证DTO
      const dto = plainToClass(CreateUserProfileDto, createUserProfileDto);
      const validationErrors = await validate(dto);

      if (validationErrors.length > 0) {
        const errorMessages = validationErrors.map(error =>
          Object.values(error.constraints || {}).join(', ')
        ).join('; ');

        this.logWarning('创建用户档案', '数据验证失败', {
          userId: createUserProfileDto.user_id.toString(),
          validationErrors: errorMessages
        });

        throw new BadRequestException(`数据验证失败: ${errorMessages}`);
      }

      // 检查用户ID是否已存在档案
      if (this.userIdToProfileId.has(createUserProfileDto.user_id)) {
        const existingProfileId = this.userIdToProfileId.get(createUserProfileDto.user_id);

        this.logWarning('创建用户档案', '用户ID已存在档案', {
          userId: createUserProfileDto.user_id.toString(),
          existingProfileId: existingProfileId?.toString()
        });

        throw new ConflictException('该用户已存在档案记录');
      }

      // 生成唯一ID
      const profileId = this.generateUniqueId();

      // 创建用户档案实体
      const userProfile = new UserProfiles();
      userProfile.id = profileId;
      userProfile.user_id = createUserProfileDto.user_id;
      userProfile.bio = createUserProfileDto.bio || null;
      userProfile.resume_content = createUserProfileDto.resume_content || null;
      userProfile.tags = createUserProfileDto.tags || null;
      userProfile.social_links = createUserProfileDto.social_links || null;
      userProfile.skin_id = createUserProfileDto.skin_id || null;
      userProfile.current_map = createUserProfileDto.current_map || 'plaza';
      userProfile.pos_x = createUserProfileDto.pos_x || 0;
      userProfile.pos_y = createUserProfileDto.pos_y || 0;
      userProfile.status = createUserProfileDto.status || 0;
      userProfile.last_position_update = new Date();

      // 存储到内存
      this.profiles.set(profileId, userProfile);
      this.userIdToProfileId.set(createUserProfileDto.user_id, profileId);

      const duration = this.calculateDuration(startTime);

      this.logSuccess('创建用户档案', {
        profileId: profileId.toString(),
        userId: userProfile.user_id.toString(),
        currentMap: userProfile.current_map
      }, duration);

      return userProfile;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      if (error instanceof BadRequestException || error instanceof ConflictException) {
        throw error;
      }

      this.logError('创建用户档案',
        error instanceof Error ? error.message : String(error),
        { userId: createUserProfileDto.user_id.toString() },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('用户档案创建失败，请稍后重试');
    }
  }

  /**
   * 根据ID查询用户档案
   *
   * 业务逻辑：
   * 1. 从内存Map中根据ID快速查找档案
   * 2. 验证档案是否存在
   * 3. 记录查询操作和结果
   *
   * @param id 档案ID
   * @returns 用户档案实体
   * @throws NotFoundException 当档案不存在时
   */
  async findOne(id: bigint): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logStart('查询用户档案', { profileId: id.toString() });

    try {
      const profile = this.profiles.get(id);

      if (!profile) {
        this.logWarning('查询用户档案', '档案不存在', { profileId: id.toString() });
        throw new NotFoundException(`ID为 ${id} 的用户档案不存在`);
      }

      const duration = this.calculateDuration(startTime);

      this.logSuccess('查询用户档案', {
        profileId: id.toString(),
        userId: profile.user_id.toString()
      }, duration);

      return profile;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logError('查询用户档案',
        error instanceof Error ? error.message : String(error),
        { profileId: id.toString() },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('用户档案查询失败，请稍后重试');
    }
  }

  /**
   * 根据用户ID查询用户档案
   *
   * @param userId 用户ID
   * @returns 用户档案实体或null
   */
  async findByUserId(userId: bigint): Promise<UserProfiles | null> {
    const profileId = this.userIdToProfileId.get(userId);
    if (!profileId) {
      return null;
    }

    return this.profiles.get(profileId) || null;
  }

  /**
   * 根据地图查询用户档案列表
   *
   * @param mapId 地图ID
   * @param status 用户状态过滤（可选）
   * @param limit 限制数量，默认50
   * @param offset 偏移量，默认0
   * @returns 用户档案列表
   */
  async findByMap(mapId: string, status?: number, limit: number = 50, offset: number = 0): Promise<UserProfiles[]> {
    const startTime = Date.now();

    this.logStart('查询地图用户档案', { mapId, status, limit, offset });

    try {
      // 过滤符合条件的档案
      const filteredProfiles = Array.from(this.profiles.values()).filter(profile => {
        if (profile.current_map !== mapId) {
          return false;
        }

        if (status !== undefined && profile.status !== status) {
          return false;
        }

        return true;
      });

      // 按最后位置更新时间排序
      filteredProfiles.sort((a, b) => {
        const timeA = a.last_position_update?.getTime() || 0;
        const timeB = b.last_position_update?.getTime() || 0;
        return timeB - timeA; // 降序排列
      });

      // 应用分页
      const result = filteredProfiles.slice(offset, offset + limit);

      const duration = this.calculateDuration(startTime);

      this.logSuccess('查询地图用户档案', {
        mapId,
        status,
        resultCount: result.length,
        totalCount: filteredProfiles.length
      }, duration);

      return result;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      return this.handleSearchError(error, '查询地图用户档案', {
        mapId,
        status,
        duration
      });
    }
  }

  /**
   * 更新用户档案信息
   *
   * @param id 档案ID
   * @param updateData 更新的数据
   * @returns 更新后的用户档案实体
   * @throws NotFoundException 当档案不存在时
   */
  async update(id: bigint, updateData: UpdateUserProfileDto): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logStart('更新用户档案信息', {
      profileId: id.toString(),
      updateFields: Object.keys(updateData)
    });

    try {
      // 检查档案是否存在
      const existingProfile = await this.findOne(id);

      // 合并更新数据
      Object.assign(existingProfile, updateData);

      // 更新内存中的数据
      this.profiles.set(id, existingProfile);

      const duration = this.calculateDuration(startTime);

      this.logSuccess('更新用户档案信息', {
        profileId: id.toString(),
        userId: existingProfile.user_id.toString(),
        updateFields: Object.keys(updateData)
      }, duration);

      return existingProfile;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logError('更新用户档案信息',
        error instanceof Error ? error.message : String(error),
        { profileId: id.toString(), updateData },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('用户档案更新失败，请稍后重试');
    }
  }

  /**
   * 更新用户位置信息
   *
   * @param userId 用户ID
   * @param positionData 位置数据
   * @returns 更新后的用户档案实体
   * @throws NotFoundException 当用户档案不存在时
   */
  async updatePosition(userId: bigint, positionData: UpdatePositionDto): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logStart('更新用户位置', {
      userId: userId.toString(),
      currentMap: positionData.current_map,
      posX: positionData.pos_x,
      posY: positionData.pos_y
    });

    try {
      // 查找用户档案
      const profileId = this.userIdToProfileId.get(userId);
      if (!profileId) {
        this.logWarning('更新用户位置', '档案不存在', { userId: userId.toString() });
        throw new NotFoundException(`用户ID ${userId} 的档案不存在`);
      }

      const profile = this.profiles.get(profileId);
      if (!profile) {
        this.logWarning('更新用户位置', '档案数据不存在', {
          userId: userId.toString(),
          profileId: profileId.toString()
        });
        throw new NotFoundException(`用户ID ${userId} 的档案不存在`);
      }

      // 更新位置信息
      profile.current_map = positionData.current_map;
      profile.pos_x = positionData.pos_x;
      profile.pos_y = positionData.pos_y;
      profile.last_position_update = new Date();

      // 更新内存中的数据
      this.profiles.set(profileId, profile);

      const duration = this.calculateDuration(startTime);

      this.logSuccess('更新用户位置', {
        profileId: profileId.toString(),
        userId: userId.toString(),
        currentMap: profile.current_map,
        posX: profile.pos_x,
        posY: profile.pos_y
      }, duration);

      return profile;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logError('更新用户位置',
        error instanceof Error ? error.message : String(error),
        { userId: userId.toString(), positionData },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('用户位置更新失败，请稍后重试');
    }
  }

  /**
   * 批量更新用户状态
   *
   * @param userIds 用户ID列表
   * @param status 目标状态
   * @returns 更新的记录数量
   */
  async batchUpdateStatus(userIds: bigint[], status: number): Promise<number> {
    const startTime = Date.now();

    this.logStart('批量更新用户状态', {
      userCount: userIds.length,
      targetStatus: status
    });

    try {
      let updatedCount = 0;

      for (const userId of userIds) {
        const profileId = this.userIdToProfileId.get(userId);
        if (profileId) {
          const profile = this.profiles.get(profileId);
          if (profile) {
            profile.status = status;
            this.profiles.set(profileId, profile);
            updatedCount++;
          }
        }
      }

      const duration = this.calculateDuration(startTime);

      this.logSuccess('批量更新用户状态', {
        userCount: userIds.length,
        targetStatus: status,
        updatedCount
      }, duration);

      return updatedCount;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      this.logError('批量更新用户状态',
        error instanceof Error ? error.message : String(error),
        { userCount: userIds.length, targetStatus: status },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('批量更新用户状态失败，请稍后重试');
    }
  }

  /**
   * 查询用户档案列表
   *
   * @param queryDto 查询条件
   * @returns 用户档案列表
   */
  async findAll(queryDto: QueryUserProfileDto = {}): Promise<UserProfiles[]> {
    const { current_map, status, limit = 20, offset = 0 } = queryDto;

    // 过滤符合条件的档案
    const filteredProfiles = Array.from(this.profiles.values()).filter(profile => {
      if (current_map && profile.current_map !== current_map) {
        return false;
      }

      if (status !== undefined && profile.status !== status) {
        return false;
      }

      return true;
    });

    // 按最后位置更新时间排序
    filteredProfiles.sort((a, b) => {
      const timeA = a.last_position_update?.getTime() || 0;
      const timeB = b.last_position_update?.getTime() || 0;
      return timeB - timeA;
    });

    // 应用分页
    return filteredProfiles.slice(offset, offset + limit);
  }

  /**
   * 统计用户档案数量
   *
   * @param conditions 查询条件
   * @returns 档案数量
   */
  async count(conditions?: any): Promise<number> {
    if (!conditions) {
      return this.profiles.size;
    }

    // 简单的条件过滤统计
    let count = 0;
    for (const profile of this.profiles.values()) {
      let match = true;

      for (const [key, value] of Object.entries(conditions)) {
        if ((profile as any)[key] !== value) {
          match = false;
          break;
        }
      }

      if (match) {
        count++;
      }
    }

    return count;
  }

  /**
   * 删除用户档案
   *
   * 业务逻辑：
   * 1. 验证目标档案是否存在
   * 2. 从内存Map中删除档案记录
   * 3. 删除用户ID到档案ID的映射
   * 4. 记录删除操作和结果
   * 5. 返回删除操作的统计信息
   *
   * @param id 档案ID
   * @returns 删除操作结果
   * @throws NotFoundException 当档案不存在时
   */
  async remove(id: bigint): Promise<{ affected: number; message: string }> {
    const startTime = Date.now();

    this.logStart('删除用户档案', { profileId: id.toString() });

    try {
      // 检查档案是否存在
      const profile = await this.findOne(id);

      // 删除档案记录
      this.profiles.delete(id);
      this.userIdToProfileId.delete(profile.user_id);

      const deleteResult = {
        affected: 1,
        message: `成功删除ID为 ${id} 的用户档案`
      };

      const duration = this.calculateDuration(startTime);

      this.logSuccess('删除用户档案', {
        profileId: id.toString(),
        userId: profile.user_id.toString(),
        affected: deleteResult.affected
      }, duration);

      return deleteResult;
    } catch (error) {
      const duration = this.calculateDuration(startTime);

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logError('删除用户档案',
        error instanceof Error ? error.message : String(error),
        { profileId: id.toString() },
        duration,
        error instanceof Error ? error.stack : undefined
      );

      throw new BadRequestException('用户档案删除失败，请稍后重试');
    }
  }

  /**
   * 检查用户档案是否存在
   *
   * @param userId 用户ID
   * @returns 是否存在
   */
  async existsByUserId(userId: bigint): Promise<boolean> {
    return this.userIdToProfileId.has(userId);
  }

  /**
   * 生成唯一ID
   *
   * 功能描述：
   * 生成唯一的档案ID，确保线程安全和ID唯一性
   *
   * 技术实现：
   * 1. 使用简单的锁机制防止并发冲突
   * 2. 自增ID生成，确保唯一性
   * 3. 释放锁，允许其他操作继续
   *
   * @returns 唯一的档案ID
   */
  private generateUniqueId(): bigint {
    const lockKey = 'id_generation';

    // 简单的锁机制
    while (this.ID_LOCK.has(lockKey)) {
      // 等待锁释放（简单的自旋锁）
    }

    this.ID_LOCK.add(lockKey);

    try {
      const id = this.CURRENT_ID;
      this.CURRENT_ID = this.CURRENT_ID + BigInt(1);
      return id;
    } finally {
      this.ID_LOCK.delete(lockKey);
    }
  }

  /**
   * 清空所有数据
   *
   * 功能描述：
   * 清空内存中的所有档案数据，用于测试环境的数据重置
   *
   * 注意：此方法仅用于测试环境，生产环境请勿使用
   */
  async clearAll(): Promise<void> {
    this.profiles.clear();
    this.userIdToProfileId.clear();
    this.CURRENT_ID = BigInt(1);

    this.logger.warn('清空所有用户档案数据', {
      operation: 'clearAll',
      timestamp: new Date().toISOString()
    });
  }

  /**
   * 获取内存使用统计
   *
   * 功能描述：
   * 获取当前内存存储的统计信息，用于监控和调试
   *
   * @returns 内存使用统计
   */
  getMemoryStats(): {
    profileCount: number;
    userIdMappingCount: number;
    currentId: string;
  } {
    return {
      profileCount: this.profiles.size,
      userIdMappingCount: this.userIdToProfileId.size,
      currentId: this.CURRENT_ID.toString()
    };
  }
}