/**
 * Game Leaderboards System Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
  getGameLeaderboard,
  getPlayerRank,
  getTopWinnersAllGames,
  getLeaderboardStats,
  type LeaderboardPeriod,
} from './gameLeaderboardsSystem';

describe('Game Leaderboards System', () => {
  describe('getGameLeaderboard', () => {
    it('should return empty array when no transactions exist', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      expect(Array.isArray(entries)).toBe(true);
    });

    it('should respect limit parameter', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 10);
      expect(entries.length).toBeLessThanOrEqual(10);
    });

    it('should sort entries by total winnings descending', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'alltime', 100);
      if (entries.length > 1) {
        for (let i = 1; i < entries.length; i++) {
          expect(entries[i - 1].totalWinnings).toBeGreaterThanOrEqual(entries[i].totalWinnings);
        }
      }
    });

    it('should assign correct ranks', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      entries.forEach((entry, index) => {
        expect(entry.rank).toBe(index + 1);
      });
    });

    it('should calculate win rate correctly', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      entries.forEach((entry) => {
        if (entry.totalSpins > 0) {
          expect(entry.winRate).toBeGreaterThanOrEqual(0);
          expect(entry.winRate).toBeLessThanOrEqual(100);
        }
      });
    });

    it('should support different time periods', async () => {
      const periods: LeaderboardPeriod[] = ['daily', 'weekly', 'monthly', 'alltime'];
      
      for (const period of periods) {
        const entries = await getGameLeaderboard('neon-nights', period, 100);
        expect(Array.isArray(entries)).toBe(true);
      }
    });
  });

  describe('getPlayerRank', () => {
    it('should return rank 0 for non-existent player', async () => {
      const result = await getPlayerRank(99999, 'neon-nights', 'weekly');
      expect(result.rank).toBe(0);
      expect(result.entry).toBeNull();
    });

    it('should return valid rank structure', async () => {
      const result = await getPlayerRank(1, 'neon-nights', 'weekly');
      expect(result).toHaveProperty('rank');
      expect(result).toHaveProperty('entry');
      expect(typeof result.rank).toBe('number');
    });
  });

  describe('getTopWinnersAllGames', () => {
    it('should return array of entries', async () => {
      const result = await getTopWinnersAllGames('weekly', 100);
      expect(Array.isArray(result)).toBe(true);
    });

    it('should respect limit parameter', async () => {
      const result = await getTopWinnersAllGames('weekly', 10);
      expect(result.length).toBeLessThanOrEqual(10);
    });

    it('should sort by total winnings descending', async () => {
      const result = await getTopWinnersAllGames('alltime', 100);
      if (result.length > 1) {
        for (let i = 1; i < result.length; i++) {
          expect(result[i - 1].totalWinnings).toBeGreaterThanOrEqual(result[i].totalWinnings);
        }
      }
    });

    it('should have gameId as all-games', async () => {
      const result = await getTopWinnersAllGames('weekly', 100);
      result.forEach((entry) => {
        expect(entry.gameId).toBe('all-games');
      });
    });
  });

  describe('getLeaderboardStats', () => {
    it('should return stats object with required fields', async () => {
      const stats = await getLeaderboardStats('neon-nights', 'weekly');
      expect(stats).toHaveProperty('totalPlayers');
      expect(stats).toHaveProperty('totalWinnings');
      expect(stats).toHaveProperty('averageWinnings');
      expect(stats).toHaveProperty('topWinner');
    });

    it('should return zero stats for empty leaderboard', async () => {
      const stats = await getLeaderboardStats('neon-nights', 'daily');
      if (stats.totalPlayers === 0) {
        expect(stats.totalWinnings).toBe(0);
        expect(stats.averageWinnings).toBe(0);
        expect(stats.topWinner).toBeNull();
      }
    });

    it('should calculate average correctly', async () => {
      const stats = await getLeaderboardStats('neon-nights', 'alltime');
      if (stats.totalPlayers > 0) {
        const expectedAverage = stats.totalWinnings / stats.totalPlayers;
        expect(stats.averageWinnings).toBe(expectedAverage);
      }
    });

    it('should have topWinner as first entry', async () => {
      const stats = await getLeaderboardStats('neon-nights', 'weekly');
      if (stats.topWinner) {
        expect(stats.topWinner.rank).toBe(1);
      }
    });
  });

  describe('Time period calculations', () => {
    it('should handle daily period', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'daily', 100);
      expect(Array.isArray(entries)).toBe(true);
    });

    it('should handle weekly period', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      expect(Array.isArray(entries)).toBe(true);
    });

    it('should handle monthly period', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'monthly', 100);
      expect(Array.isArray(entries)).toBe(true);
    });

    it('should handle alltime period', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'alltime', 100);
      expect(Array.isArray(entries)).toBe(true);
    });
  });

  describe('Entry data validation', () => {
    it('should have valid entry structure', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      entries.forEach((entry) => {
        expect(entry).toHaveProperty('rank');
        expect(entry).toHaveProperty('userId');
        expect(entry).toHaveProperty('userName');
        expect(entry).toHaveProperty('gameId');
        expect(entry).toHaveProperty('totalWinnings');
        expect(entry).toHaveProperty('totalSpins');
        expect(entry).toHaveProperty('winRate');
        expect(entry).toHaveProperty('biggestWin');
        expect(entry).toHaveProperty('averageWin');
      });
    });

    it('should have non-negative numeric values', async () => {
      const entries = await getGameLeaderboard('neon-nights', 'weekly', 100);
      entries.forEach((entry) => {
        expect(entry.totalWinnings).toBeGreaterThanOrEqual(0);
        expect(entry.totalSpins).toBeGreaterThanOrEqual(0);
        expect(entry.winRate).toBeGreaterThanOrEqual(0);
        expect(entry.biggestWin).toBeGreaterThanOrEqual(0);
        expect(entry.averageWin).toBeGreaterThanOrEqual(0);
      });
    });
  });
});
