import type { IValueObject } from '@core/shared/domain'; import { IdentityDomainValidationError } from '../errors/IdentityDomainError'; /** * Driving Reason Code Value Object * * Stable machine codes for driving rating events to support: * - Filtering and analytics * - i18n translations * - Consistent UI explanations * * Based on ratings-architecture-concept.md section 5.1.2 */ export type DrivingReasonCodeValue = // Performance | 'DRIVING_FINISH_STRENGTH_GAIN' | 'DRIVING_POSITIONS_GAINED_BONUS' | 'DRIVING_PACE_RELATIVE_GAIN' // Clean driving | 'DRIVING_INCIDENTS_PENALTY' | 'DRIVING_MAJOR_CONTACT_PENALTY' | 'DRIVING_PENALTY_INVOLVEMENT_PENALTY' // Reliability | 'DRIVING_DNS_PENALTY' | 'DRIVING_DNF_PENALTY' | 'DRIVING_DSQ_PENALTY' | 'DRIVING_AFK_PENALTY' | 'DRIVING_SEASON_ATTENDANCE_BONUS'; export interface DrivingReasonCodeProps { value: DrivingReasonCodeValue; } const VALID_REASON_CODES: DrivingReasonCodeValue[] = [ // Performance 'DRIVING_FINISH_STRENGTH_GAIN', 'DRIVING_POSITIONS_GAINED_BONUS', 'DRIVING_PACE_RELATIVE_GAIN', // Clean driving 'DRIVING_INCIDENTS_PENALTY', 'DRIVING_MAJOR_CONTACT_PENALTY', 'DRIVING_PENALTY_INVOLVEMENT_PENALTY', // Reliability 'DRIVING_DNS_PENALTY', 'DRIVING_DNF_PENALTY', 'DRIVING_DSQ_PENALTY', 'DRIVING_AFK_PENALTY', 'DRIVING_SEASON_ATTENDANCE_BONUS', ]; export class DrivingReasonCode implements IValueObject { readonly value: DrivingReasonCodeValue; private constructor(value: DrivingReasonCodeValue) { this.value = value; } static create(value: string): DrivingReasonCode { if (!value || value.trim().length === 0) { throw new IdentityDomainValidationError('DrivingReasonCode cannot be empty'); } const trimmed = value.trim() as DrivingReasonCodeValue; if (!VALID_REASON_CODES.includes(trimmed)) { throw new IdentityDomainValidationError( `Invalid driving reason code: ${value}. Valid options: ${VALID_REASON_CODES.join(', ')}` ); } return new DrivingReasonCode(trimmed); } static fromValue(value: DrivingReasonCodeValue): DrivingReasonCode { return new DrivingReasonCode(value); } get props(): DrivingReasonCodeProps { return { value: this.value }; } equals(other: IValueObject): boolean { return this.value === other.props.value; } toString(): string { return this.value; } /** * Check if this is a performance-related reason code */ isPerformance(): boolean { return this.value === 'DRIVING_FINISH_STRENGTH_GAIN' || this.value === 'DRIVING_POSITIONS_GAINED_BONUS' || this.value === 'DRIVING_PACE_RELATIVE_GAIN'; } /** * Check if this is a clean driving-related reason code */ isCleanDriving(): boolean { return this.value === 'DRIVING_INCIDENTS_PENALTY' || this.value === 'DRIVING_MAJOR_CONTACT_PENALTY' || this.value === 'DRIVING_PENALTY_INVOLVEMENT_PENALTY'; } /** * Check if this is a reliability-related reason code */ isReliability(): boolean { return this.value === 'DRIVING_DNS_PENALTY' || this.value === 'DRIVING_DNF_PENALTY' || this.value === 'DRIVING_DSQ_PENALTY' || this.value === 'DRIVING_AFK_PENALTY' || this.value === 'DRIVING_SEASON_ATTENDANCE_BONUS'; } /** * Check if this is a penalty (negative impact) */ isPenalty(): boolean { return this.value.endsWith('_PENALTY'); } /** * Check if this is a bonus (positive impact) */ isBonus(): boolean { return this.value.endsWith('_BONUS') || this.value.endsWith('_GAIN'); } }