/**
 * 位置管理业务服务
 *
 * 功能描述：
 * - 管理用户位置数据的业务逻辑
 * - 处理位置验证、过滤和转换
 * - 提供位置查询和统计功能
 * - 实现位置相关的业务规则
 *
 * 职责分离：
 * - 位置业务：专注于位置数据的业务逻辑处理
 * - 数据验证：位置数据的格式验证和业务规则验证
 * - 查询服务：提供灵活的位置数据查询接口
 * - 统计分析：位置数据的统计和分析功能
 *
 * 技术实现：
 * - 位置验证：多层次的位置数据验证机制
 * - 性能优化：高效的位置查询和缓存策略
 * - 数据转换：位置数据格式的标准化处理
 * - 业务规则：复杂的位置相关业务逻辑实现
 *
 * 最近修改：
 * - 2026-01-08: 代码重构 - 提取魔法数字为常量，优化代码质量 (修改者: moyin)
 *
 * @author moyin
 * @version 1.2.0
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Injectable, Inject, Logger, BadRequestException, NotFoundException } from '@nestjs/common';
import { Position, PositionHistory } from '../../../core/location_broadcast_core/position.interface';

/**
 * 位置查询请求DTO
 */
export interface PositionQueryRequest {
  /** 用户ID列表 */
  userIds?: string[];
  /** 地图ID */
  mapId?: string;
  /** 会话ID */
  sessionId?: string;
  /** 查询范围（中心点和半径） */
  range?: {
    centerX: number;
    centerY: number;
    radius: number;
  };
  /** 时间范围 */
  timeRange?: {
    startTime: number;
    endTime: number;
  };
  /** 是否包含离线用户 */
  includeOffline?: boolean;
  /** 分页参数 */
  pagination?: {
    offset: number;
    limit: number;
  };
}

/**
 * 位置查询响应DTO
 */
export interface PositionQueryResponse {
  /** 位置列表 */
  positions: Position[];
  /** 总数 */
  total: number;
  /** 查询时间戳 */
  timestamp: number;
}

/**
 * 位置统计请求DTO
 */
export interface PositionStatsRequest {
  /** 地图ID */
  mapId?: string;
  /** 会话ID */
  sessionId?: string;
  /** 时间范围 */
  timeRange?: {
    startTime: number;
    endTime: number;
  };
}

/**
 * 位置统计响应DTO
 */
export interface PositionStatsResponse {
  /** 总用户数 */
  totalUsers: number;
  /** 在线用户数 */
  onlineUsers: number;
  /** 活跃地图数 */
  activeMaps: number;
  /** 地图用户分布 */
  mapDistribution: Record<string, number>;
  /** 位置更新频率（每分钟） */
  updateFrequency: number;
  /** 统计时间戳 */
  timestamp: number;
}

/**
 * 位置历史查询请求DTO
 */
export interface PositionHistoryRequest {
  /** 用户ID */
  userId: string;
  /** 时间范围 */
  timeRange?: {
    startTime: number;
    endTime: number;
  };
  /** 地图ID过滤 */
  mapId?: string;
  /** 最大记录数 */
  limit?: number;
}

/**
 * 位置验证结果DTO
 */
export interface PositionValidationResult {
  /** 是否有效 */
  isValid: boolean;
  /** 错误信息 */
  errors: string[];
  /** 警告信息 */
  warnings: string[];
  /** 修正后的位置（如果有） */
  correctedPosition?: Position;
}

@Injectable()
export class LocationPositionService {
  private readonly logger = new Logger(LocationPositionService.name);

  /** 坐标最大值 */
  /** 坐标最大值 */
  private static readonly MAX_COORDINATE = 999999;
  /** 坐标最小值 */
  private static readonly MIN_COORDINATE = -999999;
  /** 默认查询限制 */
  private static readonly DEFAULT_QUERY_LIMIT = 100;
  /** 时间转换常量 */
  private static readonly MILLISECONDS_PER_MINUTE = 60 * 1000;
  /** 位置时间戳最大偏差（毫秒） */
  private static readonly MAX_TIMESTAMP_DIFF = 5 * LocationPositionService.MILLISECONDS_PER_MINUTE;
  /** 地图ID最大长度 */
  private static readonly MAX_MAP_ID_LENGTH = 50;
  /** 用户ID列表最大数量 */
  private static readonly MAX_USER_IDS_COUNT = 1000;
  /** 查询半径最大值 */
  private static readonly MAX_QUERY_RADIUS = 10000;
  /** 分页限制最大值 */
  private static readonly MAX_PAGINATION_LIMIT = 1000;

