/**
 * Leaderboard Prize Pool System
 * Manages weekly/monthly prize distributions for top players
 */

export type PrizePoolPeriod = 'weekly' | 'monthly';
export type PrizePoolStatus = 'active' | 'completed' | 'distributed';

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

export interface PrizePool {
  id: string;
  gameId: string;
  period: PrizePoolPeriod;
  status: PrizePoolStatus;
  totalAmount: number;
  distributions: PrizeDistribution[];
  startDate: Date;
  endDate: Date;
  createdAt: Date;
  distributedAt?: Date;
  winners: PrizeWinner[];
}

export interface PrizeWinner {
  userId: number;
  rank: number;
  amount: number;
  claimedAt?: Date;
  transactionId?: string;
}

/**
 * Standard prize distribution percentages
 */
export const STANDARD_DISTRIBUTIONS: Record<PrizePoolPeriod, PrizeDistribution[]> = {
  weekly: [
    { rank: 1, percentage: 30, amount: 0 },
    { rank: 2, percentage: 20, amount: 0 },
    { rank: 3, percentage: 15, amount: 0 },
    { rank: 4, percentage: 12, amount: 0 },
    { rank: 5, percentage: 10, amount: 0 },
    { rank: 6, percentage: 7, amount: 0 },
    { rank: 7, percentage: 4, amount: 0 },
    { rank: 8, percentage: 2, amount: 0 },
    { rank: 9, percentage: 1, amount: 0 },
    { rank: 10, percentage: 1, amount: 0 },
  ],
  monthly: [
    { rank: 1, percentage: 25, amount: 0 },
    { rank: 2, percentage: 18, amount: 0 },
    { rank: 3, percentage: 14, amount: 0 },
    { rank: 4, percentage: 11, amount: 0 },
    { rank: 5, percentage: 9, amount: 0 },
    { rank: 6, percentage: 7, amount: 0 },
    { rank: 7, percentage: 5, amount: 0 },
    { rank: 8, percentage: 4, amount: 0 },
    { rank: 9, percentage: 3, amount: 0 },
    { rank: 10, percentage: 2, amount: 0 },
    { rank: 11, percentage: 1, amount: 0 },
    { rank: 12, percentage: 1, amount: 0 },
  ],
};

/**
 * Create a new prize pool
 */
export function createPrizePool(
  gameId: string,
  period: PrizePoolPeriod,
  totalAmount: number
): PrizePool {
  const now = new Date();
  const startDate = new Date(now);

  let endDate: Date;
  if (period === 'weekly') {
    endDate = new Date(startDate.getTime() + 7 * 24 * 60 * 60 * 1000);
  } else {
    endDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 0, 23, 59, 59);
  }

  const distributions = STANDARD_DISTRIBUTIONS[period].map((dist) => ({
    ...dist,
    amount: (totalAmount * dist.percentage) / 100,
  }));

  return {
    id: `pool_${gameId}_${period}_${Date.now()}`,
    gameId,
    period,
    status: 'active',
    totalAmount,
    distributions,
    startDate,
    endDate,
    createdAt: now,
    winners: [],
  };
}

/**
 * Calculate prize amounts for all distributions
 */
export function calculatePrizeAmounts(pool: PrizePool): PrizeDistribution[] {
  return pool.distributions.map((dist) => ({
    ...dist,
    amount: (pool.totalAmount * dist.percentage) / 100,
  }));
}

/**
 * Distribute prizes to top players
 */
export function distributePrizes(
  pool: PrizePool,
  topPlayers: Array<{ userId: number; score: number }>
): PrizeWinner[] {
  const winners: PrizeWinner[] = [];

  topPlayers.forEach((player, index) => {
    const rank = index + 1;
    const distribution = pool.distributions.find((d) => d.rank === rank);

    if (distribution) {
      winners.push({
        userId: player.userId,
        rank,
        amount: distribution.amount,
      });
    }
  });

  return winners;
}

/**
 * Check if prize pool should be closed
 */
export function shouldClosePrizePool(pool: PrizePool): boolean {
  return new Date() >= pool.endDate;
}

/**
 * Get active prize pools for a game
 */
