/**
 * Rate Limit Metrics Tracking
 * 
 * In-memory metrics collection for rate limiting operations.
 * Tracks accepted/rejected requests, patterns, and provides analytics.
 */

export interface RateLimitMetric {
  timestamp: number;
  functionName: string;
  clientIP: string;
  userId?: string;
  allowed: boolean;
  remaining: number;
  retryAfter?: number;
  tier: string;
}

export interface MetricsStats {
  totalRequests: number;
  allowedRequests: number;
  blockedRequests: number;
  blockRate: number;
  uniqueIPs: number;
  uniqueUsers: number;
  topBlockedIPs: Array<{ ip: string; count: number }>;
  topBlockedUsers: Array<{ userId: string; count: number }>;
  tierDistribution: Record<string, number>;
}

// In-memory storage for metrics
const metricsStore: RateLimitMetric[] = [];
const MAX_METRICS = 10000; // Keep last 10k metrics

/**
 * Record a rate limit check result
 */
export function recordRateLimitMetric(metric: RateLimitMetric): void {
  metricsStore.push(metric);
  
  // Trim oldest metrics if we exceed max
  if (metricsStore.length > MAX_METRICS) {
    metricsStore.splice(0, metricsStore.length - MAX_METRICS);
  }
}

/**
 * Get recent metrics
 */
export function getRecentMetrics(limit: number = 100): RateLimitMetric[] {
  return metricsStore.slice(-limit);
}

/**
 * Get aggregated statistics for a time window
 */
export function getMetricsStats(timeWindowMs: number = 60000): MetricsStats {
  const now = Date.now();
  const cutoff = now - timeWindowMs;
  const recentMetrics = metricsStore.filter(m => m.timestamp >= cutoff);

  const allowedRequests = recentMetrics.filter(m => m.allowed).length;
  const blockedRequests = recentMetrics.filter(m => !m.allowed).length;
  const totalRequests = recentMetrics.length;

  // Track unique IPs and users
  const uniqueIPs = new Set(recentMetrics.map(m => m.clientIP)).size;
  const uniqueUsers = new Set(
    recentMetrics.filter(m => m.userId).map(m => m.userId)
  ).size;

  // Find top blocked IPs
  const ipBlockCounts = new Map<string, number>();
  const userBlockCounts = new Map<string, number>();
  const tierCounts = new Map<string, number>();

  recentMetrics.forEach(metric => {
    if (!metric.allowed) {
      ipBlockCounts.set(metric.clientIP, (ipBlockCounts.get(metric.clientIP) || 0) + 1);
      if (metric.userId) {
        userBlockCounts.set(metric.userId, (userBlockCounts.get(metric.userId) || 0) + 1);
      }
    }
    tierCounts.set(metric.tier, (tierCounts.get(metric.tier) || 0) + 1);
  });

  const topBlockedIPs = Array.from(ipBlockCounts.entries())
    .map(([ip, count]) => ({ ip, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 10);

  const topBlockedUsers = Array.from(userBlockCounts.entries())
    .map(([userId, count]) => ({ userId, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 10);

  const tierDistribution = Object.fromEntries(tierCounts);

  return {
    totalRequests,
    allowedRequests,
    blockedRequests,
    blockRate: totalRequests > 0 ? blockedRequests / totalRequests : 0,
    uniqueIPs,
    uniqueUsers,
    topBlockedIPs,
    topBlockedUsers,
    tierDistribution,
  };
}

/**
 * Clear all metrics (useful for testing)
 */
export function clearMetrics(): void {
  metricsStore.length = 0;
}

/**
 * Get metrics for a specific function
 */
export function getFunctionMetrics(functionName: string, limit: number = 100): RateLimitMetric[] {
  return metricsStore
    .filter(m => m.functionName === functionName)
    .slice(-limit);
}

/**
 * Get metrics for a specific user
 */
export function getUserMetrics(userId: string, limit: number = 100): RateLimitMetric[] {
  return metricsStore
    .filter(m => m.userId === userId)
    .slice(-limit);
}

/**
 * Get metrics for a specific IP
 */
export function getIPMetrics(clientIP: string, limit: number = 100): RateLimitMetric[] {
  return metricsStore
    .filter(m => m.clientIP === clientIP)
    .slice(-limit);
}
