/** * Application Query: GetRaceProtestsQuery * * Returns all protests filed for a specific race, with driver details. */ import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IDriverRepository } from '../../domain/repositories/IDriverRepository'; import type { ProtestStatus, ProtestIncident } from '../../domain/entities/Protest'; export interface RaceProtestDTO { id: string; raceId: string; protestingDriverId: string; protestingDriverName: string; accusedDriverId: string; accusedDriverName: string; incident: ProtestIncident; comment?: string; proofVideoUrl?: string; status: ProtestStatus; reviewedBy?: string; reviewedByName?: string; decisionNotes?: string; filedAt: string; reviewedAt?: string; } export class GetRaceProtestsQuery { constructor( private readonly protestRepository: IProtestRepository, private readonly driverRepository: IDriverRepository, ) {} async execute(raceId: string): Promise { const protests = await this.protestRepository.findByRaceId(raceId); // Load all driver details in parallel const driverIds = new Set(); protests.forEach(protest => { driverIds.add(protest.protestingDriverId); driverIds.add(protest.accusedDriverId); if (protest.reviewedBy) { driverIds.add(protest.reviewedBy); } }); const drivers = await Promise.all( Array.from(driverIds).map(id => this.driverRepository.findById(id)) ); const driverMap = new Map(); drivers.forEach(driver => { if (driver) { driverMap.set(driver.id, driver.name); } }); return protests.map(protest => ({ id: protest.id, raceId: protest.raceId, protestingDriverId: protest.protestingDriverId, protestingDriverName: driverMap.get(protest.protestingDriverId) || 'Unknown', accusedDriverId: protest.accusedDriverId, accusedDriverName: driverMap.get(protest.accusedDriverId) || 'Unknown', incident: protest.incident, comment: protest.comment, proofVideoUrl: protest.proofVideoUrl, status: protest.status, reviewedBy: protest.reviewedBy, reviewedByName: protest.reviewedBy ? driverMap.get(protest.reviewedBy) : undefined, decisionNotes: protest.decisionNotes, filedAt: protest.filedAt.toISOString(), reviewedAt: protest.reviewedAt?.toISOString(), })); } }