  constructor(
    @Inject('ILocationBroadcastCore')
    private readonly locationBroadcastCore: any,
    @Inject('IUserPositionCore')
    private readonly userPositionCore: any,
  ) {}

  /**
   * 查询位置信息
   *
   * 业务逻辑：
   * 1. 验证查询参数
   * 2. 根据条件构建查询策略
   * 3. 执行位置数据查询
   * 4. 过滤和排序结果
   * 5. 返回格式化的查询结果
   *
   * @param request 位置查询请求
   * @returns 位置查询响应
   */
  async queryPositions(request: PositionQueryRequest): Promise<PositionQueryResponse> {
    const startTime = Date.now();

    this.logger.log('查询位置信息', {
      operation: 'queryPositions',
      userIds: request.userIds?.length,
      mapId: request.mapId,
      sessionId: request.sessionId,
      hasRange: !!request.range,
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 验证查询参数
      this.validatePositionQuery(request);

      let positions: Position[] = [];

      // 2. 根据查询条件执行不同的查询策略
      if (request.sessionId) {
        // 按会话查询
        positions = await this.locationBroadcastCore.getSessionPositions(request.sessionId);
      } else if (request.mapId) {
        // 按地图查询
        positions = await this.locationBroadcastCore.getMapPositions(request.mapId);
      } else if (request.userIds && request.userIds.length > 0) {
        // 按用户ID列表查询
        positions = await this.queryPositionsByUserIds(request.userIds);
      } else {
        // 全量查询（需要谨慎使用）
        this.logger.warn('执行全量位置查询', { request });
        positions = [];
      }

      // 3. 应用过滤条件
      positions = this.applyPositionFilters(positions, request);

      // 4. 应用分页
      const total = positions.length;
      if (request.pagination) {
        const { offset, limit } = request.pagination;
        positions = positions.slice(offset, offset + limit);
      }

      const duration = Date.now() - startTime;

      this.logger.log('位置查询完成', {
        operation: 'queryPositions',
        resultCount: positions.length,
        total,
        duration,
        timestamp: new Date().toISOString()
      });

      return {
        positions,
        total,
        timestamp: Date.now()
      };

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

      this.logger.error('位置查询失败', {
        operation: 'queryPositions',
        request,
        error: error instanceof Error ? error.message : String(error),
        duration,
        timestamp: new Date().toISOString()
      }, error instanceof Error ? error.stack : undefined);

      throw error;
    }
  }

  /**
   * 获取位置统计信息
   *
   * @param request 统计请求
   * @returns 统计结果
   */
  async getPositionStats(request: PositionStatsRequest): Promise<PositionStatsResponse> {
    try {
      let positions: Position[] = [];

      // 根据条件获取位置数据
      if (request.sessionId) {
        positions = await this.locationBroadcastCore.getSessionPositions(request.sessionId);
      } else if (request.mapId) {
        positions = await this.locationBroadcastCore.getMapPositions(request.mapId);
      }

      // 应用时间过滤
      if (request.timeRange) {
        positions = positions.filter(pos =>
          pos.timestamp >= request.timeRange!.startTime &&
          pos.timestamp <= request.timeRange!.endTime
        );
      }

      // 计算统计信息
      const totalUsers = positions.length;
      const onlineUsers = totalUsers; // 缓存中的都是在线用户

      // 统计地图分布
      const mapDistribution: Record<string, number> = {};
      positions.forEach(pos => {
        mapDistribution[pos.mapId] = (mapDistribution[pos.mapId] || 0) + 1;
      });

      const activeMaps = Object.keys(mapDistribution).length;

      // 计算更新频率（简化计算）
      const updateFrequency = positions.length > 0 ?
        positions.length / Math.max(1, (Date.now() - Math.min(...positions.map(p => p.timestamp))) / LocationPositionService.MILLISECONDS_PER_MINUTE) : 0;

      return {
        totalUsers,
        onlineUsers,
        activeMaps,
        mapDistribution,
        updateFrequency,
        timestamp: Date.now()
      };

    } catch (error) {
      this.logger.error('获取位置统计失败', {
        operation: 'getPositionStats',
        request,
        error: error instanceof Error ? error.message : String(error)
      });

      throw error;
    }
  }

  /**
   * 获取用户位置历史
   *
   * @param request 历史查询请求
   * @returns 位置历史列表
   */
  async getPositionHistory(request: PositionHistoryRequest): Promise<PositionHistory[]> {
    try {
      this.logger.log('查询用户位置历史', {
        operation: 'getPositionHistory',
        userId: request.userId,
        mapId: request.mapId,
        limit: request.limit,
        timestamp: new Date().toISOString()
      });

      // 从核心服务获取位置历史
      const history = await this.userPositionCore.getPositionHistory(
        request.userId,
        request.limit || LocationPositionService.DEFAULT_QUERY_LIMIT
      );

      // 应用过滤条件
      let filteredHistory = history;

      if (request.timeRange) {
        filteredHistory = filteredHistory.filter(h =>
          h.timestamp >= request.timeRange!.startTime &&
          h.timestamp <= request.timeRange!.endTime
        );
      }

      if (request.mapId) {
        filteredHistory = filteredHistory.filter(h => h.mapId === request.mapId);
      }

      return filteredHistory;

    } catch (error) {
      this.logger.error('获取位置历史失败', {
        operation: 'getPositionHistory',
        request,
        error: error instanceof Error ? error.message : String(error)
      });

      throw error;
    }
  }

  /**
   * 验证位置数据
   *
   * @param position 位置数据
   * @returns 验证结果
   */
  async validatePosition(position: Position): Promise<PositionValidationResult> {
    const errors: string[] = [];
    const warnings: string[] = [];

    try {
      // 1. 基础数据验证
      if (!position.userId) {
        errors.push('用户ID不能为空');
      }

      if (!position.mapId) {
        errors.push('地图ID不能为空');
      }

      if (typeof position.x !== 'number' || typeof position.y !== 'number') {
        errors.push('坐标必须是数字');
      }

      if (!isFinite(position.x) || !isFinite(position.y)) {
        errors.push('坐标必须是有效的数字');
      }

      // 2. 坐标范围验证
      if (position.x > LocationPositionService.MAX_COORDINATE || position.x < LocationPositionService.MIN_COORDINATE ||
          position.y > LocationPositionService.MAX_COORDINATE || position.y < LocationPositionService.MIN_COORDINATE) {
        errors.push('坐标超出允许范围');
      }

      // 3. 时间戳验证
      if (position.timestamp) {
        const now = Date.now();
        const timeDiff = Math.abs(now - position.timestamp);

        if (timeDiff > LocationPositionService.MAX_TIMESTAMP_DIFF) {
          warnings.push('位置时间戳与当前时间差异较大');
        }
      }

      // 4. 地图ID格式验证
      if (position.mapId && position.mapId.length > 50) {
        errors.push('地图ID长度不能超过50个字符');
      }

      // 5. 元数据验证
      if (position.metadata) {
        try {
          JSON.stringify(position.metadata);
        } catch {
          errors.push('位置元数据格式无效');
        }
      }

      return {
        isValid: errors.length === 0,
        errors,
        warnings
      };

    } catch (error) {
      this.logger.error('位置验证失败', {
        operation: 'validatePosition',
        position,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        isValid: false,
        errors: ['位置验证过程中发生错误'],
        warnings
      };
    }
  }

  /**
   * 计算两个位置之间的距离
   *
   * @param pos1 位置1
   * @param pos2 位置2
   * @returns 距离（像素单位）
   */
  calculateDistance(pos1: Position, pos2: Position): number {
    if (pos1.mapId !== pos2.mapId) {
      return Infinity; // 不同地图距离为无穷大
    }

    const dx = pos1.x - pos2.x;
    const dy = pos1.y - pos2.y;

    return Math.sqrt(dx * dx + dy * dy);
  }

  /**
   * 获取指定范围内的用户
   *
   * @param centerPosition 中心位置
   * @param radius 半径
   * @returns 范围内的位置列表
   */
  async getUsersInRange(centerPosition: Position, radius: number): Promise<Position[]> {
    try {
      // 获取同地图的所有用户
      const mapPositions = await this.locationBroadcastCore.getMapPositions(centerPosition.mapId);

      // 过滤范围内的用户
      return mapPositions.filter(pos => {
        if (pos.userId === centerPosition.userId) {
          return false; // 排除自己
        }

        const distance = this.calculateDistance(centerPosition, pos);
        return distance <= radius;
      });

    } catch (error) {
      this.logger.error('获取范围内用户失败', {
        operation: 'getUsersInRange',
        centerPosition,
        radius,
        error: error instanceof Error ? error.message : String(error)
      });

      return [];
    }
  }

  /**
   * 批量更新用户位置
   *
   * @param positions 位置列表
   * @returns 更新结果
   */
  async batchUpdatePositions(positions: Position[]): Promise<{ success: number; failed: number }> {
    let success = 0;
    let failed = 0;

    for (const position of positions) {
      try {
        // 验证位置
        const validation = await this.validatePosition(position);
        if (!validation.isValid) {
          failed++;
          continue;
        }

        // 更新位置
        await this.locationBroadcastCore.setUserPosition(position.userId, position);
        success++;

      } catch (error) {
        this.logger.warn('批量更新位置失败', {
          userId: position.userId,
          error: error instanceof Error ? error.message : String(error)
        });
        failed++;
      }
    }

    this.logger.log('批量位置更新完成', {
      operation: 'batchUpdatePositions',
      total: positions.length,
      success,
      failed
    });

    return { success, failed };
  }

  /**
   * 根据用户ID列表查询位置
   *
   * @param userIds 用户ID列表
   * @returns 位置列表
   * @private
   */
  private async queryPositionsByUserIds(userIds: string[]): Promise<Position[]> {
    const positions: Position[] = [];

    for (const userId of userIds) {
      try {
        const position = await this.locationBroadcastCore.getUserPosition(userId);
        if (position) {
          positions.push(position);
        }
      } catch (error) {
        this.logger.warn('获取用户位置失败', {
          userId,
          error: error instanceof Error ? error.message : String(error)
        });
      }
    }

    return positions;
  }

  /**
   * 应用位置过滤条件
   *
   * @param positions 原始位置列表
   * @param request 查询请求
   * @returns 过滤后的位置列表
   * @private
   */
  private applyPositionFilters(positions: Position[], request: PositionQueryRequest): Position[] {
    let filtered = positions;

    // 时间范围过滤
    if (request.timeRange) {
      filtered = filtered.filter(pos =>
        pos.timestamp >= request.timeRange!.startTime &&
        pos.timestamp <= request.timeRange!.endTime
      );
    }

    // 地图过滤
    if (request.mapId) {
      filtered = filtered.filter(pos => pos.mapId === request.mapId);
    }

    // 用户ID过滤
    if (request.userIds && request.userIds.length > 0) {
      const userIdSet = new Set(request.userIds);
      filtered = filtered.filter(pos => userIdSet.has(pos.userId));
    }

    // 范围过滤
    if (request.range) {
      const { centerX, centerY, radius } = request.range;
      filtered = filtered.filter(pos => {
        const distance = Math.sqrt(
          Math.pow(pos.x - centerX, 2) + Math.pow(pos.y - centerY, 2)
        );
        return distance <= radius;
      });
    }

    return filtered;
  }

  /**
   * 验证位置查询参数
   *
   * @param request 查询请求
   * @private
   */
  private validatePositionQuery(request: PositionQueryRequest): void {
    if (request.userIds && request.userIds.length > 1000) {
      throw new BadRequestException('用户ID列表不能超过1000个');
    }

    if (request.range) {
      const { centerX, centerY, radius } = request.range;

      if (typeof centerX !== 'number' || typeof centerY !== 'number' || typeof radius !== 'number') {
        throw new BadRequestException('范围查询参数必须是数字');
      }

      if (radius < 0 || radius > 10000) {
        throw new BadRequestException('查询半径必须在0-10000之间');
      }
    }

    if (request.pagination) {
      const { offset, limit } = request.pagination;

      if (offset < 0 || limit < 1 || limit > 1000) {
        throw new BadRequestException('分页参数无效');
      }
    }
  }
}