/**
 * Tournament System
 * Manages tournaments with leaderboards, scoring, and prize distribution
 */

export type TournamentStatus = 'upcoming' | 'active' | 'ended' | 'archived';
export type TournamentType = 'weekly' | 'monthly' | 'special' | 'vip';
export type ScoringMethod = 'highest_score' | 'most_spins' | 'biggest_win' | 'most_bonuses';

export interface Tournament {
  id: string;
  name: string;
  description: string;
  type: TournamentType;
  status: TournamentStatus;
  gameIds: string[];
  scoringMethod: ScoringMethod;
  prizePool: number;
  startDate: Date;
  endDate: Date;
  createdAt: Date;
  participants: number;
  leaderboard: TournamentEntry[];
  prizes: TournamentPrize[];
  rules: TournamentRules;
}

export interface TournamentEntry {
  userId: number;
  username: string;
  score: number;
  rank: number;
  entries: number;
  joinedAt: Date;
  lastUpdatedAt: Date;
  prize?: number;
}

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

export interface TournamentRules {
  minBet?: number;
  maxBet?: number;
  allowedGames: string[];
  bonusMultiplier: number;
  tiebreaker: 'earliest_score' | 'most_entries' | 'highest_single_win';
  requiresVIP: boolean;
  vipTierRequired?: string;
  maxParticipants?: number;
}

/**
 * Create a new tournament
 */
export function createTournament(
  name: string,
  type: TournamentType,
  gameIds: string[],
  scoringMethod: ScoringMethod,
  prizePool: number,
  startDate: Date,
  endDate: Date,
  rules: TournamentRules
): Tournament {
  const prizes = generatePrizeDistribution(prizePool);

  return {
    id: `tournament_${type}_${Date.now()}`,
    name,
    description: `${name} Tournament - ${type}`,
    type,
    status: 'upcoming',
    gameIds,
    scoringMethod,
    prizePool,
    startDate,
    endDate,
    createdAt: new Date(),
    participants: 0,
    leaderboard: [],
    prizes,
    rules,
  };
}

/**
 * Generate prize distribution
 */
export function generatePrizeDistribution(prizePool: number): TournamentPrize[] {
  const distributions = [
    { rank: 1, percentage: 30 },
    { rank: 2, percentage: 20 },
    { rank: 3, percentage: 15 },
    { rank: 4, percentage: 12 },
    { rank: 5, percentage: 10 },
    { rank: 6, percentage: 7 },
    { rank: 7, percentage: 4 },
    { rank: 8, percentage: 2 },
    { rank: 9, percentage: 1 },
    { rank: 10, percentage: 1 },
  ];

  return distributions.map((dist) => ({
    rank: dist.rank,
    percentage: dist.percentage,
    amount: (prizePool * dist.percentage) / 100,
  }));
}

/**
 * Register player in tournament
 */
export function registerPlayerInTournament(
  tournament: Tournament,
  userId: number,
  username: string
): boolean {
  if (tournament.status !== 'active' && tournament.status !== 'upcoming') {
    return false;
  }

  if (tournament.rules.maxParticipants && tournament.participants >= tournament.rules.maxParticipants) {
    return false;
  }

  const existingEntry = tournament.leaderboard.find((e) => e.userId === userId);
  if (existingEntry) {
    return false;
  }

  tournament.leaderboard.push({
    userId,
    username,
    score: 0,
    rank: tournament.leaderboard.length + 1,
    entries: 0,
    joinedAt: new Date(),
    lastUpdatedAt: new Date(),
  });

  tournament.participants++;
  return true;
}

/**
 * Update player score
 */
export function updatePlayerScore(
  tournament: Tournament,
  userId: number,
  scoreValue: number,
  multiplier: number = 1
): boolean {
  const entry = tournament.leaderboard.find((e) => e.userId === userId);

  if (!entry) {
    return false;
  }

  const adjustedScore = scoreValue * multiplier;
  entry.score += adjustedScore;
  entry.entries++;
  entry.lastUpdatedAt = new Date();

  // Re-rank leaderboard
  rankLeaderboard(tournament);

  return true;
}

/**
 * Rank leaderboard entries
 */
