/** * Application Use Case: RequestProtestDefenseUseCase * * Allows a steward to request defense from the accused driver before making a decision. * This will trigger a notification to the accused driver. */ import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import { isLeagueStewardOrHigherRole } from '../../domain/types/LeagueRoles'; import { Result } from '@core/shared/application/Result'; import { Logger, UseCaseOutputPort } from '@core/shared/application'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; export type RequestProtestDefenseInput = { protestId: string; stewardId: string; }; export type RequestProtestDefenseResult = { leagueId: string; protestId: string; accusedDriverId: string; status: 'defense_requested'; }; export type RequestProtestDefenseErrorCode = | 'PROTEST_NOT_FOUND' | 'RACE_NOT_FOUND' | 'INSUFFICIENT_PERMISSIONS' | 'DEFENSE_CANNOT_BE_REQUESTED' | 'REPOSITORY_ERROR'; export class RequestProtestDefenseUseCase { constructor( private readonly protestRepository: IProtestRepository, private readonly raceRepository: IRaceRepository, private readonly membershipRepository: ILeagueMembershipRepository, private readonly logger: Logger, private readonly output: UseCaseOutputPort, ) {} async execute( input: RequestProtestDefenseInput, ): Promise>> { try { const protest = await this.protestRepository.findById(input.protestId); if (!protest) { return Result.err({ code: 'PROTEST_NOT_FOUND', details: { message: 'Protest not found' } }); } const race = await this.raceRepository.findById(protest.raceId); if (!race) { return Result.err({ code: 'RACE_NOT_FOUND', details: { message: 'Race not found' } }); } const membership = await this.membershipRepository.getMembership(race.leagueId, input.stewardId); if (!membership || !isLeagueStewardOrHigherRole(membership.role)) { return Result.err({ code: 'INSUFFICIENT_PERMISSIONS', details: { message: 'Insufficient permissions to request defense' }, }); } if (!protest.canRequestDefense()) { return Result.err({ code: 'DEFENSE_CANNOT_BE_REQUESTED', details: { message: 'Defense cannot be requested for this protest' }, }); } const updatedProtest = protest.requestDefense(input.stewardId); await this.protestRepository.update(updatedProtest); const result: RequestProtestDefenseResult = { leagueId: race.leagueId, protestId: protest.id, accusedDriverId: protest.accusedDriverId, status: 'defense_requested', }; this.output.present(result); return Result.ok(undefined); } catch (error: unknown) { const message = error instanceof Error ? error.message : 'Failed to request protest defense'; this.logger.error('RequestProtestDefenseUseCase.execute failed', error instanceof Error ? error : undefined); return Result.err({ code: 'REPOSITORY_ERROR', details: { message } }); } } }