/** * Application Use Case: FileProtestUseCase * * Allows a driver to file a protest against another driver for an incident during a race. */ import { Protest } from '../../domain/entities/Protest'; import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import { Result } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; import { randomUUID } from 'crypto'; export type FileProtestErrorCode = 'RACE_NOT_FOUND' | 'SELF_PROTEST' | 'NOT_MEMBER' | 'REPOSITORY_ERROR'; export interface FileProtestInput { raceId: string; protestingDriverId: string; accusedDriverId: string; incident: { lap: number; description: string; timeInRace?: number; }; comment?: string; proofVideoUrl?: string; } export interface FileProtestResult { protest: Protest; } export class FileProtestUseCase { constructor( private readonly protestRepository: IProtestRepository, private readonly raceRepository: IRaceRepository, private readonly leagueMembershipRepository: ILeagueMembershipRepository, private readonly output: UseCaseOutputPort, ) {} async execute(command: FileProtestInput): Promise>> { try { // Validate race exists const race = await this.raceRepository.findById(command.raceId); if (!race) { return Result.err({ code: 'RACE_NOT_FOUND', details: { message: 'Race not found' } }); } // Validate drivers are not the same if (command.protestingDriverId === command.accusedDriverId) { return Result.err({ code: 'SELF_PROTEST', details: { message: 'Cannot file a protest against yourself' } }); } // Validate protesting driver is a member of the league const memberships = await this.leagueMembershipRepository.getLeagueMembers(race.leagueId); const protestingDriverMembership = memberships.find( m => m.driverId.toString() === command.protestingDriverId && m.status.toString() === 'active', ); if (!protestingDriverMembership) { return Result.err({ code: 'NOT_MEMBER', details: { message: 'Protesting driver is not an active member of this league' } }); } // Create the protest const protest = Protest.create({ id: randomUUID(), raceId: command.raceId, protestingDriverId: command.protestingDriverId, accusedDriverId: command.accusedDriverId, incident: command.incident, ...(command.comment !== undefined ? { comment: command.comment } : {}), ...(command.proofVideoUrl !== undefined ? { proofVideoUrl: command.proofVideoUrl } : {}), status: 'pending', filedAt: new Date(), }); await this.protestRepository.create(protest); this.output.present({ protest }); return Result.ok(undefined); } catch (error) { const message = error instanceof Error ? error.message : 'Failed to file protest'; return Result.err({ code: 'REPOSITORY_ERROR', details: { message } }); } } }