/**
 * 位置更新频率限制中间件
 * 
 * 功能描述：
 * - 限制用户位置更新的频率，防止过度请求
 * - 基于用户ID和时间窗口的限流算法
 * - 支持动态配置和监控统计
 * - 提供优雅的限流响应和错误处理
 * 
 * 职责分离：
 * - 频率控制：实现基于时间窗口的请求限制
 * - 用户隔离：每个用户独立的限流计数
 * - 配置管理：支持动态调整限流参数
 * - 监控统计：记录限流事件和性能指标
 * 
 * 技术实现：
 * - 滑动窗口算法：精确控制请求频率
 * - 内存缓存：高性能的计数器存储
 * - 异步处理：不阻塞正常请求流程
 * - 错误恢复：处理异常情况的降级策略
 * 
 * 最近修改：
 * - 2026-01-08: 代码重构 - 提取魔法数字为常量，优化代码质量 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.1.0
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Injectable, Logger } from '@nestjs/common';

/**
 * 扩展的WebSocket接口
 */
interface ExtendedWebSocket extends WebSocket {
  id: string;
  userId?: string;
}

/**
 * 限流配置接口
 */
interface RateLimitConfig {
  /** 时间窗口（毫秒） */
  windowMs: number;
  /** 窗口内最大请求数 */
  maxRequests: number;
  /** 是否启用限流 */
  enabled: boolean;
  /** 限流消息 */
  message: string;
}

/**
 * 用户限流状态
 */
interface UserRateLimit {
  /** 请求时间戳列表 */
  requests: number[];
  /** 最后更新时间 */
  lastUpdate: number;
  /** 总请求数 */
  totalRequests: number;
  /** 被限流次数 */
  limitedCount: number;
}

/**
 * 限流统计信息
 */
export interface RateLimitStats {
  /** 总请求数 */
  totalRequests: number;
  /** 被限流请求数 */
  limitedRequests: number;
  /** 活跃用户数 */
  activeUsers: number;
  /** 限流率 */
  limitRate: number;
  /** 统计时间戳 */
  timestamp: number;
}

@Injectable()
export class RateLimitMiddleware {
  private readonly logger = new Logger(RateLimitMiddleware.name);
  
  /** 默认时间窗口（毫秒） */
  private static readonly DEFAULT_WINDOW_MS = 1000;
  /** 默认最大请求数 */
  private static readonly DEFAULT_MAX_REQUESTS = 10;
  /** 清理间隔（毫秒） */
  private static readonly CLEANUP_INTERVAL = 60000;
  /** 统计更新间隔（毫秒） */
  private static readonly STATS_UPDATE_INTERVAL = 10000;
  /** 窗口数据保留倍数 */
  private static readonly WINDOW_RETENTION_MULTIPLIER = 10;
  /** 时间转换常量 */
  private static readonly MILLISECONDS_PER_SECOND = 1000;
  
  /** 用户限流状态缓存 */
  private readonly userLimits = new Map<string, UserRateLimit>();
  
  /** 默认配置 */
  private config: RateLimitConfig = {
    windowMs: RateLimitMiddleware.DEFAULT_WINDOW_MS,
    maxRequests: RateLimitMiddleware.DEFAULT_MAX_REQUESTS,
    enabled: true,
    message: '位置更新频率过高，请稍后重试',
  };

  /** 统计信息 */
  private stats: RateLimitStats = {
    totalRequests: 0,
    limitedRequests: 0,
    activeUsers: 0,
    limitRate: 0,
    timestamp: Date.now(),
  };

  constructor() {
    // 定期清理过期的限流记录
    setInterval(() => {
      this.cleanupExpiredRecords();
    }, RateLimitMiddleware.CLEANUP_INTERVAL);

    // 定期更新统计信息
    setInterval(() => {
      this.updateStats();
    }, RateLimitMiddleware.STATS_UPDATE_INTERVAL);
  }

  /**
   * 检查用户是否被限流
   * 
   * @param userId 用户ID
   * @param socketId Socket连接ID
   * @returns 是否允许请求
   */
  checkRateLimit(userId: string, socketId: string): boolean {
    if (!this.config.enabled) {
      return true;
    }

    const now = Date.now();
    this.stats.totalRequests++;

    // 获取或创建用户限流状态
    let userLimit = this.userLimits.get(userId);
    if (!userLimit) {
      userLimit = {
        requests: [],
        lastUpdate: now,
        totalRequests: 0,
        limitedCount: 0,
      };
      this.userLimits.set(userId, userLimit);
    }

    // 清理过期的请求记录
    const windowStart = now - this.config.windowMs;
    userLimit.requests = userLimit.requests.filter(timestamp => timestamp > windowStart);

    // 检查是否超过限制
    if (userLimit.requests.length >= this.config.maxRequests) {
      userLimit.limitedCount++;
      this.stats.limitedRequests++;

      this.logger.warn('用户位置更新被限流', {
        userId,
        socketId,
        requestCount: userLimit.requests.length,
        maxRequests: this.config.maxRequests,
        windowMs: this.config.windowMs,
        timestamp: new Date().toISOString(),
      });

      return false;
    }

    // 记录请求
    userLimit.requests.push(now);
    userLimit.totalRequests++;
    userLimit.lastUpdate = now;

    return true;
  }

