import type { ValueObject } from '@core/shared/domain/ValueObject'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; export interface TeamDrivingReasonCodeProps { value: string; } /** * Valid reason codes for team driving rating events */ export const TEAM_DRIVING_REASON_CODES = [ 'RACE_PERFORMANCE', 'RACE_GAIN_BONUS', 'RACE_INCIDENTS', 'RACE_DNF', 'RACE_DSQ', 'RACE_DNS', 'RACE_AFK', 'RACE_PACE', 'RACE_DEFENSE', 'RACE_OVERTAKE', 'RACE_QUALIFYING', 'RACE_CONSISTENCY', 'RACE_TEAMWORK', 'RACE_SPORTSMANSHIP', ] as const; export type TeamDrivingReasonCodeValue = (typeof TEAM_DRIVING_REASON_CODES)[number]; /** * Value object representing a team driving reason code */ export class TeamDrivingReasonCode implements ValueObject { readonly value: TeamDrivingReasonCodeValue; private constructor(value: TeamDrivingReasonCodeValue) { this.value = value; } static create(value: string): TeamDrivingReasonCode { if (!value || value.trim().length === 0) { throw new RacingDomainValidationError('Team driving reason code cannot be empty'); } // Strict validation: no leading/trailing whitespace allowed if (value !== value.trim()) { throw new RacingDomainValidationError( `Team driving reason code cannot have leading or trailing whitespace: "${value}"` ); } if (!TEAM_DRIVING_REASON_CODES.includes(value as TeamDrivingReasonCodeValue)) { throw new RacingDomainValidationError( `Invalid team driving reason code: ${value}. Valid options: ${TEAM_DRIVING_REASON_CODES.join(', ')}` ); } return new TeamDrivingReasonCode(value as TeamDrivingReasonCodeValue); } get props(): TeamDrivingReasonCodeProps { return { value: this.value }; } equals(other: ValueObject): boolean { return this.value === other.props.value; } toString(): string { return this.value; } /** * Check if this is a performance-related reason */ isPerformance(): boolean { return ['RACE_PERFORMANCE', 'RACE_GAIN_BONUS', 'RACE_PACE', 'RACE_QUALIFYING', 'RACE_CONSISTENCY'].includes(this.value); } /** * Check if this is a penalty-related reason */ isPenalty(): boolean { return ['RACE_INCIDENTS', 'RACE_DNF', 'RACE_DSQ', 'RACE_DNS', 'RACE_AFK'].includes(this.value); } /** * Check if this is a positive reason */ isPositive(): boolean { return ['RACE_PERFORMANCE', 'RACE_GAIN_BONUS', 'RACE_OVERTAKE', 'RACE_DEFENSE', 'RACE_TEAMWORK', 'RACE_SPORTSMANSHIP'].includes(this.value); } /** * Check if this is a negative reason */ isNegative(): boolean { return ['RACE_INCIDENTS', 'RACE_DNF', 'RACE_DSQ', 'RACE_DNS', 'RACE_AFK'].includes(this.value); } }