import { describe, expect, it } from 'vitest';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { DrivingReasonCode, type DrivingReasonCodeValue } from './DrivingReasonCode';

describe('DrivingReasonCode', () => {
  describe('create', () => {
    it('should create valid reason codes', () => {
      const validCodes = [
        'DRIVING_FINISH_STRENGTH_GAIN',
        'DRIVING_POSITIONS_GAINED_BONUS',
        'DRIVING_PACE_RELATIVE_GAIN',
        'DRIVING_INCIDENTS_PENALTY',
        'DRIVING_MAJOR_CONTACT_PENALTY',
        'DRIVING_PENALTY_INVOLVEMENT_PENALTY',
        'DRIVING_DNS_PENALTY',
        'DRIVING_DNF_PENALTY',
        'DRIVING_DSQ_PENALTY',
        'DRIVING_AFK_PENALTY',
        'DRIVING_SEASON_ATTENDANCE_BONUS',
      ];

      validCodes.forEach(code => {
        const reasonCode = DrivingReasonCode.create(code);
        expect(reasonCode.value).toBe(code);
      });
    });

    it('should throw error for empty string', () => {
      expect(() => DrivingReasonCode.create('')).toThrow(IdentityDomainValidationError);
      expect(() => DrivingReasonCode.create('   ')).toThrow(IdentityDomainValidationError);
    });

    it('should throw error for invalid reason code', () => {
      expect(() => DrivingReasonCode.create('INVALID_CODE')).toThrow(IdentityDomainValidationError);
      expect(() => DrivingReasonCode.create('driving_finish')).toThrow(IdentityDomainValidationError);
    });

    it('should trim whitespace from valid codes', () => {
      const reasonCode = DrivingReasonCode.create('  DRIVING_FINISH_STRENGTH_GAIN  ');
      expect(reasonCode.value).toBe('DRIVING_FINISH_STRENGTH_GAIN');
    });
  });

  describe('fromValue', () => {
    it('should create from value without validation', () => {
      const reasonCode = DrivingReasonCode.fromValue('DRIVING_FINISH_STRENGTH_GAIN');
      expect(reasonCode.value).toBe('DRIVING_FINISH_STRENGTH_GAIN');
    });
  });

  describe('equals', () => {
    it('should return true for equal codes', () => {
      const code1 = DrivingReasonCode.create('DRIVING_FINISH_STRENGTH_GAIN');
      const code2 = DrivingReasonCode.create('DRIVING_FINISH_STRENGTH_GAIN');
      expect(code1.equals(code2)).toBe(true);
    });

    it('should return false for different codes', () => {
      const code1 = DrivingReasonCode.create('DRIVING_FINISH_STRENGTH_GAIN');
      const code2 = DrivingReasonCode.create('DRIVING_INCIDENTS_PENALTY');
      expect(code1.equals(code2)).toBe(false);
    });
  });

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

  describe('category methods', () => {
    describe('isPerformance', () => {
      it('should return true for performance codes', () => {
        const performanceCodes = [
          'DRIVING_FINISH_STRENGTH_GAIN',
          'DRIVING_POSITIONS_GAINED_BONUS',
          'DRIVING_PACE_RELATIVE_GAIN',
        ];
        performanceCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isPerformance()).toBe(true);
        });
      });

      it('should return false for non-performance codes', () => {
        const nonPerformanceCodes = [
          'DRIVING_INCIDENTS_PENALTY',
          'DRIVING_DNS_PENALTY',
          'DRIVING_SEASON_ATTENDANCE_BONUS',
        ];
        nonPerformanceCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isPerformance()).toBe(false);
        });
      });
    });

    describe('isCleanDriving', () => {
      it('should return true for clean driving codes', () => {
        const cleanDrivingCodes = [
          'DRIVING_INCIDENTS_PENALTY',
          'DRIVING_MAJOR_CONTACT_PENALTY',
          'DRIVING_PENALTY_INVOLVEMENT_PENALTY',
        ];
        cleanDrivingCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isCleanDriving()).toBe(true);
        });
      });

      it('should return false for non-clean driving codes', () => {
        const nonCleanDrivingCodes = [
          'DRIVING_FINISH_STRENGTH_GAIN',
          'DRIVING_DNS_PENALTY',
          'DRIVING_SEASON_ATTENDANCE_BONUS',
        ];
        nonCleanDrivingCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isCleanDriving()).toBe(false);
        });
      });
    });

    describe('isReliability', () => {
      it('should return true for reliability codes', () => {
        const reliabilityCodes = [
          'DRIVING_DNS_PENALTY',
          'DRIVING_DNF_PENALTY',
          'DRIVING_DSQ_PENALTY',
          'DRIVING_AFK_PENALTY',
          'DRIVING_SEASON_ATTENDANCE_BONUS',
        ];
        reliabilityCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isReliability()).toBe(true);
        });
      });

      it('should return false for non-reliability codes', () => {
        const nonReliabilityCodes = [
          'DRIVING_FINISH_STRENGTH_GAIN',
          'DRIVING_INCIDENTS_PENALTY',
        ];
        nonReliabilityCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isReliability()).toBe(false);
        });
      });
    });

    describe('isPenalty', () => {
      it('should return true for penalty codes', () => {
        const penaltyCodes = [
          'DRIVING_INCIDENTS_PENALTY',
          'DRIVING_MAJOR_CONTACT_PENALTY',
          'DRIVING_PENALTY_INVOLVEMENT_PENALTY',
          'DRIVING_DNS_PENALTY',
          'DRIVING_DNF_PENALTY',
          'DRIVING_DSQ_PENALTY',
          'DRIVING_AFK_PENALTY',
        ];
        penaltyCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isPenalty()).toBe(true);
        });
      });

      it('should return false for non-penalty codes', () => {
        const nonPenaltyCodes = [
          'DRIVING_FINISH_STRENGTH_GAIN',
          'DRIVING_POSITIONS_GAINED_BONUS',
          'DRIVING_SEASON_ATTENDANCE_BONUS',
        ];
        nonPenaltyCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isPenalty()).toBe(false);
        });
      });
    });

    describe('isBonus', () => {
      it('should return true for bonus codes', () => {
        const bonusCodes = [
          'DRIVING_POSITIONS_GAINED_BONUS',
          'DRIVING_SEASON_ATTENDANCE_BONUS',
          'DRIVING_FINISH_STRENGTH_GAIN',
          'DRIVING_PACE_RELATIVE_GAIN',
        ];
        bonusCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isBonus()).toBe(true);
        });
      });

      it('should return false for non-bonus codes', () => {
        const nonBonusCodes = [
          'DRIVING_INCIDENTS_PENALTY',
          'DRIVING_DNS_PENALTY',
        ];
        nonBonusCodes.forEach(codeStr => {
          const code = DrivingReasonCode.fromValue(codeStr as DrivingReasonCodeValue);
          expect(code.isBonus()).toBe(false);
        });
      });
    });
  });
});