/**
 * 用户位置持久化核心服务
 *
 * 功能描述：
 * - 管理用户位置数据的数据库持久化操作
 * - 处理user_profiles表的位置字段更新
 * - 提供位置历史记录的存储和查询
 * - 支持位置数据的批量操作和统计分析
 *
 * 职责分离：
 * - 数据持久化：将位置数据保存到MySQL数据库
 * - 历史管理：维护用户位置的历史轨迹记录
 * - 批量操作：优化的批量数据处理能力
 * - 数据恢复：支持位置数据的加载和恢复
 *
 * 技术实现：
 * - 数据库操作：通过UserProfiles服务操作数据库
 * - 事务处理：确保数据操作的原子性
 * - 异常处理：完善的错误处理和回滚机制
 * - 性能优化：批量操作和索引优化
 *
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 完成TODO项实现，实现位置历史记录存储和过期数据清理功能 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建用户位置持久化核心服务 (修改者: moyin)
 * - 2026-01-08: 注释优化 - 完善类注释和方法注释规范 (修改者: moyin)
 * - 2026-01-08: 注释完善 - 补充所有辅助方法的完整注释 (修改者: moyin)
 * - 2026-01-08: 代码质量优化 - 添加常量定义和参数验证优化，完善日志记录优化 (修改者: moyin)
 * - 2026-01-08: 代码质量优化 - 统一所有方法的日志记录模式，减少代码重复 (修改者: moyin)
 * - 2026-01-08: 架构分层检查 - 确认Core层专注技术实现，职责分离清晰 (修改者: moyin)
 *
 * @author moyin
 * @version 1.0.7
 * @since 2026-01-08
 * @lastModified 2026-01-12
 */

import { Injectable, Inject, Logger } from '@nestjs/common';
import { IUserPositionCore } from './core_services.interface';
import { Position, PositionHistory } from './position.interface';

// 常量定义
const MIN_STATUS_VALUE = 0; // 最小状态值
const MAX_STATUS_VALUE = 255; // 最大状态值
const DEFAULT_HISTORY_LIMIT = 10; // 默认历史记录限制数量

@Injectable()
/**
 * 用户位置持久化核心服务类
 *
 * 职责：
 * - 管理用户位置数据的数据库持久化
 * - 处理位置历史记录的存储和查询
 * - 提供批量位置数据操作功能
 * - 支持位置数据的统计和分析
 *
 * 主要方法：
 * - saveUserPosition: 保存用户位置到数据库
 * - loadUserPosition: 从数据库加载用户位置
 * - savePositionHistory: 保存位置历史记录
 * - batchUpdateUserStatus: 批量更新用户状态
 * - getUserPositionStats: 获取用户位置统计
 *
 * 使用场景：
 * - 位置数据的长期存储和备份
 * - 用户位置历史轨迹分析
 * - 批量数据处理和维护
 * - 位置相关的统计报表
 */
export class UserPositionCore implements IUserPositionCore {
  private readonly logger = new Logger(UserPositionCore.name);

  // 内存存储位置历史记录（简单实现）
  private readonly positionHistory = new Map<string, PositionHistory[]>();
  private historyIdCounter = 1;

  constructor(
    @Inject('IUserProfilesService')
    private readonly userProfilesService: any, // 用户档案服务
  ) {}

  /**
   * 记录操作开始日志
   * @param operation 操作名称
   * @param params 操作参数
   * @returns 开始时间
   */
  private logOperationStart(operation: string, params: Record<string, any>): number {
    const startTime = Date.now();
    this.logger.log(`开始${this.getOperationDescription(operation)}`, {
      operation,
      ...params,
      timestamp: new Date().toISOString()
    });
    return startTime;
  }

  /**
   * 记录操作成功日志
   * @param operation 操作名称
   * @param params 操作参数
   * @param startTime 开始时间
   */
  private logOperationSuccess(operation: string, params: Record<string, any>, startTime: number): void {
    const duration = Date.now() - startTime;
    this.logger.log(`${this.getOperationDescription(operation)}成功`, {
      operation,
      ...params,
      duration,
      timestamp: new Date().toISOString()
    });
  }

