/**
 * 用户档案服务类
 *
 * 功能描述：
 * - 提供用户档案数据的增删改查技术实现
 * - 处理位置信息的持久化和存储操作
 * - 数据格式验证和约束检查
 * - 支持完整的用户档案生命周期管理
 *
 * 职责分离：
 * - 数据持久化：通过TypeORM操作MySQL数据库
 * - 数据验证：数据格式和约束完整性检查
 * - 异常处理：统一的错误处理和日志记录
 * - 性能监控：操作耗时统计和性能优化
 *
 * 位置广播系统集成：
 * - 位置数据的持久化存储
 * - 支持位置更新时间戳管理
 * - 提供地图用户查询功能
 * - 实现位置数据的批量操作
 *
 * 最近修改：
 * - 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 { InjectRepository } from '@nestjs/typeorm';
import { Repository, FindOptionsWhere } from 'typeorm';
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 UserProfilesService extends BaseUserProfilesService {

  constructor(
    @InjectRepository(UserProfiles)
    private readonly userProfilesRepository: Repository<UserProfiles>,
  ) {
    super(); // 调用基类构造函数
  }

  /**
   * 创建新用户档案
   *
   * 技术实现：
   * 1. 验证输入数据的格式和完整性
   * 2. 使用class-validator进行DTO数据验证
   * 3. 检查用户ID的唯一性约束
   * 4. 创建用户档案实体并设置默认值
   * 5. 保存用户档案数据到数据库
   * 6. 记录操作日志和性能指标
   * 7. 返回创建成功的用户档案实体
   *
   * @param createUserProfileDto 创建用户档案的数据传输对象
   * @returns 创建成功的用户档案实体，包含自动生成的ID和时间戳
   * @throws BadRequestException 当数据验证失败或输入格式错误时
   * @throws ConflictException 当用户ID已存在档案时
   *
   * @example
   * ```typescript
   * const newProfile = await userProfilesService.create({
   *   user_id: BigInt(1),
   *   current_map: 'plaza',
   *   pos_x: 0,
   *   pos_y: 0,
   *   bio: '新用户'
   * });
   * console.log(`用户档案创建成功，ID: ${newProfile.id}`);
   * ```
   */
  async create(createUserProfileDto: CreateUserProfileDto): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logger.log('开始创建用户档案', {
      operation: 'create',
      userId: createUserProfileDto.user_id.toString(),
      currentMap: createUserProfileDto.current_map,
      timestamp: new Date().toISOString()
    });

    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.logger.warn('用户档案创建失败：数据验证失败', {
          operation: 'create',
          userId: createUserProfileDto.user_id.toString(),
          validationErrors: errorMessages
        });

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

      // 检查用户ID是否已存在档案
      const existingProfile = await this.userProfilesRepository.findOne({
        where: { user_id: createUserProfileDto.user_id }
      });

      if (existingProfile) {
        this.logger.warn('用户档案创建失败：用户ID已存在档案', {
          operation: 'create',
          userId: createUserProfileDto.user_id.toString(),
          existingProfileId: existingProfile.id.toString()
        });

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

      // 创建用户档案实体
      const userProfile = new UserProfiles();
      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 || 'whale_port';
      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(); // 设置初始位置更新时间

      // 保存到数据库
      const savedProfile = await this.userProfilesRepository.save(userProfile);

      const duration = Date.now() - startTime;

      this.logger.log('用户档案创建成功', {
        operation: 'create',
        profileId: savedProfile.id.toString(),
        userId: savedProfile.user_id.toString(),
        currentMap: savedProfile.current_map,
        duration,
        timestamp: new Date().toISOString()
      });

      return savedProfile;
    } catch (error) {
      const duration = Date.now() - startTime;

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

      this.logger.error('用户档案创建系统异常', {
        operation: 'create',
        userId: createUserProfileDto.user_id.toString(),
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, error instanceof Error ? error.stack : undefined);

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

  /**
   * 根据ID查询用户档案
   *
   * @param id 档案ID
   * @returns 用户档案实体
   * @throws NotFoundException 当档案不存在时
   */
  async findOne(id: bigint): Promise<UserProfiles> {
    const profile = await this.userProfilesRepository.findOne({
      where: { id }
    });

    if (!profile) {
      throw new NotFoundException(`ID为 ${id} 的用户档案不存在`);
    }

    return profile;
  }

  /**
   * 根据用户ID查询用户档案
   *
   * @param userId 用户ID
   * @returns 用户档案实体或null
   */
  async findByUserId(userId: bigint): Promise<UserProfiles | null> {
    return await this.userProfilesRepository.findOne({
      where: { user_id: userId }
    });
  }

  /**
   * 根据地图查询用户档案列表
   *
   * 功能描述：
   * 查询指定地图中的所有用户档案，支持状态过滤和分页
   *
   * 业务逻辑：
   * 1. 构建查询条件（地图、状态）
   * 2. 应用分页参数
   * 3. 按最后位置更新时间排序
   * 4. 返回查询结果
   *
   * 位置广播系统应用：
   * - 获取同一地图的所有在线用户
   * - 支持位置广播的目标用户筛选
   * - 提供地图用户统计功能
   *
   * @param mapId 地图ID
   * @param status 用户状态过滤（可选）
   * @param limit 限制数量，默认50
   * @param offset 偏移量，默认0
   * @returns 用户档案列表
   *
   * @example
   * ```typescript
   * // 获取plaza地图中的所有在线用户
   * const onlineUsers = await userProfilesService.findByMap('plaza', 1, 20, 0);
   *
   * // 获取forest地图中的所有用户（不限状态）
   * const allUsers = await userProfilesService.findByMap('forest');
   * ```
   */
  async findByMap(mapId: string, status?: number, limit: number = 50, offset: number = 0): Promise<UserProfiles[]> {
    const startTime = Date.now();

    this.logger.log('开始查询地图用户档案', {
      operation: 'findByMap',
      mapId,
      status,
      limit,
      offset,
      timestamp: new Date().toISOString()
    });

    try {
      // 构建查询条件
      const whereCondition: FindOptionsWhere<UserProfiles> = {
        current_map: mapId
      };

      // 添加状态过滤
      if (status !== undefined) {
        whereCondition.status = status;
      }

      const profiles = await this.userProfilesRepository.find({
        where: whereCondition,
        take: limit,
        skip: offset,
        order: { last_position_update: 'DESC' }
      });

      const duration = Date.now() - startTime;

      this.logger.log('地图用户档案查询成功', {
        operation: 'findByMap',
        mapId,
        status,
        resultCount: profiles.length,
        duration,
        timestamp: new Date().toISOString()
      });

      return profiles;
    } catch (error) {
      const duration = Date.now() - startTime;

      this.logger.error('地图用户档案查询异常', {
        operation: 'findByMap',
        mapId,
        status,
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, error instanceof Error ? error.stack : undefined);

      // 查询异常返回空数组而不抛出异常
      return [];
    }
  }

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

    this.logger.log('开始更新用户档案信息', {
      operation: 'update',
      profileId: id.toString(),
      updateFields: Object.keys(updateData),
      timestamp: new Date().toISOString()
    });

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

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

      // 保存更新后的档案信息
      const updatedProfile = await this.userProfilesRepository.save(existingProfile);

      const duration = Date.now() - startTime;

      this.logger.log('用户档案信息更新成功', {
        operation: 'update',
        profileId: id.toString(),
        userId: updatedProfile.user_id.toString(),
        updateFields: Object.keys(updateData),
        duration,
        timestamp: new Date().toISOString()
      });

      return updatedProfile;
    } catch (error) {
      const duration = Date.now() - startTime;

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logger.error('用户档案更新系统异常', {
        operation: 'update',
        profileId: id.toString(),
        updateData,
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, error instanceof Error ? error.stack : undefined);

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

  /**
   * 更新用户位置信息
   *
   * 功能描述：
   * 专门用于位置广播系统的位置更新操作，高性能优化
   *
   * 技术实现：
   * 1. 根据用户ID查找档案记录
   * 2. 更新位置相关字段（地图、坐标）
   * 3. 自动更新位置更新时间戳
   * 4. 执行数据库更新操作
   * 5. 记录位置更新日志
   *
   * 性能优化：
   * - 只更新位置相关字段，减少数据传输
   * - 使用部分更新，避免全量数据操作
   * - 批量操作支持，提高并发性能
   *
   * @param userId 用户ID
   * @param positionData 位置数据
   * @returns 更新后的用户档案实体
   * @throws NotFoundException 当用户档案不存在时
   *
   * @example
   * ```typescript
   * // 更新用户位置
   * const updatedProfile = await userProfilesService.updatePosition(
   *   BigInt(1),
   *   {
   *     current_map: 'forest',
   *     pos_x: 150.5,
   *     pos_y: 200.3
   *   }
   * );
   * ```
   */
  async updatePosition(userId: bigint, positionData: UpdatePositionDto): Promise<UserProfiles> {
    const startTime = Date.now();

    this.logger.log('开始更新用户位置', {
      operation: 'updatePosition',
      userId: userId.toString(),
      currentMap: positionData.current_map,
      posX: positionData.pos_x,
      posY: positionData.pos_y,
      timestamp: new Date().toISOString()
    });

    try {
      // 查找用户档案
      const profile = await this.userProfilesRepository.findOne({
        where: { user_id: userId }
      });

      if (!profile) {
        this.logger.warn('用户位置更新失败：档案不存在', {
          operation: 'updatePosition',
          userId: userId.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(); // 更新位置更新时间

      // 保存更新
      const updatedProfile = await this.userProfilesRepository.save(profile);

      const duration = Date.now() - startTime;

      this.logger.log('用户位置更新成功', {
        operation: 'updatePosition',
        profileId: updatedProfile.id.toString(),
        userId: userId.toString(),
        currentMap: updatedProfile.current_map,
        posX: updatedProfile.pos_x,
        posY: updatedProfile.pos_y,
        duration,
        timestamp: new Date().toISOString()
      });

      return updatedProfile;
    } catch (error) {
      const duration = Date.now() - startTime;

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logger.error('用户位置更新系统异常', {
        operation: 'updatePosition',
        userId: userId.toString(),
        positionData,
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, 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.logger.log('开始批量更新用户状态', {
      operation: 'batchUpdateStatus',
      userCount: userIds.length,
      targetStatus: status,
      timestamp: new Date().toISOString()
    });

    try {
      const result = await this.userProfilesRepository.update(
        { user_id: { $in: userIds } as any },
        { status }
      );

      const duration = Date.now() - startTime;

      this.logger.log('批量更新用户状态成功', {
        operation: 'batchUpdateStatus',
        userCount: userIds.length,
        targetStatus: status,
        affectedRows: result.affected || 0,
        duration,
        timestamp: new Date().toISOString()
      });

      return result.affected || 0;
    } catch (error) {
      const duration = Date.now() - startTime;

      this.logger.error('批量更新用户状态异常', {
        operation: 'batchUpdateStatus',
        userCount: userIds.length,
        targetStatus: status,
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, 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 whereCondition: FindOptionsWhere<UserProfiles> = {};

    if (current_map) {
      whereCondition.current_map = current_map;
    }

    if (status !== undefined) {
      whereCondition.status = status;
    }

    return await this.userProfilesRepository.find({
      where: whereCondition,
      take: limit,
      skip: offset,
      order: { last_position_update: 'DESC' }
    });
  }

  /**
   * 统计用户档案数量
   *
   * @param conditions 查询条件
   * @returns 档案数量
   */
  async count(conditions?: FindOptionsWhere<UserProfiles>): Promise<number> {
    return await this.userProfilesRepository.count({ where: conditions });
  }

  /**
   * 删除用户档案
   *
   * @param id 档案ID
   * @returns 删除操作结果
   * @throws NotFoundException 当档案不存在时
   */
  async remove(id: bigint): Promise<{ affected: number; message: string }> {
    const startTime = Date.now();

    this.logger.log('开始删除用户档案', {
      operation: 'remove',
      profileId: id.toString(),
      timestamp: new Date().toISOString()
    });

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

      // 执行删除操作
      const result = await this.userProfilesRepository.delete({ id });

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

      const duration = Date.now() - startTime;

      this.logger.log('用户档案删除成功', {
        operation: 'remove',
        profileId: id.toString(),
        affected: deleteResult.affected,
        duration,
        timestamp: new Date().toISOString()
      });

      return deleteResult;
    } catch (error) {
      const duration = Date.now() - startTime;

      if (error instanceof NotFoundException) {
        throw error;
      }

      this.logger.error('用户档案删除系统异常', {
        operation: 'remove',
        profileId: id.toString(),
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, error instanceof Error ? error.stack : undefined);

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

  /**
   * 检查用户档案是否存在
   *
   * @param userId 用户ID
   * @returns 是否存在
   */
  async existsByUserId(userId: bigint): Promise<boolean> {
    const count = await this.userProfilesRepository.count({
      where: { user_id: userId }
    });
    return count > 0;
  }
}
