import { EventEmitter } from 'events';

export interface Tournament {
  id: string;
  name: string;
  description: string;
  gameId: string;
  startDate: Date;
  endDate: Date;
  status: 'draft' | 'active' | 'completed' | 'cancelled';
  maxPlayers: number;
  entryFee: number;
  prizePool: number;
  rewards: TournamentReward[];
  leaderboard: TournamentEntry[];
  rules: TournamentRules;
  createdAt: Date;
  updatedAt: Date;
}

export interface TournamentEntry {
  playerId: string;
  playerName: string;
  score: number;
  rank: number;
  plays: number;
  joinedAt: Date;
  totalSpent: number;
}

export interface TournamentReward {
  rank: number;
  amount: number;
  percentage: number;
}

export interface TournamentRules {
  scoringMethod: 'highest_score' | 'most_wins' | 'highest_multiplier';
  playLimit: number;
  timeLimit: number;
  allowRebuy: boolean;
  rebuyLimit: number;
}

/**
 * Game Tournament System
 * Manages tournaments, leaderboards, and reward distribution
 */
export class GameTournamentSystem extends EventEmitter {
  private tournaments: Map<string, Tournament> = new Map();
  private playerTournaments: Map<string, Set<string>> = new Map(); // playerId -> tournamentIds
  private tournamentHistory: Tournament[] = [];

  constructor() {
    super();
    console.log('[GameTournament] System initialized');
  }

  /**
   * Create tournament
   */
  createTournament(tournament: Partial<Tournament>): Tournament {
    const newTournament: Tournament = {
      id: `tournament-${Date.now()}`,
      name: tournament.name || 'Untitled Tournament',
      description: tournament.description || '',
      gameId: tournament.gameId || '',
      startDate: tournament.startDate || new Date(),
      endDate: tournament.endDate || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
      status: 'draft',
      maxPlayers: tournament.maxPlayers || 100,
      entryFee: tournament.entryFee || 0,
      prizePool: tournament.prizePool || 1000,
      rewards: tournament.rewards || this.generateDefaultRewards(tournament.prizePool || 1000),
      leaderboard: [],
      rules: tournament.rules || {
        scoringMethod: 'highest_score',
        playLimit: 100,
        timeLimit: 60,
        allowRebuy: false,
        rebuyLimit: 0,
      },
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.tournaments.set(newTournament.id, newTournament);

    this.emit('tournamentCreated', newTournament);
    console.log(`[GameTournament] Tournament created: ${newTournament.id}`);

    return newTournament;
  }

  /**
   * Generate default reward distribution
   */
  private generateDefaultRewards(prizePool: number): TournamentReward[] {
    return [
      { rank: 1, amount: prizePool * 0.5, percentage: 50 },
      { rank: 2, amount: prizePool * 0.3, percentage: 30 },
      { rank: 3, amount: prizePool * 0.2, percentage: 20 },
    ];
  }

  /**
   * Join tournament
   */
  joinTournament(tournamentId: string, playerId: string, playerName: string): boolean {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament) return false;

    if (tournament.leaderboard.length >= tournament.maxPlayers) {
      console.log(`[GameTournament] Tournament ${tournamentId} is full`);
      return false;
    }

    // Check if already joined
    if (tournament.leaderboard.some((e) => e.playerId === playerId)) {
      console.log(`[GameTournament] Player ${playerId} already joined`);
      return false;
    }

    const entry: TournamentEntry = {
      playerId,
      playerName,
      score: 0,
      rank: tournament.leaderboard.length + 1,
      plays: 0,
      joinedAt: new Date(),
      totalSpent: 0,
    };

    tournament.leaderboard.push(entry);
    tournament.updatedAt = new Date();

    if (!this.playerTournaments.has(playerId)) {
      this.playerTournaments.set(playerId, new Set());
    }
    this.playerTournaments.get(playerId)!.add(tournamentId);

    this.emit('playerJoined', { tournamentId, playerId, playerName });
    console.log(`[GameTournament] Player ${playerId} joined tournament ${tournamentId}`);

    return true;
  }

  /**
   * Record tournament play
   */
  recordTournamentPlay(tournamentId: string, playerId: string, score: number, spent: number): boolean {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament) return false;

    const entry = tournament.leaderboard.find((e) => e.playerId === playerId);
    if (!entry) return false;

    entry.score += score;
    entry.plays++;
    entry.totalSpent += spent;
    tournament.updatedAt = new Date();

    // Update ranks
    this.updateLeaderboardRanks(tournamentId);

    this.emit('playRecorded', { tournamentId, playerId, score, spent });