export function getActivePrizePools(pools: PrizePool[], gameId: string): PrizePool[] {
  return pools.filter((p) => p.gameId === gameId && p.status === 'active' && new Date() < p.endDate);
}

/**
 * Get completed but not distributed prize pools
 */
export function getCompletedPrizePools(pools: PrizePool[], gameId: string): PrizePool[] {
  return pools.filter((p) => p.gameId === gameId && p.status === 'completed' && !p.distributedAt);
}

/**
 * Calculate total prize pool for a game in a period
 */
export function calculateTotalPrizePool(pools: PrizePool[], gameId: string, period: PrizePoolPeriod): number {
  return pools
    .filter((p) => p.gameId === gameId && p.period === period && p.status === 'active')
    .reduce((sum, p) => sum + p.totalAmount, 0);
}

/**
 * Get player's prize pool earnings
 */
export function getPlayerPrizeEarnings(pools: PrizePool[], userId: number): number {
  return pools
    .filter((p) => p.status === 'distributed')
    .reduce((sum, p) => {
      const winner = p.winners.find((w) => w.userId === userId);
      return sum + (winner?.amount || 0);
    }, 0);
}

/**
 * Get top prize winners across all pools
 */
export interface TopWinner {
  userId: number;
  totalEarnings: number;
  winCount: number;
  averageWinAmount: number;
}

export function getTopWinners(pools: PrizePool[], limit: number = 10): TopWinner[] {
  const winnerMap = new Map<number, { earnings: number; count: number }>();

  pools
    .filter((p) => p.status === 'distributed')
    .forEach((pool) => {
      pool.winners.forEach((winner) => {
        const existing = winnerMap.get(winner.userId) || { earnings: 0, count: 0 };
        winnerMap.set(winner.userId, {
          earnings: existing.earnings + winner.amount,
          count: existing.count + 1,
        });
      });
    });

  return Array.from(winnerMap.entries())
    .map(([userId, data]) => ({
      userId,
      totalEarnings: data.earnings,
      winCount: data.count,
      averageWinAmount: data.earnings / data.count,
    }))
    .sort((a, b) => b.totalEarnings - a.totalEarnings)
    .slice(0, limit);
}

/**
 * Prize pool statistics
 */
export interface PrizePoolStats {
  totalPoolsCreated: number;
  totalDistributed: number;
  averagePoolSize: number;
  totalWinnersRewarded: number;
  highestPayout: number;
  lowestPayout: number;
}

export function calculatePrizePoolStats(pools: PrizePool[]): PrizePoolStats {
  const distributedPools = pools.filter((p) => p.status === 'distributed');
  const allWinners = distributedPools.flatMap((p) => p.winners);

  const payouts = allWinners.map((w) => w.amount);
  const totalDistributed = payouts.reduce((sum, p) => sum + p, 0);

  return {
    totalPoolsCreated: pools.length,
    totalDistributed,
    averagePoolSize: pools.length > 0 ? pools.reduce((sum, p) => sum + p.totalAmount, 0) / pools.length : 0,
    totalWinnersRewarded: new Set(allWinners.map((w) => w.userId)).size,
    highestPayout: payouts.length > 0 ? Math.max(...payouts) : 0,
    lowestPayout: payouts.length > 0 ? Math.min(...payouts) : 0,
  };
}

/**
 * Generate prize pool report
 */
export interface PrizePoolReport {
  poolId: string;
  gameId: string;
  period: PrizePoolPeriod;
  totalAmount: number;
  winners: Array<{
    rank: number;
    userId: number;
    amount: number;
    percentage: number;
  }>;
  distributionDate: Date;
}

export function generatePrizePoolReport(pool: PrizePool): PrizePoolReport {
  return {
    poolId: pool.id,
    gameId: pool.gameId,
    period: pool.period,
    totalAmount: pool.totalAmount,
    winners: pool.winners.map((winner) => ({
      rank: winner.rank,
      userId: winner.userId,
      amount: winner.amount,
      percentage: (winner.amount / pool.totalAmount) * 100,
    })),
    distributionDate: pool.distributedAt || new Date(),
  };
}
