import { EventEmitter } from 'events';

interface PlayerGameStats {
  gameId: string;
  totalPlays: number;
  totalWins: number;
  totalScore: number;
  highScore: number;
  winRate: number;
  averageScore: number;
  lastPlayedAt: Date;
  achievements: string[];
}

interface UnifiedPlayerStats {
  userId: string;
  globalLevel: number;
  globalXP: number;
  totalGamesPlayed: number;
  totalGamesWon: number;
  globalWinRate: number;
  totalCoinsEarned: number;
  gameStats: Map<string, PlayerGameStats>;
  unifiedAchievements: string[];
  badges: string[];
  titles: string[];
  createdAt: Date;
  lastUpdatedAt: Date;
}

interface CrossGameAchievement {
  id: string;
  name: string;
  description: string;
  requirement: {
    type: 'global_wins' | 'global_score' | 'games_played' | 'level_reached' | 'multi_game';
    value: number;
    games?: string[];
  };
  reward: {
    xp: number;
    badge?: string;
    title?: string;
  };
}

interface UnifiedLeaderboard {
  rank: number;
  userId: string;
  username: string;
  level: number;
  totalWins: number;
  totalScore: number;
  globalWinRate: number;
  favoriteGame: string;
}

export class CrossGameProgressionSystem extends EventEmitter {
  private playerStats = new Map<string, UnifiedPlayerStats>();
  private crossGameAchievements = new Map<string, CrossGameAchievement>();
  private leaderboard: UnifiedLeaderboard[] = [];

  /**
   * Initialize player unified stats
   */
  initializePlayer(userId: string): UnifiedPlayerStats {
    let stats = this.playerStats.get(userId);

    if (!stats) {
      stats = {
        userId,
        globalLevel: 1,
        globalXP: 0,
        totalGamesPlayed: 0,
        totalGamesWon: 0,
        globalWinRate: 0,
        totalCoinsEarned: 0,
        gameStats: new Map(),
        unifiedAchievements: [],
        badges: [],
        titles: [],
        createdAt: new Date(),
        lastUpdatedAt: new Date(),
      };
      this.playerStats.set(userId, stats);
    }

    return stats;
  }

  /**
   * Update game-specific stats
   */
  updateGameStats(userId: string, gameId: string, stats: {
    plays: number;
    wins: number;
    score: number;
    highScore: number;
  }): UnifiedPlayerStats {
    const playerStats = this.initializePlayer(userId);
    const existingGameStats = playerStats.gameStats.get(gameId);

    const gameStats: PlayerGameStats = {
      gameId,
      totalPlays: (existingGameStats?.totalPlays || 0) + stats.plays,
      totalWins: (existingGameStats?.totalWins || 0) + stats.wins,
      totalScore: (existingGameStats?.totalScore || 0) + stats.score,
      highScore: Math.max(existingGameStats?.highScore || 0, stats.highScore),
      winRate: 0,
      averageScore: 0,
      lastPlayedAt: new Date(),
      achievements: existingGameStats?.achievements || [],
    };

    // Calculate win rate
    gameStats.winRate = gameStats.totalPlays > 0 ? (gameStats.totalWins / gameStats.totalPlays) * 100 : 0;

    // Calculate average score
    gameStats.averageScore = gameStats.totalPlays > 0 ? gameStats.totalScore / gameStats.totalPlays : 0;

    playerStats.gameStats.set(gameId, gameStats);

    // Update unified stats
    this.updateUnifiedStats(userId);

    return playerStats;
  }

  /**
   * Update unified stats from all games
   */
  private updateUnifiedStats(userId: string): void {
    const playerStats = this.playerStats.get(userId);
    if (!playerStats) return;

    let totalPlays = 0;
    let totalWins = 0;
    let totalScore = 0;

    for (const gameStats of playerStats.gameStats.values()) {
      totalPlays += gameStats.totalPlays;
      totalWins += gameStats.totalWins;
      totalScore += gameStats.totalScore;
    }

    playerStats.totalGamesPlayed = totalPlays;
    playerStats.totalGamesWon = totalWins;
    playerStats.globalWinRate = totalPlays > 0 ? (totalWins / totalPlays) * 100 : 0;
    playerStats.totalCoinsEarned = totalScore;
    playerStats.lastUpdatedAt = new Date();

    // Check for level up
    this.checkLevelUp(userId);

    // Check for achievements
    this.checkAchievements(userId);

    // Update leaderboard
    this.updateLeaderboard();

    this.emit('player:stats-updated', { userId });
  }

  /**
   * Check and award level ups
   */
  private checkLevelUp(userId: string): void {
    const playerStats = this.playerStats.get(userId);
    if (!playerStats) return;

    const requiredXPPerLevel = 1000;
    const newLevel = Math.floor(playerStats.globalXP / requiredXPPerLevel) + 1;

    if (newLevel > playerStats.globalLevel) {
      const oldLevel = playerStats.globalLevel;
      playerStats.globalLevel = newLevel;

      this.emit('player:level-up', {
        userId,
        oldLevel,
        newLevel,
        reward: { coins: newLevel * 100 },
      });
    }
  }

  /**
   * Check and award achievements
   */
  private checkAchievements(userId: string): void {
    const playerStats = this.playerStats.get(userId);
    if (!playerStats) return;

    for (const [achievementId, achievement] of this.crossGameAchievements.entries()) {
      if (playerStats.unifiedAchievements.includes(achievementId)) {
        continue; // Already unlocked
      }

      if (this.checkAchievementRequirement(playerStats, achievement)) {
        playerStats.unifiedAchievements.push(achievementId);

        if (achievement.reward.badge) {
          playerStats.badges.push(achievement.reward.badge);
        }
        if (achievement.reward.title) {
          playerStats.titles.push(achievement.reward.title);
        }

        this.emit('achievement:unlocked', {
          userId,
          achievementId,
          achievement,
          reward: achievement.reward,
        });
      }
    }
  }

