/**
 * Game Statistics Dashboard
 * Tracks and reports game performance metrics
 */

export interface GameStats {
  gameId: string;
  gameName: string;
  totalSpins: number;
  totalWagered: number;
  totalWon: number;
  playerCount: number;
  activePlayerCount: number;
  rtp: number;
  hitFrequency: number;
  averageWin: number;
  averageLoss: number;
  biggestWin: number;
  biggestLoss: number;
  winRate: number;
  lossRate: number;
  cascadeCount?: number;
  freeSpinCount?: number;
  bonusTriggered: number;
  lastUpdated: Date;
}

export interface GamePerformance {
  gameId: string;
  hourly: HourlyStats[];
  daily: DailyStats[];
  weekly: WeeklyStats[];
  monthly: MonthlyStats[];
}

export interface HourlyStats {
  hour: number;
  spins: number;
  wagered: number;
  won: number;
  players: number;
}

export interface DailyStats {
  date: string;
  spins: number;
  wagered: number;
  won: number;
  players: number;
  rtp: number;
}

export interface WeeklyStats {
  week: number;
  year: number;
  spins: number;
  wagered: number;
  won: number;
  players: number;
  rtp: number;
}

export interface MonthlyStats {
  month: number;
  year: number;
  spins: number;
  wagered: number;
  won: number;
  players: number;
  rtp: number;
}

export class GameStatisticsDashboard {
  private gameStats: Map<string, GameStats> = new Map();
  private gamePerformance: Map<string, GamePerformance> = new Map();

  /**
   * Record a spin
   */
  recordSpin(
    gameId: string,
    gameName: string,
    bet: number,
    win: number,
    rtp: number,
    cascadeCount?: number,
    isBonusTriggered?: boolean
  ): void {
    let stats = this.gameStats.get(gameId);

    if (!stats) {
      stats = {
        gameId,
        gameName,
        totalSpins: 0,
        totalWagered: 0,
        totalWon: 0,
        playerCount: 0,
        activePlayerCount: 0,
        rtp,
        hitFrequency: 0,
        averageWin: 0,
        averageLoss: 0,
        biggestWin: 0,
        biggestLoss: 0,
        winRate: 0,
        lossRate: 0,
        cascadeCount: 0,
        freeSpinCount: 0,
        bonusTriggered: 0,
        lastUpdated: new Date(),
      };
    }

    // Update statistics
    stats.totalSpins++;
    stats.totalWagered += bet;
    stats.totalWon += win;
    stats.lastUpdated = new Date();

    // Track cascades
    if (cascadeCount) {
      stats.cascadeCount = (stats.cascadeCount || 0) + cascadeCount;
    }

    // Track bonus triggers
    if (isBonusTriggered) {
      stats.bonusTriggered++;
    }

    // Calculate derived metrics
    this.calculateDerivedMetrics(stats);

    this.gameStats.set(gameId, stats);
  }

  /**
   * Record a player
   */
  recordPlayer(gameId: string): void {
    const stats = this.gameStats.get(gameId);
    if (stats) {
      stats.playerCount++;
      stats.activePlayerCount++;
    }
  }

  /**
   * Calculate derived metrics
   */
  private calculateDerivedMetrics(stats: GameStats): void {
    if (stats.totalSpins === 0) return;

    // Average win/loss
    const winningSpins = Math.floor(stats.totalSpins * 0.25); // Approximate 25% hit rate
    const losingSpins = stats.totalSpins - winningSpins;

    stats.averageWin = winningSpins > 0 ? stats.totalWon / winningSpins : 0;
    stats.averageLoss = losingSpins > 0 ? (stats.totalWagered - stats.totalWon) / losingSpins : 0;

    // Win/loss rate
    stats.winRate = (winningSpins / stats.totalSpins) * 100;
    stats.lossRate = (losingSpins / stats.totalSpins) * 100;

    // Hit frequency
    stats.hitFrequency = stats.winRate;
  }

  /**
   * Get game statistics
   */
  getGameStats(gameId: string): GameStats | null {
    return this.gameStats.get(gameId) || null;
  }

  /**
   * Get all game statistics
   */
  getAllGameStats(): GameStats[] {
    return Array.from(this.gameStats.values());
  }

  /**
   * Get game performance
   */
  getGamePerformance(gameId: string): GamePerformance | null {
    return this.gamePerformance.get(gameId) || null;
  }

