import { describe, expect, it } from 'vitest';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { TEAM_DRIVING_REASON_CODES, TeamDrivingReasonCode } from './TeamDrivingReasonCode';

describe('TeamDrivingReasonCode', () => {
  describe('create', () => {
    it('should create valid reason codes', () => {
      for (const code of TEAM_DRIVING_REASON_CODES) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.value).toBe(code);
      }
    });

    it('should throw error for empty string', () => {
      expect(() => TeamDrivingReasonCode.create('')).toThrow(RacingDomainValidationError);
      expect(() => TeamDrivingReasonCode.create('')).toThrow('cannot be empty');
    });

    it('should throw error for whitespace-only string', () => {
      expect(() => TeamDrivingReasonCode.create('   ')).toThrow(RacingDomainValidationError);
    });

    it('should throw error for leading whitespace', () => {
      expect(() => TeamDrivingReasonCode.create(' RACE_PERFORMANCE')).toThrow(RacingDomainValidationError);
      expect(() => TeamDrivingReasonCode.create(' RACE_PERFORMANCE')).toThrow('leading or trailing whitespace');
    });

    it('should throw error for trailing whitespace', () => {
      expect(() => TeamDrivingReasonCode.create('RACE_PERFORMANCE ')).toThrow(RacingDomainValidationError);
      expect(() => TeamDrivingReasonCode.create('RACE_PERFORMANCE ')).toThrow('leading or trailing whitespace');
    });

    it('should throw error for invalid reason code', () => {
      expect(() => TeamDrivingReasonCode.create('INVALID_CODE')).toThrow(RacingDomainValidationError);
      expect(() => TeamDrivingReasonCode.create('INVALID_CODE')).toThrow('Invalid team driving reason code');
    });

    it('should throw error for null/undefined', () => {
      expect(() => TeamDrivingReasonCode.create(null as unknown as string)).toThrow(RacingDomainValidationError);
      expect(() => TeamDrivingReasonCode.create(undefined as unknown as string)).toThrow(RacingDomainValidationError);
    });
  });

  describe('equals', () => {
    it('should return true for same value', () => {
      const code1 = TeamDrivingReasonCode.create('RACE_PERFORMANCE');
      const code2 = TeamDrivingReasonCode.create('RACE_PERFORMANCE');
      expect(code1.equals(code2)).toBe(true);
    });

    it('should return false for different values', () => {
      const code1 = TeamDrivingReasonCode.create('RACE_PERFORMANCE');
      const code2 = TeamDrivingReasonCode.create('RACE_INCIDENTS');
      expect(code1.equals(code2)).toBe(false);
    });
  });

  describe('toString', () => {
    it('should return the string value', () => {
      const code = TeamDrivingReasonCode.create('RACE_PERFORMANCE');
      expect(code.toString()).toBe('RACE_PERFORMANCE');
    });
  });

  describe('isPerformance', () => {
    it('should return true for performance codes', () => {
      const performanceCodes = [
        'RACE_PERFORMANCE',
        'RACE_GAIN_BONUS',
        'RACE_PACE',
        'RACE_QUALIFYING',
        'RACE_CONSISTENCY',
      ];

      for (const code of performanceCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPerformance()).toBe(true);
      }
    });

    it('should return false for non-performance codes', () => {
      const nonPerformanceCodes = [
        'RACE_INCIDENTS',
        'RACE_DNF',
        'RACE_DSQ',
        'RACE_DNS',
        'RACE_AFK',
        'RACE_OVERTAKE',
        'RACE_DEFENSE',
        'RACE_TEAMWORK',
        'RACE_SPORTSMANSHIP',
      ];

      for (const code of nonPerformanceCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPerformance()).toBe(false);
      }
    });
  });

  describe('isPenalty', () => {
    it('should return true for penalty codes', () => {
      const penaltyCodes = [
        'RACE_INCIDENTS',
        'RACE_DNF',
        'RACE_DSQ',
        'RACE_DNS',
        'RACE_AFK',
      ];

      for (const code of penaltyCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPenalty()).toBe(true);
      }
    });

    it('should return false for non-penalty codes', () => {
      const nonPenaltyCodes = [
        'RACE_PERFORMANCE',
        'RACE_GAIN_BONUS',
        'RACE_PACE',
        'RACE_QUALIFYING',
        'RACE_CONSISTENCY',
        'RACE_OVERTAKE',
        'RACE_DEFENSE',
        'RACE_TEAMWORK',
        'RACE_SPORTSMANSHIP',
      ];

      for (const code of nonPenaltyCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPenalty()).toBe(false);
      }
    });
  });

  describe('isPositive', () => {
    it('should return true for positive codes', () => {
      const positiveCodes = [
        'RACE_PERFORMANCE',
        'RACE_GAIN_BONUS',
        'RACE_OVERTAKE',
        'RACE_DEFENSE',
        'RACE_TEAMWORK',
        'RACE_SPORTSMANSHIP',
      ];

      for (const code of positiveCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPositive()).toBe(true);
      }
    });

    it('should return false for non-positive codes', () => {
      const nonPositiveCodes = [
        'RACE_INCIDENTS',
        'RACE_DNF',
        'RACE_DSQ',
        'RACE_DNS',
        'RACE_AFK',
        'RACE_PACE',
        'RACE_QUALIFYING',
        'RACE_CONSISTENCY',
      ];

      for (const code of nonPositiveCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isPositive()).toBe(false);
      }
    });
  });

  describe('isNegative', () => {
    it('should return true for negative codes', () => {
      const negativeCodes = [
        'RACE_INCIDENTS',
        'RACE_DNF',
        'RACE_DSQ',
        'RACE_DNS',
        'RACE_AFK',
      ];

      for (const code of negativeCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isNegative()).toBe(true);
      }
    });

    it('should return false for non-negative codes', () => {
      const nonNegativeCodes = [
        'RACE_PERFORMANCE',
        'RACE_GAIN_BONUS',
        'RACE_PACE',
        'RACE_QUALIFYING',
        'RACE_CONSISTENCY',
        'RACE_OVERTAKE',
        'RACE_DEFENSE',
        'RACE_TEAMWORK',
        'RACE_SPORTSMANSHIP',
      ];

      for (const code of nonNegativeCodes) {
        const reasonCode = TeamDrivingReasonCode.create(code);
        expect(reasonCode.isNegative()).toBe(false);
      }
    });
  });

  describe('props', () => {
    it('should return the correct props object', () => {
      const code = TeamDrivingReasonCode.create('RACE_PERFORMANCE');
      expect(code.props).toEqual({ value: 'RACE_PERFORMANCE' });
    });
  });
});