  /**
   * 记录操作失败日志
   * @param operation 操作名称
   * @param params 操作参数
   * @param startTime 开始时间
   * @param error 错误信息
   */
  private logOperationError(operation: string, params: Record<string, any>, startTime: number, error: any): void {
    const duration = Date.now() - startTime;
    this.logger.error(`${this.getOperationDescription(operation)}失败`, {
      operation,
      ...params,
      error: error instanceof Error ? error.message : String(error),
      duration,
      timestamp: new Date().toISOString()
    }, error instanceof Error ? error.stack : undefined);
  }

  /**
   * 获取操作描述
   * @param operation 操作名称
   * @returns 操作描述
   */
  private getOperationDescription(operation: string): string {
    const descriptions: Record<string, string> = {
      'saveUserPosition': '保存用户位置到数据库',
      'loadUserPosition': '从数据库加载用户位置',
      'savePositionHistory': '保存位置历史记录',
      'getPositionHistory': '获取位置历史记录',
      'batchUpdateUserStatus': '批量更新用户状态',
      'cleanupExpiredPositions': '清理过期位置数据',
      'getUserPositionStats': '获取用户位置统计',
      'migratePositionData': '迁移位置数据'
    };
    return descriptions[operation] || operation;
  }

  /**
   * 保存用户位置到数据库
   *
   * 技术实现：
   * 1. 验证用户ID和位置数据的有效性
   * 2. 调用用户档案服务更新位置字段
   * 3. 更新last_position_update时间戳
   * 4. 记录操作日志和性能指标
   * 5. 处理异常情况和错误恢复
   *
   * @param userId 用户ID
   * @param position 位置信息
   * @returns Promise<void> 操作完成的Promise
   * @throws Error 当用户ID或位置数据无效时抛出异常
   * @throws Error 当数据库操作失败时抛出异常
   *
   * @example
   * ```typescript
   * const position: Position = {
   *   userId: '123',
   *   x: 100,
   *   y: 200,
   *   mapId: 'plaza',
   *   timestamp: Date.now()
   * };
   * await userPositionCore.saveUserPosition('123', position);
   * ```
   */
  async saveUserPosition(userId: string, position: Position): Promise<void> {
    try {
      // 1. 验证输入参数
      if (!userId || !position) {
        throw new Error('用户ID和位置信息不能为空');
      }

      const startTime = this.logOperationStart('saveUserPosition', {
        userId,
        mapId: position.mapId,
        x: position.x,
        y: position.y
      });

      if (typeof position.x !== 'number' || typeof position.y !== 'number') {
        throw new Error('位置坐标必须是数字类型');
      }

      if (!position.mapId || position.mapId.trim() === '') {
        throw new Error('地图ID不能为空');
      }

      // 2. 调用用户档案服务更新位置
      await this.userProfilesService.updatePosition(BigInt(userId), {
        current_map: position.mapId,
        pos_x: position.x,
        pos_y: position.y
      });

      this.logOperationSuccess('saveUserPosition', {
        userId,
        mapId: position.mapId,
        x: position.x,
        y: position.y
      }, startTime);

    } catch (error) {
      const startTime = Date.now();
      this.logOperationError('saveUserPosition', { userId, position }, startTime, error);
      throw error;
    }
  }

  /**
   * 从数据库加载用户位置
   *
   * 技术实现：
   * 1. 通过用户档案服务查询用户信息
   * 2. 提取位置相关字段数据
   * 3. 构建标准的Position对象
   * 4. 处理数据不存在的情况
   * 5. 记录查询日志和性能指标
   *
   * @param userId 用户ID
   * @returns Promise<Position | null> 位置信息，如果不存在返回null
   * @throws Error 当用户ID为空时抛出异常
   *
   * @example
   * ```typescript
   * const position = await userPositionCore.loadUserPosition('123');
   * if (position) {
   *   console.log(`用户在地图 ${position.mapId} 的位置: (${position.x}, ${position.y})`);
   * }
   * ```
   */
  async loadUserPosition(userId: string): Promise<Position | null> {
    const startTime = this.logOperationStart('loadUserPosition', { userId });

    try {
      // 1. 验证用户ID
      if (!userId) {
        throw new Error('用户ID不能为空');
      }

      // 2. 查询用户档案信息
      const userProfile = await this.userProfilesService.findByUserId(BigInt(userId));

      if (!userProfile) {
        this.logger.warn('用户档案不存在', {
          operation: 'loadUserPosition',
          userId
        });
        return null;
      }

      // 3. 构建位置对象
      const position: Position = {
        userId,
        x: userProfile.pos_x || 0,
        y: userProfile.pos_y || 0,
        mapId: userProfile.current_map || 'plaza',
        timestamp: userProfile.last_position_update?.getTime() || Date.now(),
        metadata: {
          status: userProfile.status,
          lastLogin: userProfile.last_login_at?.getTime()
        }
      };

      this.logOperationSuccess('loadUserPosition', {
        userId,
        mapId: position.mapId,
        x: position.x,
        y: position.y
      }, startTime);

      return position;

    } catch (error) {
      this.logOperationError('loadUserPosition', { userId }, startTime, error);
      return null;
    }
  }

