/**
 * SubscriptionPlan Value Object Tests
 *
 * Unit tests for the SubscriptionPlan value object
 */

import { SubscriptionPlan } from './subscription-plan.vo';

describe('SubscriptionPlan Value Object', () => {
  describe('static factory methods', () => {
    it('should create BRONZE plan via bronze()', () => {
      const plan = SubscriptionPlan.bronze();
      expect(plan.value).toBe('BRONZE');
    });

    it('should create SILVER plan via silver()', () => {
      const plan = SubscriptionPlan.silver();
      expect(plan.value).toBe('SILVER');
    });

    it('should create GOLD plan via gold()', () => {
      const plan = SubscriptionPlan.gold();
      expect(plan.value).toBe('GOLD');
    });

    it('should create PLATINIUM plan via platinium()', () => {
      const plan = SubscriptionPlan.platinium();
      expect(plan.value).toBe('PLATINIUM');
    });

    it('should create BRONZE plan via free() alias', () => {
      const plan = SubscriptionPlan.free();
      expect(plan.value).toBe('BRONZE');
    });

    it('should create SILVER plan via starter() alias', () => {
      const plan = SubscriptionPlan.starter();
      expect(plan.value).toBe('SILVER');
    });

    it('should create GOLD plan via pro() alias', () => {
      const plan = SubscriptionPlan.pro();
      expect(plan.value).toBe('GOLD');
    });

    it('should create PLATINIUM plan via enterprise() alias', () => {
      const plan = SubscriptionPlan.enterprise();
      expect(plan.value).toBe('PLATINIUM');
    });
  });

  describe('create', () => {
    it('should create plan from valid type SILVER', () => {
      const plan = SubscriptionPlan.create('SILVER');
      expect(plan.value).toBe('SILVER');
    });

    it('should create plan from valid type BRONZE', () => {
      const plan = SubscriptionPlan.create('BRONZE');
      expect(plan.value).toBe('BRONZE');
    });

    it('should throw for invalid plan type', () => {
      expect(() => SubscriptionPlan.create('INVALID' as any)).toThrow('Invalid subscription plan');
    });
  });

  describe('fromString', () => {
    it('should create SILVER from lowercase "silver"', () => {
      const plan = SubscriptionPlan.fromString('silver');
      expect(plan.value).toBe('SILVER');
    });

    it('should map legacy "starter" to SILVER', () => {
      const plan = SubscriptionPlan.fromString('starter');
      expect(plan.value).toBe('SILVER');
    });

    it('should map legacy "free" to BRONZE', () => {
      const plan = SubscriptionPlan.fromString('free');
      expect(plan.value).toBe('BRONZE');
    });

    it('should map legacy "pro" to GOLD', () => {
      const plan = SubscriptionPlan.fromString('pro');
      expect(plan.value).toBe('GOLD');
    });

    it('should map legacy "enterprise" to PLATINIUM', () => {
      const plan = SubscriptionPlan.fromString('enterprise');
      expect(plan.value).toBe('PLATINIUM');
    });

    it('should throw for invalid string', () => {
      expect(() => SubscriptionPlan.fromString('invalid')).toThrow('Invalid subscription plan');
    });
  });

  describe('maxLicenses', () => {
    it('should return 1 for BRONZE plan', () => {
      const plan = SubscriptionPlan.bronze();
      expect(plan.maxLicenses).toBe(1);
    });

    it('should return 5 for SILVER plan', () => {
      const plan = SubscriptionPlan.silver();
      expect(plan.maxLicenses).toBe(5);
    });

    it('should return 20 for GOLD plan', () => {
      const plan = SubscriptionPlan.gold();
      expect(plan.maxLicenses).toBe(20);
    });

    it('should return -1 (unlimited) for PLATINIUM plan', () => {
      const plan = SubscriptionPlan.platinium();
      expect(plan.maxLicenses).toBe(-1);
    });
  });

  describe('isUnlimited', () => {
    it('should return false for BRONZE plan', () => {
      expect(SubscriptionPlan.bronze().isUnlimited()).toBe(false);
    });

    it('should return false for SILVER plan', () => {
      expect(SubscriptionPlan.silver().isUnlimited()).toBe(false);
    });

    it('should return false for GOLD plan', () => {
      expect(SubscriptionPlan.gold().isUnlimited()).toBe(false);
    });

    it('should return true for PLATINIUM plan', () => {
      expect(SubscriptionPlan.platinium().isUnlimited()).toBe(true);
    });
  });

  describe('isPaid', () => {
    it('should return false for BRONZE plan', () => {
      expect(SubscriptionPlan.bronze().isPaid()).toBe(false);
    });

    it('should return true for SILVER plan', () => {
      expect(SubscriptionPlan.silver().isPaid()).toBe(true);
    });

    it('should return true for GOLD plan', () => {
      expect(SubscriptionPlan.gold().isPaid()).toBe(true);
    });

    it('should return true for PLATINIUM plan', () => {
      expect(SubscriptionPlan.platinium().isPaid()).toBe(true);
    });
  });

  describe('isFree', () => {
    it('should return true for BRONZE plan', () => {
      expect(SubscriptionPlan.bronze().isFree()).toBe(true);
    });

    it('should return false for SILVER plan', () => {
      expect(SubscriptionPlan.silver().isFree()).toBe(false);
    });
  });

  describe('canAccommodateUsers', () => {
    it('should return true for BRONZE plan with 1 user', () => {
      expect(SubscriptionPlan.bronze().canAccommodateUsers(1)).toBe(true);
    });

    it('should return false for BRONZE plan with 2 users', () => {
      expect(SubscriptionPlan.bronze().canAccommodateUsers(2)).toBe(false);
    });

    it('should return true for SILVER plan with 5 users', () => {
      expect(SubscriptionPlan.silver().canAccommodateUsers(5)).toBe(true);
    });

    it('should always return true for PLATINIUM plan', () => {
      expect(SubscriptionPlan.platinium().canAccommodateUsers(1000)).toBe(true);
    });
  });

  describe('canUpgradeTo', () => {
    it('should allow upgrade from BRONZE to SILVER', () => {
      expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.silver())).toBe(true);
    });

    it('should allow upgrade from BRONZE to GOLD', () => {
      expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
    });

    it('should allow upgrade from BRONZE to PLATINIUM', () => {
      expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.platinium())).toBe(true);
    });

    it('should allow upgrade from SILVER to GOLD', () => {
      expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
    });

    it('should not allow downgrade from SILVER to BRONZE', () => {
      expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.bronze())).toBe(false);
    });

    it('should not allow same plan upgrade', () => {
      expect(SubscriptionPlan.gold().canUpgradeTo(SubscriptionPlan.gold())).toBe(false);
    });
  });

  describe('canDowngradeTo', () => {
    it('should allow downgrade from SILVER to BRONZE when users fit', () => {
      expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 1)).toBe(true);
    });

    it('should not allow downgrade from SILVER to BRONZE when users exceed', () => {
      expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 5)).toBe(false);
    });

    it('should not allow upgrade via canDowngradeTo', () => {
      expect(SubscriptionPlan.bronze().canDowngradeTo(SubscriptionPlan.silver(), 1)).toBe(false);
    });
  });

  describe('plan details', () => {
    it('should return correct name for BRONZE plan', () => {
      expect(SubscriptionPlan.bronze().name).toBe('Bronze');
    });

    it('should return correct name for SILVER plan', () => {
      expect(SubscriptionPlan.silver().name).toBe('Silver');
    });

    it('should return correct prices for SILVER plan', () => {
      const plan = SubscriptionPlan.silver();
      expect(plan.monthlyPriceEur).toBe(249);
      expect(plan.yearlyPriceEur).toBe(2739);
    });

    it('should return features for GOLD plan', () => {
      const plan = SubscriptionPlan.gold();
      expect(plan.features).toContain("Jusqu'à 20 utilisateurs");
      expect(plan.features).toContain('Intégration API');
    });
  });

  describe('getAllPlans', () => {
    it('should return all 4 plans', () => {
      const plans = SubscriptionPlan.getAllPlans();

      expect(plans).toHaveLength(4);
      expect(plans.map(p => p.value)).toEqual(['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM']);
    });
  });

  describe('equals', () => {
    it('should return true for same plan', () => {
      expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.bronze())).toBe(true);
    });

    it('should return false for different plans', () => {
      expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.silver())).toBe(false);
    });
  });

  describe('toString', () => {
    it('should return plan value as string', () => {
      expect(SubscriptionPlan.bronze().toString()).toBe('BRONZE');
      expect(SubscriptionPlan.silver().toString()).toBe('SILVER');
    });
  });
});
