import { ExternalRating } from './ExternalRating';
import { GameKey } from './GameKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';

describe('ExternalRating', () => {
  describe('create', () => {
    it('should create valid external rating', () => {
      const gameKey = GameKey.create('iracing');
      const rating = ExternalRating.create(gameKey, 'iRating', 2500);
      
      expect(rating.gameKey.value).toBe('iracing');
      expect(rating.type).toBe('iRating');
      expect(rating.value).toBe(2500);
    });

    it('should create rating with safety rating', () => {
      const gameKey = GameKey.create('iracing');
      const rating = ExternalRating.create(gameKey, 'safetyRating', 2.5);
      
      expect(rating.type).toBe('safetyRating');
      expect(rating.value).toBe(2.5);
    });

    it('should throw for empty type', () => {
      const gameKey = GameKey.create('iracing');
      expect(() => ExternalRating.create(gameKey, '', 2500)).toThrow(IdentityDomainValidationError);
      expect(() => ExternalRating.create(gameKey, '  ', 2500)).toThrow(IdentityDomainValidationError);
    });

    it('should throw for non-numeric value', () => {
      const gameKey = GameKey.create('iracing');
      expect(() => ExternalRating.create(gameKey, 'iRating', '2500' as unknown as number)).toThrow();
      expect(() => ExternalRating.create(gameKey, 'iRating', null as unknown as number)).toThrow();
    });

    it('should trim whitespace from type', () => {
      const gameKey = GameKey.create('iracing');
      const rating = ExternalRating.create(gameKey, '  iRating  ', 2500);
      expect(rating.type).toBe('iRating');
    });
  });

  describe('equals', () => {
    it('should return true for same gameKey, type, and value', () => {
      const gameKey1 = GameKey.create('iracing');
      const gameKey2 = GameKey.create('iracing');
      const rating1 = ExternalRating.create(gameKey1, 'iRating', 2500);
      const rating2 = ExternalRating.create(gameKey2, 'iRating', 2500);
      
      expect(rating1.equals(rating2)).toBe(true);
    });

    it('should return false for different gameKeys', () => {
      const gameKey1 = GameKey.create('iracing');
      const gameKey2 = GameKey.create('acc');
      const rating1 = ExternalRating.create(gameKey1, 'iRating', 2500);
      const rating2 = ExternalRating.create(gameKey2, 'iRating', 2500);
      
      expect(rating1.equals(rating2)).toBe(false);
    });

    it('should return false for different types', () => {
      const gameKey = GameKey.create('iracing');
      const rating1 = ExternalRating.create(gameKey, 'iRating', 2500);
      const rating2 = ExternalRating.create(gameKey, 'safetyRating', 2500);
      
      expect(rating1.equals(rating2)).toBe(false);
    });

    it('should return false for different values', () => {
      const gameKey = GameKey.create('iracing');
      const rating1 = ExternalRating.create(gameKey, 'iRating', 2500);
      const rating2 = ExternalRating.create(gameKey, 'iRating', 2600);
      
      expect(rating1.equals(rating2)).toBe(false);
    });
  });

  describe('props', () => {
    it('should expose props correctly', () => {
      const gameKey = GameKey.create('iracing');
      const rating = ExternalRating.create(gameKey, 'iRating', 2500);
      const props = rating.props;
      
      expect(props.gameKey.value).toBe('iracing');
      expect(props.type).toBe('iRating');
      expect(props.value).toBe(2500);
    });
  });

  describe('toString', () => {
    it('should return string representation', () => {
      const gameKey = GameKey.create('iracing');
      const rating = ExternalRating.create(gameKey, 'iRating', 2500);
      
      expect(rating.toString()).toBe('iracing:iRating=2500');
    });
  });
});