  /**
   * 保存位置历史记录
   *
   * 技术实现：
   * 1. 构建位置历史记录数据
   * 2. 插入到位置历史表中
   * 3. 处理会话ID的关联
   * 4. 实现历史记录的清理策略
   *
   * 注意：这个方法需要创建位置历史表，当前先记录日志
   *
   * @param userId 用户ID
   * @param position 位置信息
   * @param sessionId 会话ID（可选）
   * @returns Promise<void> 操作完成的Promise
   * @throws 不抛出异常，历史记录保存失败不影响主要功能
   *
   * @example
   * ```typescript
   * const position: Position = {
   *   userId: '123',
   *   x: 100,
   *   y: 200,
   *   mapId: 'plaza',
   *   timestamp: Date.now()
   * };
   * await userPositionCore.savePositionHistory('123', position, 'session456');
   * ```
   */
  async savePositionHistory(userId: string, position: Position, sessionId?: string): Promise<void> {
    const startTime = this.logOperationStart('savePositionHistory', {
      userId,
      mapId: position.mapId,
      x: position.x,
      y: position.y,
      sessionId
    });

    try {
      // 创建历史记录
      const historyRecord: PositionHistory = {
        id: this.historyIdCounter++,
        userId: position.userId,
        x: position.x,
        y: position.y,
        mapId: position.mapId,
        timestamp: position.timestamp,
        sessionId,
        createdAt: new Date()
      };

      // 获取用户的历史记录列表
      let userHistory = this.positionHistory.get(userId);
      if (!userHistory) {
        userHistory = [];
        this.positionHistory.set(userId, userHistory);
      }

      // 添加新记录
      userHistory.push(historyRecord);

      // 保持最多100条记录（避免内存无限增长）
      if (userHistory.length > 100) {
        userHistory.shift(); // 移除最旧的记录
      }

      this.logOperationSuccess('savePositionHistory', {
        userId,
        mapId: position.mapId,
        x: position.x,
        y: position.y,
        sessionId,
        historyId: historyRecord.id,
        totalRecords: userHistory.length
      }, startTime);

    } catch (error) {
      this.logOperationError('savePositionHistory', { userId, position, sessionId }, startTime, error);
      // 历史记录保存失败不应该影响主要功能，所以不抛出异常
    }
  }

  /**
   * 获取位置历史记录
   *
   * 技术实现：
   * 1. 从位置历史表查询用户记录
   * 2. 按时间倒序排列
   * 3. 限制返回记录数量
   * 4. 构建PositionHistory对象列表
   *
   * 注意：当前版本返回空数组，后续版本实现完整查询功能
   *
   * @param userId 用户ID
   * @param limit 限制数量，默认10条
   * @returns Promise<PositionHistory[]> 历史记录列表
   * @throws 不抛出异常，错误时返回空数组并记录日志
   *
   * @example
   * ```typescript
   * const history = await userPositionCore.getPositionHistory('123', 20);
   * console.log(`用户有 ${history.length} 条位置历史记录`);
   * ```
   */
  async getPositionHistory(userId: string, limit: number = DEFAULT_HISTORY_LIMIT): Promise<PositionHistory[]> {
    const startTime = this.logOperationStart('getPositionHistory', { userId, limit });

    try {
      // 从内存获取用户的历史记录
      const userHistory = this.positionHistory.get(userId) || [];

      // 按时间倒序排列，返回最新的记录
      const sortedHistory = userHistory
        .sort((a, b) => b.timestamp - a.timestamp)
        .slice(0, limit);

      this.logOperationSuccess('getPositionHistory', {
        userId,
        limit,
        recordCount: sortedHistory.length,
        totalRecords: userHistory.length
      }, startTime);

      return sortedHistory;

    } catch (error) {
      this.logOperationError('getPositionHistory', { userId, limit }, startTime, error);
      return [];
    }
  }