export function rankLeaderboard(tournament: Tournament): void {
  tournament.leaderboard.sort((a, b) => {
    if (b.score !== a.score) {
      return b.score - a.score;
    }

    // Apply tiebreaker
    switch (tournament.rules.tiebreaker) {
      case 'earliest_score':
        return a.lastUpdatedAt.getTime() - b.lastUpdatedAt.getTime();
      case 'most_entries':
        return b.entries - a.entries;
      case 'highest_single_win':
        return 0; // Would need additional tracking
      default:
        return 0;
    }
  });

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

/**
 * Check if tournament should end
 */
export function shouldEndTournament(tournament: Tournament): boolean {
  return new Date() >= tournament.endDate;
}

/**
 * End tournament and distribute prizes
 */
export function endTournament(tournament: Tournament): void {
  if (tournament.status === 'ended' || tournament.status === 'archived') {
    return;
  }

  tournament.status = 'ended';

  // Distribute prizes
  tournament.leaderboard.forEach((entry) => {
    const prize = tournament.prizes.find((p) => p.rank === entry.rank);
    if (prize) {
      entry.prize = prize.amount;
    }
  });
}

/**
 * Get tournament leaderboard
 */
export function getTournamentLeaderboard(tournament: Tournament, limit: number = 100): TournamentEntry[] {
  return tournament.leaderboard.slice(0, limit);
}

/**
 * Get player tournament position
 */
export function getPlayerPosition(tournament: Tournament, userId: number): TournamentEntry | null {
  return tournament.leaderboard.find((e) => e.userId === userId) || null;
}

/**
 * Get top performers
 */
export function getTopPerformers(tournament: Tournament, limit: number = 10): TournamentEntry[] {
  return tournament.leaderboard.slice(0, limit);
}

/**
 * Calculate tournament statistics
 */
export interface TournamentStats {
  totalParticipants: number;
  totalScoreSum: number;
  averageScore: number;
  highestScore: number;
  lowestScore: number;
  medianScore: number;
  totalPrizeDistributed: number;
}

export function calculateTournamentStats(tournament: Tournament): TournamentStats {
  const scores = tournament.leaderboard.map((e) => e.score);

  const stats: TournamentStats = {
    totalParticipants: tournament.leaderboard.length,
    totalScoreSum: scores.reduce((sum, s) => sum + s, 0),
    averageScore: scores.length > 0 ? scores.reduce((sum, s) => sum + s, 0) / scores.length : 0,
    highestScore: scores.length > 0 ? Math.max(...scores) : 0,
    lowestScore: scores.length > 0 ? Math.min(...scores) : 0,
    medianScore: calculateMedian(scores),
    totalPrizeDistributed: tournament.leaderboard.reduce((sum, e) => sum + (e.prize || 0), 0),
  };

  return stats;
}

/**
 * Calculate median
 */
function calculateMedian(scores: number[]): number {
  if (scores.length === 0) return 0;

  const sorted = [...scores].sort((a, b) => a - b);
  const mid = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 0) {
    return (sorted[mid - 1] + sorted[mid]) / 2;
  }

  return sorted[mid];
}

/**
 * Get tournament winners
 */
export function getTournamentWinners(tournament: Tournament, limit: number = 10): TournamentEntry[] {
  return tournament.leaderboard
    .filter((e) => e.prize && e.prize > 0)
    .slice(0, limit);
}

/**
 * Check if player is eligible for tournament
 */
export function isPlayerEligible(tournament: Tournament, userVIPTier?: string): boolean {
  if (!tournament.rules.requiresVIP) {
    return true;
  }

  if (!userVIPTier) {
    return false;
  }

  if (tournament.rules.vipTierRequired) {
    const tiers = ['bronze', 'silver', 'gold', 'platinum', 'diamond', 'elite'];
    const requiredIndex = tiers.indexOf(tournament.rules.vipTierRequired);
    const userIndex = tiers.indexOf(userVIPTier);

    return userIndex >= requiredIndex;
  }

  return true;
}

/**
 * Generate tournament report
 */
export interface TournamentReport {
  tournamentId: string;
  tournamentName: string;
  type: TournamentType;
  status: TournamentStatus;
  totalParticipants: number;
  totalPrizePool: number;
  totalDistributed: number;
  winners: Array<{
    rank: number;
    username: string;
    score: number;
    prize: number;
  }>;
  statistics: TournamentStats;
}

export function generateTournamentReport(tournament: Tournament): TournamentReport {
  const stats = calculateTournamentStats(tournament);
  const winners = getTournamentWinners(tournament, 10);

  return {
    tournamentId: tournament.id,
    tournamentName: tournament.name,
    type: tournament.type,
    status: tournament.status,
    totalParticipants: tournament.participants,
    totalPrizePool: tournament.prizePool,
    totalDistributed: stats.totalPrizeDistributed,
    winners: winners.map((w) => ({
      rank: w.rank,
      username: w.username,
      score: w.score,
      prize: w.prize || 0,
    })),
    statistics: stats,
  };
}

/**
 * Get active tournaments
 */
export function getActiveTournaments(tournaments: Tournament[]): Tournament[] {
  return tournaments.filter((t) => t.status === 'active');
}

/**
 * Get upcoming tournaments
 */
export function getUpcomingTournaments(tournaments: Tournament[]): Tournament[] {
  return tournaments.filter((t) => t.status === 'upcoming').sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
}

/**
 * Get completed tournaments
 */
export function getCompletedTournaments(tournaments: Tournament[]): Tournament[] {
  return tournaments.filter((t) => t.status === 'ended' || t.status === 'archived');
}
