/** * Use Case: GetRaceProtestsUseCase * * Returns all protests filed for a specific race, with driver details. * Orchestrates domain logic and delegates presentation to the presenter. */ import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IDriverRepository } from '../../domain/repositories/IDriverRepository'; import type { Protest } from '../../domain/entities/Protest'; import type { Driver } from '../../domain/entities/Driver'; import { Result } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { UseCaseOutputPort } from '@core/shared/application'; export interface GetRaceProtestsInput { raceId: string; } export type GetRaceProtestsErrorCode = 'REPOSITORY_ERROR'; export interface GetRaceProtestsResult { protests: Protest[]; drivers: Driver[]; } export class GetRaceProtestsUseCase { constructor( private readonly protestRepository: IProtestRepository, private readonly driverRepository: IDriverRepository, private readonly output: UseCaseOutputPort, ) {} async execute( input: GetRaceProtestsInput, ): Promise>> { try { const protests = await this.protestRepository.findByRaceId(input.raceId); 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 validDrivers = drivers.filter((driver): driver is NonNullable => driver !== null); const result: GetRaceProtestsResult = { protests, drivers: validDrivers, }; this.output.present(result); return Result.ok(undefined); } catch (error: unknown) { const message = error instanceof Error && error.message ? error.message : 'Failed to load race protests'; return Result.err({ code: 'REPOSITORY_ERROR', details: { message }, }); } } }