/**
 * Referral Rewards System Tests
 */

import { describe, it, expect } from 'vitest';
import {
  generateReferralCode,
  getReferralTier,
  calculateCommission,
  calculateTierUpgradeBonus,
  getReferralTierRequirements,
} from './referralRewardsSystem';

describe('Referral Rewards System', () => {
  describe('generateReferralCode', () => {
    it('should generate code with REF prefix', () => {
      const code = generateReferralCode(1);
      expect(code).toMatch(/^REF/);
    });

    it('should generate 11 character code', () => {
      const code = generateReferralCode(1);
      expect(code.length).toBe(11); // REF + 8 chars
    });

    it('should contain only alphanumeric characters', () => {
      const code = generateReferralCode(1);
      expect(code).toMatch(/^[A-Z0-9]+$/);
    });

    it('should generate unique codes', () => {
      const code1 = generateReferralCode(1);
      const code2 = generateReferralCode(1);
      // Very likely to be different (1 in 36^8 chance of collision)
      expect(code1).not.toBe(code2);
    });
  });

  describe('getReferralTier', () => {
    it('should return bronze for 0 referrals', () => {
      const tier = getReferralTier(0);
      expect(tier.tier).toBe('bronze');
    });

    it('should return silver for 5 referrals', () => {
      const tier = getReferralTier(5);
      expect(tier.tier).toBe('silver');
    });

    it('should return gold for 10 referrals', () => {
      const tier = getReferralTier(10);
      expect(tier.tier).toBe('gold');
    });

    it('should return platinum for 25 referrals', () => {
      const tier = getReferralTier(25);
      expect(tier.tier).toBe('platinum');
    });

    it('should return diamond for 50+ referrals', () => {
      const tier = getReferralTier(50);
      expect(tier.tier).toBe('diamond');
      
      const tier2 = getReferralTier(100);
      expect(tier2.tier).toBe('diamond');
    });

    it('should have increasing commission rates', () => {
      const tiers = [
        getReferralTier(0),
        getReferralTier(5),
        getReferralTier(10),
        getReferralTier(25),
        getReferralTier(50),
      ];

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

    it('should have increasing bonus multipliers', () => {
      const tiers = [
        getReferralTier(0),
        getReferralTier(5),
        getReferralTier(10),
        getReferralTier(25),
        getReferralTier(50),
      ];

      for (let i = 1; i < tiers.length; i++) {
        expect(tiers[i].bonusMultiplier).toBeGreaterThanOrEqual(tiers[i - 1].bonusMultiplier);
      }
    });

    it('should have increasing monthly bonuses', () => {
      const tiers = [
        getReferralTier(0),
        getReferralTier(5),
        getReferralTier(10),
        getReferralTier(25),
        getReferralTier(50),
      ];

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

  describe('calculateCommission', () => {
    it('should calculate base commission correctly', () => {
      const commission = calculateCommission(0, 100, 'wager');
      // Bronze tier: 2% * 1 multiplier = 2
      expect(commission).toBe(2);
    });

    it('should apply multiplier for deposits', () => {
      const commission = calculateCommission(5, 100, 'deposit');
      // Silver tier: 3% * 1.1 multiplier = 3.3
      expect(commission).toBe(3.3);
    });

    it('should apply multiplier for wagers', () => {
      const commission = calculateCommission(10, 100, 'wager');
      // Gold tier: 4% * 1.2 multiplier = 4.8
      expect(commission).toBe(4.8);
    });

    it('should increase with tier', () => {
      const bronze = calculateCommission(0, 100, 'wager');
      const silver = calculateCommission(5, 100, 'wager');
      const gold = calculateCommission(10, 100, 'wager');
      
      expect(silver).toBeGreaterThan(bronze);
      expect(gold).toBeGreaterThan(silver);
    });

    it('should scale with amount', () => {
      const small = calculateCommission(0, 10, 'wager');
      const large = calculateCommission(0, 100, 'wager');
      
      expect(large).toBe(small * 10);
    });

    it('should return rounded value', () => {
      const commission = calculateCommission(0, 33.33, 'wager');
      expect(commission % 1).toBeLessThanOrEqual(0.01);
    });
  });

  describe('calculateTierUpgradeBonus', () => {
    it('should return 0 for bronze tier', () => {
      const bonus = calculateTierUpgradeBonus('bronze');
      expect(bonus).toBe(0);
    });

    it('should return 100 for silver tier', () => {
      const bonus = calculateTierUpgradeBonus('silver');
      expect(bonus).toBe(100);
    });

    it('should return 500 for gold tier', () => {
      const bonus = calculateTierUpgradeBonus('gold');
      expect(bonus).toBe(500);
    });

    it('should return 2000 for platinum tier', () => {
      const bonus = calculateTierUpgradeBonus('platinum');
      expect(bonus).toBe(2000);
    });

    it('should return 5000 for diamond tier', () => {
      const bonus = calculateTierUpgradeBonus('diamond');
      expect(bonus).toBe(5000);
    });

    it('should have increasing bonuses', () => {
      const bonuses = [
        calculateTierUpgradeBonus('bronze'),
        calculateTierUpgradeBonus('silver'),
        calculateTierUpgradeBonus('gold'),
        calculateTierUpgradeBonus('platinum'),
        calculateTierUpgradeBonus('diamond'),
      ];

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

  describe('getReferralTierRequirements', () => {
    it('should return array of tiers', () => {
      const tiers = getReferralTierRequirements();
      expect(Array.isArray(tiers)).toBe(true);
      expect(tiers.length).toBe(5); // 5 tiers
    });

    it('should have all tier names', () => {
      const tiers = getReferralTierRequirements();
      const tierNames = tiers.map((t) => t.tier);
      expect(tierNames).toContain('bronze');
      expect(tierNames).toContain('silver');
      expect(tierNames).toContain('gold');
      expect(tierNames).toContain('platinum');
      expect(tierNames).toContain('diamond');
    });

    it('should have valid min/max referral ranges', () => {
      const tiers = getReferralTierRequirements();
      tiers.forEach((tier) => {
        expect(tier.minReferrals).toBeLessThanOrEqual(tier.maxReferrals);
        expect(tier.minReferrals).toBeGreaterThanOrEqual(0);
      });
    });

    it('should have valid commission rates', () => {
      const tiers = getReferralTierRequirements();
      tiers.forEach((tier) => {
        expect(tier.commissionRate).toBeGreaterThan(0);
        expect(tier.commissionRate).toBeLessThanOrEqual(10);
      });
    });

    it('should have valid bonus multipliers', () => {
      const tiers = getReferralTierRequirements();
      tiers.forEach((tier) => {
        expect(tier.bonusMultiplier).toBeGreaterThanOrEqual(1);
        expect(tier.bonusMultiplier).toBeLessThanOrEqual(2);
      });
    });

    it('should have valid monthly bonuses', () => {
      const tiers = getReferralTierRequirements();
      tiers.forEach((tier) => {
        expect(tier.monthlyBonus).toBeGreaterThanOrEqual(0);
      });
    });
  });

  describe('Tier progression', () => {
    it('should have continuous referral ranges', () => {
      const tiers = getReferralTierRequirements();
      for (let i = 1; i < tiers.length; i++) {
        expect(tiers[i].minReferrals).toBe(tiers[i - 1].maxReferrals + 1);
      }
    });

    it('should cover all referral counts', () => {
      const tiers = getReferralTierRequirements();
      expect(tiers[0].minReferrals).toBe(0);
      expect(tiers[tiers.length - 1].maxReferrals).toBeGreaterThan(1000);
    });
  });

  describe('Commission calculations', () => {
    it('should handle zero amount', () => {
      const commission = calculateCommission(0, 0, 'wager');
      expect(commission).toBe(0);
    });

    it('should handle large amounts', () => {
      const commission = calculateCommission(0, 1000000, 'wager');
      expect(commission).toBeGreaterThan(0);
      expect(isFinite(commission)).toBe(true);
    });

    it('should handle all transaction types', () => {
      const types = ['signup', 'deposit', 'wager', 'bonus'] as const;
      types.forEach((type) => {
        const commission = calculateCommission(0, 100, type);
        expect(commission).toBeGreaterThanOrEqual(0);
      });
    });
  });
});