  /**
   * Check achievement requirement
   */
  private checkAchievementRequirement(
    playerStats: UnifiedPlayerStats,
    achievement: CrossGameAchievement
  ): boolean {
    const req = achievement.requirement;

    switch (req.type) {
      case 'global_wins':
        return playerStats.totalGamesWon >= req.value;

      case 'global_score':
        return playerStats.totalCoinsEarned >= req.value;

      case 'games_played':
        return playerStats.totalGamesPlayed >= req.value;

      case 'level_reached':
        return playerStats.globalLevel >= req.value;

      case 'multi_game':
        if (!req.games) return false;
        let gamesCompleted = 0;
        for (const gameId of req.games) {
          const gameStats = playerStats.gameStats.get(gameId);
          if (gameStats && gameStats.totalWins >= req.value) {
            gamesCompleted++;
          }
        }
        return gamesCompleted === req.games.length;

      default:
        return false;
    }
  }

  /**
   * Add cross-game achievement
   */
  addAchievement(achievement: CrossGameAchievement): void {
    this.crossGameAchievements.set(achievement.id, achievement);
    this.emit('achievement:created', { achievementId: achievement.id });
  }

  /**
   * Get player unified stats
   */
  getPlayerStats(userId: string): UnifiedPlayerStats | null {
    return this.playerStats.get(userId) || null;
  }

  /**
   * Get game-specific stats
   */
  getGameStats(userId: string, gameId: string): PlayerGameStats | null {
    const playerStats = this.playerStats.get(userId);
    return playerStats?.gameStats.get(gameId) || null;
  }

  /**
   * Get unified leaderboard
   */
  getLeaderboard(limit: number = 100): UnifiedLeaderboard[] {
    return this.leaderboard.slice(0, limit);
  }

  /**
   * Get player rank
   */
  getPlayerRank(userId: string): number {
    const index = this.leaderboard.findIndex(entry => entry.userId === userId);
    return index >= 0 ? index + 1 : 0;
  }

  /**
   * Update leaderboard
   */
  private updateLeaderboard(): void {
    const entries: UnifiedLeaderboard[] = [];

    for (const playerStats of this.playerStats.values()) {
      // Get favorite game
      let favoriteGame = 'None';
      let maxPlays = 0;

      for (const gameStats of playerStats.gameStats.values()) {
        if (gameStats.totalPlays > maxPlays) {
          maxPlays = gameStats.totalPlays;
          favoriteGame = gameStats.gameId;
        }
      }

      entries.push({
        rank: 0,
        userId: playerStats.userId,
        username: `Player_${playerStats.userId.substring(0, 8)}`,
        level: playerStats.globalLevel,
        totalWins: playerStats.totalGamesWon,
        totalScore: playerStats.totalCoinsEarned,
        globalWinRate: playerStats.globalWinRate,
        favoriteGame,
      });
    }

    // Sort by level, then by wins, then by score
    entries.sort((a, b) => {
      if (b.level !== a.level) return b.level - a.level;
      if (b.totalWins !== a.totalWins) return b.totalWins - a.totalWins;
      return b.totalScore - a.totalScore;
    });

    // Assign ranks
    entries.forEach((entry, index) => {
      entry.rank = index + 1;
    });

    this.leaderboard = entries;
    this.emit('leaderboard:updated');
  }

  /**
   * Get player comparison
   */
  comparePlayers(userId1: string, userId2: string) {
    const stats1 = this.playerStats.get(userId1);
    const stats2 = this.playerStats.get(userId2);

    if (!stats1 || !stats2) return null;

    return {
      player1: {
        userId: userId1,
        level: stats1.globalLevel,
        totalWins: stats1.totalGamesWon,
        winRate: stats1.globalWinRate,
        totalScore: stats1.totalCoinsEarned,
      },
      player2: {
        userId: userId2,
        level: stats2.globalLevel,
        totalWins: stats2.totalGamesWon,
        winRate: stats2.globalWinRate,
        totalScore: stats2.totalCoinsEarned,
      },
      comparison: {
        levelDifference: stats1.globalLevel - stats2.globalLevel,
        winsDifference: stats1.totalGamesWon - stats2.totalGamesWon,
        winRateDifference: stats1.globalWinRate - stats2.globalWinRate,
        scoreDifference: stats1.totalCoinsEarned - stats2.totalCoinsEarned,
      },
    };
  }

  /**
   * Get player achievements
   */
  getPlayerAchievements(userId: string): CrossGameAchievement[] {
    const playerStats = this.playerStats.get(userId);
    if (!playerStats) return [];

    return playerStats.unifiedAchievements
      .map(id => this.crossGameAchievements.get(id))
      .filter((a): a is CrossGameAchievement => a !== undefined);
  }

  /**
   * Export player stats
   */
  exportPlayerStats(userId: string) {
    const playerStats = this.playerStats.get(userId);
    if (!playerStats) return null;

    return {
      userId,
      globalStats: {
        level: playerStats.globalLevel,
        xp: playerStats.globalXP,
        totalPlays: playerStats.totalGamesPlayed,
        totalWins: playerStats.totalGamesWon,
        winRate: playerStats.globalWinRate,
        totalCoinsEarned: playerStats.totalCoinsEarned,
      },
      gameStats: Array.from(playerStats.gameStats.values()),
      achievements: this.getPlayerAchievements(userId),
      badges: playerStats.badges,
      titles: playerStats.titles,
      rank: this.getPlayerRank(userId),
    };
  }
}

export const crossGameProgressionSystem = new CrossGameProgressionSystem();