  /**
   * 处理限流异常
   * 
   * @param client WebSocket客户端
   * @param userId 用户ID
   */
  handleRateLimit(client: ExtendedWebSocket, userId: string): void {
    const error = {
      type: 'error',
      code: 'RATE_LIMIT_EXCEEDED',
      message: this.config.message,
      details: {
        windowMs: this.config.windowMs,
        maxRequests: this.config.maxRequests,
        retryAfter: Math.ceil(this.config.windowMs / RateLimitMiddleware.MILLISECONDS_PER_SECOND),
      },
      timestamp: Date.now(),
    };

    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify({ event: 'error', data: error }));
    }

    this.logger.debug('发送限流错误响应', {
      userId,
      socketId: client.id,
      error,
    });
  }

  /**
   * 获取用户限流状态
   * 
   * @param userId 用户ID
   * @returns 用户限流状态
   */
  getUserRateLimit(userId: string): UserRateLimit | null {
    return this.userLimits.get(userId) || null;
  }

  /**
   * 获取限流统计信息
   * 
   * @returns 统计信息
   */
  getStats(): RateLimitStats {
    return { ...this.stats };
  }

  /**
   * 更新限流配置
   * 
   * @param newConfig 新配置
   */
  updateConfig(newConfig: Partial<RateLimitConfig>): void {
    this.config = { ...this.config, ...newConfig };
    
    this.logger.log('限流配置已更新', {
      config: this.config,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * 重置用户限流状态
   * 
   * @param userId 用户ID
   */
  resetUserLimit(userId: string): void {
    this.userLimits.delete(userId);
    
    this.logger.debug('重置用户限流状态', {
      userId,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * 清理所有限流记录
   */
  clearAllLimits(): void {
    this.userLimits.clear();
    this.stats = {
      totalRequests: 0,
      limitedRequests: 0,
      activeUsers: 0,
      limitRate: 0,
      timestamp: Date.now(),
    };

    this.logger.log('清理所有限流记录', {
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * 清理过期的限流记录
   * 
   * @private
   */
  private cleanupExpiredRecords(): void {
    const now = Date.now();
    const expireTime = now - (this.config.windowMs * RateLimitMiddleware.WINDOW_RETENTION_MULTIPLIER);
    let cleanedCount = 0;

    for (const [userId, userLimit] of this.userLimits.entries()) {
      if (userLimit.lastUpdate < expireTime) {
        this.userLimits.delete(userId);
        cleanedCount++;
      }
    }

    if (cleanedCount > 0) {
      this.logger.debug('清理过期限流记录', {
        cleanedCount,
        remainingUsers: this.userLimits.size,
        timestamp: new Date().toISOString(),
      });
    }
  }

  /**
   * 更新统计信息
   * 
   * @private
   */
  private updateStats(): void {
    this.stats.activeUsers = this.userLimits.size;
    this.stats.limitRate = this.stats.totalRequests > 0 
      ? (this.stats.limitedRequests / this.stats.totalRequests) * 100 
      : 0;
    this.stats.timestamp = Date.now();
  }
}

/**
 * 位置更新限流装饰器
 * 
 * 使用示例：
 * ```typescript
 * @PositionUpdateRateLimit()
 * @SubscribeMessage('position_update')
 * async handlePositionUpdate(@ConnectedSocket() client: AuthenticatedSocket, @MessageBody() message: PositionUpdateMessage) {
 *   // 处理位置更新
 * }
 * ```
 */
export function PositionUpdateRateLimit() {
  return function (_target: any, _propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value;
    
    descriptor.value = async function (...args: any[]) {
      const client = args[0] as ExtendedWebSocket;
      const rateLimitMiddleware = new RateLimitMiddleware();
      
      if (client.userId) {
        const allowed = rateLimitMiddleware.checkRateLimit(client.userId, client.id);
        
        if (!allowed) {
          rateLimitMiddleware.handleRateLimit(client, client.userId);
          return;
        }
      }
      
      return method.apply(this, args);
    };
  };
}