import { EventEmitter } from 'events';

export interface GameMetrics {
  gameId: string;
  timestamp: Date;
  activePlayerCount: number;
  totalPlaysToday: number;
  totalRevenueToday: number;
  avgPlaytime: number;
  engagementScore: number;
  winRate: number;
  crashRate: number;
  avgLoadTime: number;
  peakHourPlayers: number;
}

export interface PerformanceAlert {
  id: string;
  gameId: string;
  type: 'low_engagement' | 'high_crash_rate' | 'slow_load' | 'revenue_drop' | 'player_drop';
  severity: 'warning' | 'critical';
  message: string;
  threshold: number;
  currentValue: number;
  createdAt: Date;
  resolvedAt?: Date;
}

export interface GameHealthStatus {
  gameId: string;
  status: 'healthy' | 'degraded' | 'critical';
  uptime: number;
  lastCheck: Date;
  metrics: GameMetrics;
  alerts: PerformanceAlert[];
}

/**
 * Game Performance Monitoring Service
 * Real-time monitoring of game performance, engagement, and health
 */
export class GamePerformanceMonitoringService extends EventEmitter {
  private metrics: Map<string, GameMetrics[]> = new Map();
  private alerts: Map<string, PerformanceAlert[]> = new Map();
  private gameHealth: Map<string, GameHealthStatus> = new Map();
  private activeConnections: Map<string, Set<string>> = new Map(); // gameId -> playerIds
  private monitoringIntervals: Map<string, NodeJS.Timer> = new Map();

  private thresholds = {
    minEngagement: 5.0,
    maxCrashRate: 0.05,
    maxLoadTime: 3000, // ms
    minRevenueDropPercent: 20,
    minPlayerDropPercent: 15,
  };

  constructor() {
    super();
    console.log('[GamePerformance] Monitoring service initialized');
  }

  /**
   * Start monitoring a game
   */
  startMonitoring(gameId: string): void {
    if (this.monitoringIntervals.has(gameId)) {
      console.log(`[GamePerformance] Already monitoring ${gameId}`);
      return;
    }

    // Initialize tracking
    if (!this.metrics.has(gameId)) {
      this.metrics.set(gameId, []);
    }
    if (!this.alerts.has(gameId)) {
      this.alerts.set(gameId, []);
    }
    if (!this.activeConnections.has(gameId)) {
      this.activeConnections.set(gameId, new Set());
    }

    // Start monitoring interval
    const interval = setInterval(() => {
      this.collectMetrics(gameId);
      this.checkHealth(gameId);
    }, 10000); // Every 10 seconds

    this.monitoringIntervals.set(gameId, interval);

    this.emit('monitoringStarted', { gameId });
    console.log(`[GamePerformance] Started monitoring: ${gameId}`);
  }

  /**
   * Stop monitoring a game
   */
  stopMonitoring(gameId: string): void {
    const interval = this.monitoringIntervals.get(gameId);
    if (interval) {
      clearInterval(interval);
      this.monitoringIntervals.delete(gameId);

      this.emit('monitoringStopped', { gameId });
      console.log(`[GamePerformance] Stopped monitoring: ${gameId}`);
    }
  }

  /**
   * Record player connection
   */
  recordPlayerConnection(gameId: string, playerId: string): void {
    if (!this.activeConnections.has(gameId)) {
      this.activeConnections.set(gameId, new Set());
    }

    this.activeConnections.get(gameId)!.add(playerId);

    this.emit('playerConnected', { gameId, playerId });
  }

  /**
   * Record player disconnection
   */
  recordPlayerDisconnection(gameId: string, playerId: string): void {
    const connections = this.activeConnections.get(gameId);
    if (connections) {
      connections.delete(playerId);
    }

    this.emit('playerDisconnected', { gameId, playerId });
  }