  /**
   * 批量更新用户状态
   *
   * 技术实现：
   * 1. 验证用户ID列表和状态值
   * 2. 调用用户档案服务的批量更新方法
   * 3. 记录批量操作的结果和性能
   * 4. 处理部分成功的情况
   *
   * @param userIds 用户ID列表
   * @param status 状态值（0-255之间的数字）
   * @returns Promise<number> 更新的记录数
   * @throws Error 当用户ID列表为空或状态值无效时抛出异常
   * @throws Error 当数据库批量操作失败时抛出异常
   *
   * @example
   * ```typescript
   * const userIds = ['123', '456', '789'];
   * const count = await userPositionCore.batchUpdateUserStatus(userIds, 1);
   * console.log(`成功更新了 ${count} 个用户的状态`);
   * ```
   */
  async batchUpdateUserStatus(userIds: string[], status: number): Promise<number> {
    const startTime = this.logOperationStart('batchUpdateUserStatus', {
      userCount: userIds.length,
      status
    });

    try {
      // 1. 验证输入参数
      if (!userIds || userIds.length === 0) {
        throw new Error('用户ID列表不能为空');
      }

      if (typeof status !== 'number' || status < MIN_STATUS_VALUE || status > MAX_STATUS_VALUE) {
        throw new Error(`状态值必须是${MIN_STATUS_VALUE}-${MAX_STATUS_VALUE}之间的数字`);
      }

      // 2. 转换用户ID为bigint类型
      const bigintUserIds = userIds.map(id => {
        try {
          return BigInt(id);
        } catch (error) {
          throw new Error(`无效的用户ID: ${id}`);
        }
      });

      // 3. 调用用户档案服务批量更新
      const updatedCount = await this.userProfilesService.batchUpdateStatus(bigintUserIds, status);

      this.logOperationSuccess('batchUpdateUserStatus', {
        userCount: userIds.length,
        status,
        updatedCount
      }, startTime);

      return updatedCount;

    } catch (error) {
      this.logOperationError('batchUpdateUserStatus', { userCount: userIds.length, status }, startTime, error);
      throw error;
    }
  }

  /**
   * 清理过期位置数据
   *
   * 技术实现：
   * 1. 清理内存中过期的位置历史记录
   * 2. 统计清理的记录数量
   * 3. 记录清理操作日志
   *
   * @param expireTime 过期时间
   * @returns Promise<number> 清理的记录数
   * @throws 不抛出异常，错误时返回0并记录日志
   *
   * @example
   * ```typescript
   * const expireTime = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); // 7天前
   * const count = await userPositionCore.cleanupExpiredPositions(expireTime);
   * console.log(`清理了 ${count} 条过期位置数据`);
   * ```
   */
  async cleanupExpiredPositions(expireTime: Date): Promise<number> {
    const startTime = this.logOperationStart('cleanupExpiredPositions', {
      expireTime: expireTime.toISOString()
    });

    try {
      let cleanedCount = 0;
      const expireTimestamp = expireTime.getTime();

      // 清理内存中过期的位置历史记录
      for (const [userId, userHistory] of this.positionHistory.entries()) {
        const originalLength = userHistory.length;

        // 过滤掉过期的记录
        const filteredHistory = userHistory.filter(record =>
          record.timestamp > expireTimestamp
        );

        const removedCount = originalLength - filteredHistory.length;
        cleanedCount += removedCount;

        if (removedCount > 0) {
          this.positionHistory.set(userId, filteredHistory);

          // 如果用户没有任何历史记录了，删除整个条目
          if (filteredHistory.length === 0) {
            this.positionHistory.delete(userId);
          }
        }
      }

      this.logOperationSuccess('cleanupExpiredPositions', {
        expireTime: expireTime.toISOString(),
        cleanedCount
      }, startTime);

      return cleanedCount;

    } catch (error) {
      this.logOperationError('cleanupExpiredPositions', { expireTime: expireTime.toISOString() }, startTime, error);
      return 0;
    }
  }