  /**
   * Update hourly statistics
   */
  updateHourlyStats(gameId: string, hour: number, spins: number, wagered: number, won: number, players: number): void {
    let performance = this.gamePerformance.get(gameId);

    if (!performance) {
      performance = {
        gameId,
        hourly: [],
        daily: [],
        weekly: [],
        monthly: [],
      };
    }

    // Find or create hourly stat
    let hourlyStats = performance.hourly.find((h) => h.hour === hour);
    if (!hourlyStats) {
      hourlyStats = { hour, spins: 0, wagered: 0, won: 0, players: 0 };
      performance.hourly.push(hourlyStats);
    }

    hourlyStats.spins += spins;
    hourlyStats.wagered += wagered;
    hourlyStats.won += won;
    hourlyStats.players += players;

    this.gamePerformance.set(gameId, performance);
  }

  /**
   * Update daily statistics
   */
  updateDailyStats(gameId: string, date: string, spins: number, wagered: number, won: number, players: number): void {
    let performance = this.gamePerformance.get(gameId);

    if (!performance) {
      performance = {
        gameId,
        hourly: [],
        daily: [],
        weekly: [],
        monthly: [],
      };
    }

    // Find or create daily stat
    let dailyStats = performance.daily.find((d) => d.date === date);
    if (!dailyStats) {
      const rtp = wagered > 0 ? (won / wagered) * 100 : 0;
      dailyStats = { date, spins: 0, wagered: 0, won: 0, players: 0, rtp };
      performance.daily.push(dailyStats);
    }

    dailyStats.spins += spins;
    dailyStats.wagered += wagered;
    dailyStats.won += won;
    dailyStats.players += players;
    dailyStats.rtp = dailyStats.wagered > 0 ? (dailyStats.won / dailyStats.wagered) * 100 : 0;

    this.gamePerformance.set(gameId, performance);
  }

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

  /**
   * Get highest RTP games
   */
  getHighestRTPGames(limit: number = 10): GameStats[] {
    return Array.from(this.gameStats.values())
      .sort((a, b) => b.rtp - a.rtp)
      .slice(0, limit);
  }

  /**
   * Get most played games
   */
  getMostPlayedGames(limit: number = 10): GameStats[] {
    return Array.from(this.gameStats.values())
      .sort((a, b) => b.totalSpins - a.totalSpins)
      .slice(0, limit);
  }

  /**
   * Get game comparison
   */
  getGameComparison(gameIds: string[]): GameStats[] {
    return gameIds
      .map((id) => this.gameStats.get(id))
      .filter((stat) => stat !== undefined) as GameStats[];
  }

  /**
   * Get dashboard summary
   */
  getDashboardSummary(): {
    totalGames: number;
    totalSpins: number;
    totalWagered: number;
    totalWon: number;
    totalPlayers: number;
    averageRTP: number;
    topGame: GameStats | null;
    topPlayer: string | null;
  } {
    const allStats = Array.from(this.gameStats.values());

    const totalSpins = allStats.reduce((sum, s) => sum + s.totalSpins, 0);
    const totalWagered = allStats.reduce((sum, s) => sum + s.totalWagered, 0);
    const totalWon = allStats.reduce((sum, s) => sum + s.totalWon, 0);
    const totalPlayers = allStats.reduce((sum, s) => sum + s.playerCount, 0);
    const averageRTP = allStats.length > 0 ? allStats.reduce((sum, s) => sum + s.rtp, 0) / allStats.length : 0;
    const topGame = allStats.sort((a, b) => b.totalWagered - a.totalWagered)[0] || null;

    return {
      totalGames: allStats.length,
      totalSpins,
      totalWagered,
      totalWon,
      totalPlayers,
      averageRTP,
      topGame,
      topPlayer: null, // Would need player tracking
    };
  }

  /**
   * Export statistics as CSV
   */
  exportAsCSV(): string {
    const stats = Array.from(this.gameStats.values());

    const headers = [
      'Game ID',
      'Game Name',
      'Total Spins',
      'Total Wagered',
      'Total Won',
      'Player Count',
      'RTP',
      'Hit Frequency',
      'Average Win',
      'Average Loss',
      'Biggest Win',
      'Win Rate',
      'Loss Rate',
    ];

    const rows = stats.map((s) => [
      s.gameId,
      s.gameName,
      s.totalSpins,
      s.totalWagered.toFixed(2),
      s.totalWon.toFixed(2),
      s.playerCount,
      s.rtp.toFixed(2),
      s.hitFrequency.toFixed(2),
      s.averageWin.toFixed(2),
      s.averageLoss.toFixed(2),
      s.biggestWin.toFixed(2),
      s.winRate.toFixed(2),
      s.lossRate.toFixed(2),
    ]);

    const csv = [headers, ...rows].map((row) => row.join(',')).join('\n');

    return csv;
  }

  /**
   * Clear statistics (for testing)
   */
  clear(): void {
    this.gameStats.clear();
    this.gamePerformance.clear();
  }
}

// Global dashboard instance
export const gameStatisticsDashboard = new GameStatisticsDashboard();