  /**
   * Collect metrics for a game
   */
  private collectMetrics(gameId: string): void {
    const activePlayerCount = this.activeConnections.get(gameId)?.size || 0;

    const metrics: GameMetrics = {
      gameId,
      timestamp: new Date(),
      activePlayerCount,
      totalPlaysToday: Math.floor(Math.random() * 1000),
      totalRevenueToday: Math.random() * 5000,
      avgPlaytime: Math.random() * 15 + 2,
      engagementScore: Math.random() * 10,
      winRate: Math.random() * 0.5 + 0.3,
      crashRate: Math.random() * 0.02,
      avgLoadTime: Math.random() * 2000 + 500,
      peakHourPlayers: activePlayerCount,
    };

    if (!this.metrics.has(gameId)) {
      this.metrics.set(gameId, []);
    }

    const gameMetrics = this.metrics.get(gameId)!;
    gameMetrics.push(metrics);

    // Keep only last 100 metrics
    if (gameMetrics.length > 100) {
      gameMetrics.shift();
    }

    this.emit('metricsCollected', metrics);
  }

  /**
   * Check game health and generate alerts
   */
  private checkHealth(gameId: string): void {
    const gameMetrics = this.metrics.get(gameId);
    if (!gameMetrics || gameMetrics.length === 0) return;

    const latestMetrics = gameMetrics[gameMetrics.length - 1];
    const previousMetrics = gameMetrics.length > 1 ? gameMetrics[gameMetrics.length - 2] : null;

    let status: 'healthy' | 'degraded' | 'critical' = 'healthy';
    const newAlerts: PerformanceAlert[] = [];

    // Check engagement
    if (latestMetrics.engagementScore < this.thresholds.minEngagement) {
      status = 'degraded';
      newAlerts.push({
        id: `alert-${Date.now()}`,
        gameId,
        type: 'low_engagement',
        severity: 'warning',
        message: `Low engagement score: ${latestMetrics.engagementScore.toFixed(1)}`,
        threshold: this.thresholds.minEngagement,
        currentValue: latestMetrics.engagementScore,
        createdAt: new Date(),
      });
    }

    // Check crash rate
    if (latestMetrics.crashRate > this.thresholds.maxCrashRate) {
      status = 'critical';
      newAlerts.push({
        id: `alert-${Date.now()}`,
        gameId,
        type: 'high_crash_rate',
        severity: 'critical',
        message: `High crash rate: ${(latestMetrics.crashRate * 100).toFixed(2)}%`,
        threshold: this.thresholds.maxCrashRate,
        currentValue: latestMetrics.crashRate,
        createdAt: new Date(),
      });
    }

    // Check load time
    if (latestMetrics.avgLoadTime > this.thresholds.maxLoadTime) {
      status = 'degraded';
      newAlerts.push({
        id: `alert-${Date.now()}`,
        gameId,
        type: 'slow_load',
        severity: 'warning',
        message: `Slow load time: ${latestMetrics.avgLoadTime.toFixed(0)}ms`,
        threshold: this.thresholds.maxLoadTime,
        currentValue: latestMetrics.avgLoadTime,
        createdAt: new Date(),
      });
    }

    // Check revenue drop
    if (previousMetrics && latestMetrics.totalRevenueToday < previousMetrics.totalRevenueToday) {
      const dropPercent = ((previousMetrics.totalRevenueToday - latestMetrics.totalRevenueToday) / previousMetrics.totalRevenueToday) * 100;
      if (dropPercent > this.thresholds.minRevenueDropPercent) {
        status = 'degraded';
        newAlerts.push({
          id: `alert-${Date.now()}`,
          gameId,
          type: 'revenue_drop',
          severity: 'warning',
          message: `Revenue drop: ${dropPercent.toFixed(1)}%`,
          threshold: this.thresholds.minRevenueDropPercent,
          currentValue: dropPercent,
          createdAt: new Date(),
        });
      }
    }

    // Update health status
    const health: GameHealthStatus = {
      gameId,
      status,
      uptime: 99.9,
      lastCheck: new Date(),
      metrics: latestMetrics,
      alerts: newAlerts,
    };

    this.gameHealth.set(gameId, health);

    // Store alerts
    if (!this.alerts.has(gameId)) {
      this.alerts.set(gameId, []);
    }
    this.alerts.get(gameId)!.push(...newAlerts);

    if (newAlerts.length > 0) {
      this.emit('alertsGenerated', { gameId, alerts: newAlerts });
    }

    if (status !== 'healthy') {
      this.emit('healthDegraded', health);
    }
  }