  /**
   * 获取用户位置统计
   *
   * 技术实现：
   * 1. 获取用户当前位置信息
   * 2. 统计历史记录数量
   * 3. 计算活跃度指标
   * 4. 构建统计信息对象
   *
   * @param userId 用户ID
   * @returns Promise<any> 统计信息对象
   * @throws 不抛出异常，错误时返回错误信息对象
   *
   * @example
   * ```typescript
   * const stats = await userPositionCore.getUserPositionStats('123');
   * if (stats.hasCurrentPosition) {
   *   console.log(`用户当前在地图 ${stats.currentPosition.mapId}`);
   * }
   * ```
   */
  async getUserPositionStats(userId: string): Promise<any> {
    const startTime = this.logOperationStart('getUserPositionStats', { userId });

    try {
      // 1. 获取用户当前位置
      const currentPosition = await this.loadUserPosition(userId);

      // 2. 获取历史记录数量
      const userHistory = this.positionHistory.get(userId) || [];
      const historyCount = userHistory.length;

      // 3. 计算统计信息
      const uniqueMaps = new Set<string>();
      if (currentPosition) {
        uniqueMaps.add(currentPosition.mapId);
      }

      // 统计历史记录中的地图
      userHistory.forEach(record => {
        uniqueMaps.add(record.mapId);
      });

      // 4. 构建统计信息
      const stats = {
        userId,
        hasCurrentPosition: !!currentPosition,
        currentPosition,
        lastUpdateTime: currentPosition?.timestamp,
        historyCount,
        totalMaps: uniqueMaps.size,
        uniqueMaps: Array.from(uniqueMaps),
        timestamp: Date.now()
      };

      this.logOperationSuccess('getUserPositionStats', {
        userId,
        hasCurrentPosition: stats.hasCurrentPosition,
        historyCount,
        totalMaps: stats.totalMaps
      }, startTime);

      return stats;

    } catch (error) {
      this.logOperationError('getUserPositionStats', { userId }, startTime, error);

      return {
        userId,
        hasCurrentPosition: false,
        error: error instanceof Error ? error.message : String(error),
        timestamp: Date.now()
      };
    }
  }

  /**
   * 迁移位置数据
   *
   * 技术实现：
   * 1. 验证源用户ID和目标用户ID
   * 2. 加载源用户的位置数据
   * 3. 将位置数据保存到目标用户
   * 4. 迁移历史记录数据（暂未实现）
   * 5. 记录迁移操作日志
   *
   * @param fromUserId 源用户ID
   * @param toUserId 目标用户ID
   * @returns Promise<void> 操作完成的Promise
   * @throws Error 当用户ID无效或相同时抛出异常
   * @throws Error 当数据库操作失败时抛出异常
   *
   * @example
   * ```typescript
   * await userPositionCore.migratePositionData('oldUser123', 'newUser456');
   * console.log('位置数据迁移完成');
   * ```
   */
  async migratePositionData(fromUserId: string, toUserId: string): Promise<void> {
    const startTime = this.logOperationStart('migratePositionData', { fromUserId, toUserId });

    try {
      // 1. 验证输入参数
      if (!fromUserId || !toUserId) {
        throw new Error('源用户ID和目标用户ID不能为空');
      }

      if (fromUserId === toUserId) {
        throw new Error('源用户ID和目标用户ID不能相同');
      }

      // 2. 加载源用户位置数据
      const sourcePosition = await this.loadUserPosition(fromUserId);

      if (!sourcePosition) {
        this.logger.warn('源用户没有位置数据，跳过迁移', {
          operation: 'migratePositionData',
          fromUserId,
          toUserId
        });
        return;
      }

      // 3. 将位置数据保存到目标用户
      const targetPosition: Position = {
        ...sourcePosition,
        userId: toUserId
      };

      await this.saveUserPosition(toUserId, targetPosition);

      // 4. 历史记录数据迁移功能暂未实现

      this.logOperationSuccess('migratePositionData', {
        fromUserId,
        toUserId,
        migratedPosition: {
          mapId: sourcePosition.mapId,
          x: sourcePosition.x,
          y: sourcePosition.y
        }
      }, startTime);

    } catch (error) {
      this.logOperationError('migratePositionData', { fromUserId, toUserId }, startTime, error);
      throw error;
    }
  }
}