    return true;
  }

  /**
   * Update leaderboard ranks
   */
  private updateLeaderboardRanks(tournamentId: string): void {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament) return;

    // Sort by score
    tournament.leaderboard.sort((a, b) => b.score - a.score);

    // Update ranks
    tournament.leaderboard.forEach((entry, index) => {
      entry.rank = index + 1;
    });
  }

  /**
   * Get tournament
   */
  getTournament(tournamentId: string): Tournament | undefined {
    return this.tournaments.get(tournamentId);
  }

  /**
   * Get active tournaments
   */
  getActiveTournaments(): Tournament[] {
    return Array.from(this.tournaments.values()).filter((t) => t.status === 'active');
  }

  /**
   * Get upcoming tournaments
   */
  getUpcomingTournaments(): Tournament[] {
    const now = new Date();
    return Array.from(this.tournaments.values()).filter((t) => t.status === 'draft' && t.startDate > now);
  }

  /**
   * Start tournament
   */
  startTournament(tournamentId: string): boolean {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament || tournament.status !== 'draft') return false;

    tournament.status = 'active';
    tournament.startDate = new Date();
    tournament.updatedAt = new Date();

    this.emit('tournamentStarted', tournament);
    console.log(`[GameTournament] Tournament started: ${tournamentId}`);

    return true;
  }

  /**
   * End tournament and distribute rewards
   */
  endTournament(tournamentId: string): Map<string, number> {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament) return new Map();

    tournament.status = 'completed';
    tournament.endDate = new Date();
    tournament.updatedAt = new Date();

    // Distribute rewards
    const rewards = new Map<string, number>();

    for (const entry of tournament.leaderboard) {
      const reward = tournament.rewards.find((r) => r.rank === entry.rank);
      if (reward) {
        rewards.set(entry.playerId, reward.amount);
      }
    }

    // Archive tournament
    this.tournamentHistory.push({ ...tournament });

    this.emit('tournamentEnded', { tournamentId, rewards });
    console.log(`[GameTournament] Tournament ended: ${tournamentId}`);

    return rewards;
  }

  /**
   * Get player tournaments
   */
  getPlayerTournaments(playerId: string): Tournament[] {
    const tournamentIds = this.playerTournaments.get(playerId) || new Set();
    return Array.from(tournamentIds)
      .map((id) => this.tournaments.get(id))
      .filter((t) => t !== undefined) as Tournament[];
  }

  /**
   * Get tournament leaderboard
   */
  getTournamentLeaderboard(tournamentId: string): TournamentEntry[] {
    const tournament = this.tournaments.get(tournamentId);
    return tournament ? tournament.leaderboard : [];
  }

  /**
   * Get player rank in tournament
   */
  getPlayerRank(tournamentId: string, playerId: string): number | undefined {
    const tournament = this.tournaments.get(tournamentId);
    const entry = tournament?.leaderboard.find((e) => e.playerId === playerId);
    return entry?.rank;
  }

  /**
   * Get tournament statistics
   */
  getTournamentStats(tournamentId: string) {
    const tournament = this.tournaments.get(tournamentId);
    if (!tournament) return null;

    const totalSpent = tournament.leaderboard.reduce((sum, e) => sum + e.totalSpent, 0);
    const totalPlays = tournament.leaderboard.reduce((sum, e) => sum + e.plays, 0);
    const avgScore = tournament.leaderboard.length > 0 ? tournament.leaderboard.reduce((sum, e) => sum + e.score, 0) / tournament.leaderboard.length : 0;

    return {
      tournamentId,
      playerCount: tournament.leaderboard.length,
      totalSpent,
      totalPlays,
      avgScore,
      prizePool: tournament.prizePool,
      status: tournament.status,
    };
  }

  /**
   * Get all tournaments statistics
   */
  getAllTournamentsStats() {
    const active = this.getActiveTournaments().length;
    const completed = this.tournamentHistory.length;
    const upcoming = this.getUpcomingTournaments().length;

    const totalPrizePool = Array.from(this.tournaments.values()).reduce((sum, t) => sum + t.prizePool, 0);
    const totalPlayers = new Set(Array.from(this.tournaments.values()).flatMap((t) => t.leaderboard.map((e) => e.playerId))).size;

    return {
      activeTournaments: active,
      completedTournaments: completed,
      upcomingTournaments: upcoming,
      totalPrizePool,
      totalPlayers,
    };
  }

  /**
   * Clear all data
   */
  clear(): void {
    this.tournaments.clear();
    this.playerTournaments.clear();
    this.tournamentHistory = [];
    console.log('[GameTournament] System cleared');
  }
}

export const gameTournamentSystem = new GameTournamentSystem();