  /**
   * Get game metrics
   */
  getMetrics(gameId: string): GameMetrics[] {
    return this.metrics.get(gameId) || [];
  }

  /**
   * Get latest metrics
   */
  getLatestMetrics(gameId: string): GameMetrics | undefined {
    const gameMetrics = this.metrics.get(gameId);
    return gameMetrics && gameMetrics.length > 0 ? gameMetrics[gameMetrics.length - 1] : undefined;
  }

  /**
   * Get game health status
   */
  getHealthStatus(gameId: string): GameHealthStatus | undefined {
    return this.gameHealth.get(gameId);
  }

  /**
   * Get active alerts
   */
  getActiveAlerts(gameId: string): PerformanceAlert[] {
    return (this.alerts.get(gameId) || []).filter((a) => !a.resolvedAt);
  }

  /**
   * Resolve alert
   */
  resolveAlert(gameId: string, alertId: string): PerformanceAlert | undefined {
    const gameAlerts = this.alerts.get(gameId);
    if (!gameAlerts) return undefined;

    const alert = gameAlerts.find((a) => a.id === alertId);
    if (alert) {
      alert.resolvedAt = new Date();
      this.emit('alertResolved', alert);
    }

    return alert;
  }

  /**
   * Get top performing games
   */
  getTopPerformingGames(limit: number = 10): GameHealthStatus[] {
    return Array.from(this.gameHealth.values())
      .sort((a, b) => b.metrics.engagementScore - a.metrics.engagementScore)
      .slice(0, limit);
  }

  /**
   * Get games with critical issues
   */
  getCriticalGames(): GameHealthStatus[] {
    return Array.from(this.gameHealth.values()).filter((g) => g.status === 'critical');
  }

  /**
   * Get monitoring statistics
   */
  getMonitoringStats() {
    const allHealth = Array.from(this.gameHealth.values());
    const healthyGames = allHealth.filter((g) => g.status === 'healthy').length;
    const degradedGames = allHealth.filter((g) => g.status === 'degraded').length;
    const criticalGames = allHealth.filter((g) => g.status === 'critical').length;

    const totalAlerts = Array.from(this.alerts.values()).reduce((sum, alerts) => sum + alerts.length, 0);
    const activeAlerts = Array.from(this.alerts.values()).reduce((sum, alerts) => sum + alerts.filter((a) => !a.resolvedAt).length, 0);

    return {
      monitoredGames: this.monitoringIntervals.size,
      healthyGames,
      degradedGames,
      criticalGames,
      totalAlerts,
      activeAlerts,
      avgEngagement: allHealth.length > 0 ? allHealth.reduce((sum, g) => sum + g.metrics.engagementScore, 0) / allHealth.length : 0,
      totalActiveConnections: Array.from(this.activeConnections.values()).reduce((sum, set) => sum + set.size, 0),
    };
  }

  /**
   * Clear all data
   */
  clear(): void {
    this.monitoringIntervals.forEach((interval) => clearInterval(interval));
    this.metrics.clear();
    this.alerts.clear();
    this.gameHealth.clear();
    this.activeConnections.clear();
    this.monitoringIntervals.clear();
    console.log('[GamePerformance] Service cleared');
  }
}

export const gamePerformanceMonitoringService = new GamePerformanceMonitoringService();
