/**
 * Bonus Rounds System Tests
 */

import { describe, it, expect } from 'vitest';
import {
  triggerBonusRound,
  processPickEm,
  processWheelSpin,
  processFreeSpins,
  processMultiplier,
  processMysteryBox,
  calculateBonusPayout,
  getBonusStats,
} from './bonusRoundsSystem';

describe('Bonus Rounds System', () => {
  describe('triggerBonusRound', () => {
    it('should return null for less than 3 scatters', async () => {
      const bonus = await triggerBonusRound(1, 'neon-nights', 2, 100);
      expect(bonus).toBeNull();
    });

    it('should trigger free-spins for 3 scatters', async () => {
      const bonus = await triggerBonusRound(1, 'neon-nights', 3, 100);
      expect(bonus).not.toBeNull();
      if (bonus) {
        expect(bonus.bonusType).toBe('free-spins');
        expect(bonus.freeSpins).toBeGreaterThan(0);
      }
    });

    it('should trigger wheel-spin for 4 scatters', async () => {
      const bonus = await triggerBonusRound(1, 'neon-nights', 4, 100);
      expect(bonus).not.toBeNull();
      if (bonus) {
        expect(bonus.bonusType).toBe('wheel-spin');
        expect(bonus.multiplier).toBeGreaterThan(1);
      }
    });

    it('should trigger pick-em for 5+ scatters', async () => {
      const bonus = await triggerBonusRound(1, 'neon-nights', 5, 100);
      expect(bonus).not.toBeNull();
      if (bonus) {
        expect(bonus.bonusType).toBe('pick-em');
        expect(bonus.multiplier).toBeGreaterThan(1);
      }
    });

    it('should set correct bonus properties', async () => {
      const bonus = await triggerBonusRound(1, 'neon-nights', 4, 100);
      if (bonus) {
        expect(bonus.userId).toBe(1);
        expect(bonus.gameId).toBe('neon-nights');
        expect(bonus.triggerAmount).toBe(100);
        expect(bonus.completed).toBe(false);
        expect(bonus.startedAt).toBeInstanceOf(Date);
        expect(bonus.prize).toBeGreaterThan(0);
      }
    });
  });

  describe('processPickEm', () => {
    it('should generate correct number of prizes', () => {
      const result = processPickEm(9, [0, 4, 8]);
      expect(result.prizes.length).toBe(9);
      expect(result.selectedItems).toEqual([0, 4, 8]);
    });

    it('should calculate total prize correctly', () => {
      const result = processPickEm(9, [0, 1, 2]);
      const expectedTotal = result.prizes[0] + result.prizes[1] + result.prizes[2];
      expect(result.totalPrize).toBe(expectedTotal);
    });

    it('should have valid prize values', () => {
      const result = processPickEm(9, [0, 4, 8]);
      result.prizes.forEach((prize) => {
        expect(prize).toBeGreaterThanOrEqual(10);
        expect(prize).toBeLessThanOrEqual(100);
      });
    });

    it('should have correct type', () => {
      const result = processPickEm(9, [0, 4, 8]);
      expect(result.type).toBe('pick-em');
    });
  });

  describe('processWheelSpin', () => {
    it('should generate correct segment count', () => {
      const result = processWheelSpin(8, 3, 2);
      expect(result.segments).toBe(8);
      expect(result.selectedSegment).toBe(3);
    });

    it('should calculate multiplier based on segment', () => {
      const result = processWheelSpin(8, 3, 2);
      expect(result.multiplier).toBeGreaterThanOrEqual(2);
      expect(result.multiplier).toBeLessThanOrEqual(3);
    });

    it('should have valid prize value', () => {
      const result = processWheelSpin(8, 3, 2);
      expect(result.prize).toBeGreaterThanOrEqual(5);
      expect(result.prize).toBeLessThanOrEqual(200);
    });

    it('should have correct type', () => {
      const result = processWheelSpin(8, 3, 2);
      expect(result.type).toBe('wheel-spin');
    });
  });

  describe('processFreeSpins', () => {
    it('should set correct free spins count', () => {
      const result = processFreeSpins(10, 1.5);
      expect(result.freeSpins).toBe(10);
    });

    it('should apply multiplier bonus', () => {
      const result = processFreeSpins(10, 1.5);
      expect(result.multiplier).toBeGreaterThan(1.5);
    });

    it('should calculate estimated prize', () => {
      const result = processFreeSpins(10, 1.5);
      expect(result.totalPrize).toBeGreaterThan(0);
    });

    it('should have correct type', () => {
      const result = processFreeSpins(10, 1.5);
      expect(result.type).toBe('free-spins');
    });
  });

  describe('processMultiplier', () => {
    it('should double the base multiplier', () => {
      const result = processMultiplier(2, 10, 100);
      expect(result.multiplier).toBe(4);
    });

    it('should calculate prize correctly', () => {
      const result = processMultiplier(2, 10, 100);
      expect(result.prize).toBe(400); // 100 * 4
    });

    it('should set duration', () => {
      const result = processMultiplier(2, 10, 100);
      expect(result.duration).toBe(10);
    });

    it('should have correct type', () => {
      const result = processMultiplier(2, 10, 100);
      expect(result.type).toBe('multiplier');
    });
  });

  describe('processMysteryBox', () => {
    it('should generate correct number of prizes', () => {
      const result = processMysteryBox(6, [0, 2, 4]);
      expect(result.prizes.length).toBe(6);
    });

    it('should calculate total prize correctly', () => {
      const result = processMysteryBox(6, [0, 2, 4]);
      const expectedTotal = result.prizes[0] + result.prizes[2] + result.prizes[4];
      expect(result.totalPrize).toBe(expectedTotal);
    });

    it('should have valid prize values', () => {
      const result = processMysteryBox(6, [0, 2, 4]);
      result.prizes.forEach((prize) => {
        expect(prize).toBeGreaterThanOrEqual(15);
        expect(prize).toBeLessThanOrEqual(150);
      });
    });

    it('should have correct type', () => {
      const result = processMysteryBox(6, [0, 2, 4]);
      expect(result.type).toBe('mystery-box');
    });
  });

  describe('calculateBonusPayout', () => {
    it('should calculate payout for pick-em bonus', () => {
      const bonus = {
        id: 'test',
        userId: 1,
        gameId: 'neon-nights',
        bonusType: 'pick-em' as const,
        triggerAmount: 100,
        multiplier: 3,
        freeSpins: 0,
        prize: 300,
        completed: true,
        startedAt: new Date(),
      };
      const result = { totalPrize: 250 };
      const payout = calculateBonusPayout(bonus, result);
      expect(payout).toBe(250);
    });

    it('should round payout to 2 decimals', () => {
      const bonus = {
        id: 'test',
        userId: 1,
        gameId: 'neon-nights',
        bonusType: 'wheel-spin' as const,
        triggerAmount: 100,
        multiplier: 2,
        freeSpins: 0,
        prize: 200,
        completed: true,
        startedAt: new Date(),
      };
      const result = { prize: 123.456 };
      const payout = calculateBonusPayout(bonus, result);
      expect(payout).toBe(123.46);
    });
  });

  describe('getBonusStats', () => {
    it('should return stats object with required fields', async () => {
      const stats = await getBonusStats(1);
      expect(stats).toHaveProperty('totalBonuses');
      expect(stats).toHaveProperty('completedBonuses');
      expect(stats).toHaveProperty('totalBonusPayout');
      expect(stats).toHaveProperty('averagePayout');
      expect(stats).toHaveProperty('biggestBonus');
      expect(stats).toHaveProperty('bonusByType');
    });

    it('should return zero stats for new player', async () => {
      const stats = await getBonusStats(99999);
      expect(stats.totalBonuses).toBe(0);
      expect(stats.completedBonuses).toBe(0);
      expect(stats.totalBonusPayout).toBe(0);
      expect(stats.averagePayout).toBe(0);
      expect(stats.biggestBonus).toBe(0);
    });

    it('should have bonus type breakdown', async () => {
      const stats = await getBonusStats(1);
      expect(stats.bonusByType).toHaveProperty('pick-em');
      expect(stats.bonusByType).toHaveProperty('wheel-spin');
      expect(stats.bonusByType).toHaveProperty('free-spins');
      expect(stats.bonusByType).toHaveProperty('multiplier');
      expect(stats.bonusByType).toHaveProperty('mystery-box');
    });
  });

  describe('Bonus type validation', () => {
    it('should support all bonus types', () => {
      const types = ['pick-em', 'wheel-spin', 'free-spins', 'multiplier', 'mystery-box'] as const;
      types.forEach((type) => {
        expect(['pick-em', 'wheel-spin', 'free-spins', 'multiplier', 'mystery-box']).toContain(type);
      });
    });
  });
});
