/**
 * VIP Tier System Tests
 */

import { describe, it, expect, beforeEach } from 'vitest';
import {
  getTierFromSpend,
  createVIPStatus,
  getNextTier,
  generatePerks,
  updatePlayerSpend,
  generateMonthlyBonus,
  generateBirthdayBonus,
  generateFreeSpins,
  claimReward,
  getTierComparison,
  getSpendForNextTier,
  VIP_TIERS,
  type PlayerVIPStatus,
  type VIPTier,
} from './vipTierSystem';

describe('VIP Tier System', () => {
  let vipStatus: PlayerVIPStatus;

  beforeEach(() => {
    vipStatus = createVIPStatus(1, 0);
  });

  describe('getTierFromSpend', () => {
    it('should return bronze for 0 spend', () => {
      expect(getTierFromSpend(0)).toBe('bronze');
    });

    it('should return silver for 500+ spend', () => {
      expect(getTierFromSpend(500)).toBe('silver');
    });

    it('should return gold for 1500+ spend', () => {
      expect(getTierFromSpend(1500)).toBe('gold');
    });

    it('should return platinum for 5000+ spend', () => {
      expect(getTierFromSpend(5000)).toBe('platinum');
    });

    it('should return diamond for 10000+ spend', () => {
      expect(getTierFromSpend(10000)).toBe('diamond');
    });

    it('should return elite for 25000+ spend', () => {
      expect(getTierFromSpend(25000)).toBe('elite');
    });
  });

  describe('createVIPStatus', () => {
    it('should create bronze status for new player', () => {
      const status = createVIPStatus(1, 0);

      expect(status.currentTier).toBe('bronze');
      expect(status.totalSpend).toBe(0);
      expect(status.userId).toBe(1);
    });

    it('should create status with correct tier based on spend', () => {
      const status = createVIPStatus(1, 2000);

      expect(status.currentTier).toBe('gold');
    });

    it('should initialize points correctly', () => {
      const status = createVIPStatus(1, 1000);

      expect(status.points).toBe(100);
    });

    it('should generate perks for tier', () => {
      const status = createVIPStatus(1, 0);

      expect(status.perks.length).toBeGreaterThan(0);
    });

    it('should calculate next tier progress', () => {
      const status = createVIPStatus(1, 250);

      expect(status.nextTierProgress).toBeGreaterThan(0);
      expect(status.nextTierProgress).toBeLessThan(100);
    });
  });

  describe('getNextTier', () => {
    it('should return silver for bronze', () => {
      expect(getNextTier('bronze')).toBe('silver');
    });

    it('should return gold for silver', () => {
      expect(getNextTier('silver')).toBe('gold');
    });

    it('should return platinum for gold', () => {
      expect(getNextTier('gold')).toBe('platinum');
    });

    it('should return diamond for platinum', () => {
      expect(getNextTier('platinum')).toBe('diamond');
    });

    it('should return elite for diamond', () => {
      expect(getNextTier('diamond')).toBe('elite');
    });

    it('should return null for elite', () => {
      expect(getNextTier('elite')).toBeNull();
    });
  });

  describe('generatePerks', () => {
    it('should generate perks for bronze tier', () => {
      const tierConfig = VIP_TIERS.bronze;
      const perks = generatePerks(tierConfig);

      expect(perks.length).toBeGreaterThan(0);
      expect(perks.some((p) => p.includes('5%'))).toBe(true);
    });

    it('should include bonus percentage', () => {
      const tierConfig = VIP_TIERS.gold;
      const perks = generatePerks(tierConfig);

      expect(perks.some((p) => p.includes('15%'))).toBe(true);
    });

    it('should include free spins', () => {
      const tierConfig = VIP_TIERS.silver;
      const perks = generatePerks(tierConfig);

      expect(perks.some((p) => p.includes('25'))).toBe(true);
    });

    it('should include priority support for silver+', () => {
      const silverPerks = generatePerks(VIP_TIERS.silver);
      const bronzePerks = generatePerks(VIP_TIERS.bronze);

      expect(silverPerks.some((p) => p.includes('priority'))).toBe(true);
      expect(bronzePerks.some((p) => p.includes('priority'))).toBe(false);
    });
  });

  describe('updatePlayerSpend', () => {
    it('should update total spend', () => {
      const result = updatePlayerSpend(vipStatus, 100);

      expect(vipStatus.totalSpend).toBe(100);
      expect(result.promoted).toBe(false);
    });

    it('should update monthly spend', () => {
      updatePlayerSpend(vipStatus, 100, true);

      expect(vipStatus.monthlySpend).toBe(100);
    });

    it('should promote player on tier up', () => {
      const result = updatePlayerSpend(vipStatus, 500);

      expect(result.promoted).toBe(true);
      expect(result.newTier).toBe('silver');
      expect(result.oldTier).toBe('bronze');
      expect(vipStatus.currentTier).toBe('silver');
    });

    it('should update perks on promotion', () => {
      const oldPerks = vipStatus.perks;
      updatePlayerSpend(vipStatus, 500);

      expect(vipStatus.perks).not.toEqual(oldPerks);
    });

    it('should update points', () => {
      updatePlayerSpend(vipStatus, 100);

      expect(vipStatus.points).toBe(10);
    });

    it('should update next tier progress', () => {
      updatePlayerSpend(vipStatus, 250);

      expect(vipStatus.nextTierProgress).toBeGreaterThan(0);
    });

    it('should handle multiple promotions', () => {
      updatePlayerSpend(vipStatus, 5000);

      expect(vipStatus.currentTier).toBe('platinum');
    });
  });

  describe('generateMonthlyBonus', () => {
    it('should generate bonus for current tier', () => {
      const bonus = generateMonthlyBonus(vipStatus);

      expect(bonus.type).toBe('bonus');
      expect(bonus.amount).toBe(VIP_TIERS.bronze.monthlyBonus);
    });

    it('should set 30-day expiration', () => {
      const bonus = generateMonthlyBonus(vipStatus);
      const expirationMs = bonus.expiresAt.getTime() - Date.now();
      const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;

      expect(Math.abs(expirationMs - thirtyDaysMs)).toBeLessThan(1000);
    });

    it('should mark as unclaimed', () => {
      const bonus = generateMonthlyBonus(vipStatus);

      expect(bonus.claimed).toBe(false);
    });

    it('should increase with tier', () => {
      const bronzeBonus = generateMonthlyBonus(vipStatus);

      vipStatus.currentTier = 'gold';
      const goldBonus = generateMonthlyBonus(vipStatus);

      expect(goldBonus.amount).toBeGreaterThan(bronzeBonus.amount);
    });
  });

  describe('generateBirthdayBonus', () => {
    it('should generate birthday bonus', () => {
      const bonus = generateBirthdayBonus(vipStatus);

      expect(bonus.type).toBe('bonus');
      expect(bonus.amount).toBe(VIP_TIERS.bronze.birthdayBonus);
    });

    it('should set 7-day expiration', () => {
      const bonus = generateBirthdayBonus(vipStatus);
      const expirationMs = bonus.expiresAt.getTime() - Date.now();
      const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;

      expect(Math.abs(expirationMs - sevenDaysMs)).toBeLessThan(1000);
    });
  });

  describe('generateFreeSpins', () => {
    it('should generate free spins reward', () => {
      const reward = generateFreeSpins(vipStatus);

      expect(reward.type).toBe('freespins');
      expect(reward.amount).toBe(VIP_TIERS.bronze.freeSpinsPerMonth);
    });

    it('should set 30-day expiration', () => {
      const reward = generateFreeSpins(vipStatus);
      const expirationMs = reward.expiresAt.getTime() - Date.now();
      const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;

      expect(Math.abs(expirationMs - thirtyDaysMs)).toBeLessThan(1000);
    });
  });

  describe('claimReward', () => {
    it('should claim unclaimed reward', () => {
      const reward = generateMonthlyBonus(vipStatus);
      vipStatus.activeRewards.push(reward);

      const success = claimReward(vipStatus, reward.id);

      expect(success).toBe(true);
      expect(reward.claimed).toBe(true);
      expect(reward.claimedAt).toBeDefined();
    });

    it('should not claim already claimed reward', () => {
      const reward = generateMonthlyBonus(vipStatus);
      reward.claimed = true;
      vipStatus.activeRewards.push(reward);

      const success = claimReward(vipStatus, reward.id);

      expect(success).toBe(false);
    });

    it('should not claim expired reward', () => {
      const reward = generateMonthlyBonus(vipStatus);
      reward.expiresAt = new Date(Date.now() - 1000);
      vipStatus.activeRewards.push(reward);

      const success = claimReward(vipStatus, reward.id);

      expect(success).toBe(false);
    });

    it('should not claim non-existent reward', () => {
      const success = claimReward(vipStatus, 'non-existent');

      expect(success).toBe(false);
    });
  });

  describe('getTierComparison', () => {
    it('should return all tiers', () => {
      const comparison = getTierComparison();

      expect(comparison.length).toBe(6);
    });

    it('should include all tier data', () => {
      const comparison = getTierComparison();

      comparison.forEach((tier) => {
        expect(tier.tier).toBeDefined();
        expect(tier.minSpend).toBeDefined();
        expect(tier.bonusPercentage).toBeDefined();
        expect(tier.cashbackPercentage).toBeDefined();
        expect(tier.freeSpinsPerMonth).toBeDefined();
        expect(tier.monthlyBonus).toBeDefined();
      });
    });

    it('should show increasing benefits', () => {
      const comparison = getTierComparison();

      for (let i = 1; i < comparison.length; i++) {
        expect(comparison[i].bonusPercentage).toBeGreaterThanOrEqual(comparison[i - 1].bonusPercentage);
        expect(comparison[i].monthlyBonus).toBeGreaterThanOrEqual(comparison[i - 1].monthlyBonus);
      }
    });
  });

  describe('getSpendForNextTier', () => {
    it('should return spend needed for next tier', () => {
      const spendNeeded = getSpendForNextTier(0);

      expect(spendNeeded).toBe(500);
    });

    it('should return 0 for elite tier', () => {
      const spendNeeded = getSpendForNextTier(25000);

      expect(spendNeeded).toBe(0);
    });

    it('should decrease as player spends more', () => {
      const spend0 = getSpendForNextTier(0);
      const spend250 = getSpendForNextTier(250);

      expect(spend250).toBeLessThan(spend0);
    });
  });

  describe('VIP Tier Config', () => {
    it('should have all tiers configured', () => {
      const tiers: VIPTier[] = ['bronze', 'silver', 'gold', 'platinum', 'diamond', 'elite'];

      tiers.forEach((tier) => {
        expect(VIP_TIERS[tier]).toBeDefined();
      });
    });

    it('should have increasing min spend', () => {
      const tiers: VIPTier[] = ['bronze', 'silver', 'gold', 'platinum', 'diamond', 'elite'];

      for (let i = 1; i < tiers.length; i++) {
        expect(VIP_TIERS[tiers[i]].minSpend).toBeGreaterThan(VIP_TIERS[tiers[i - 1]].minSpend);
      }
    });

    it('should have valid spend ranges', () => {
      const tiers: VIPTier[] = ['bronze', 'silver', 'gold', 'platinum', 'diamond', 'elite'];

      tiers.forEach((tier) => {
        const config = VIP_TIERS[tier];
        expect(config.minSpend).toBeLessThanOrEqual(config.maxSpend);
      });
    });
  });
});
