/** * Application Use Case: SubmitProtestDefenseUseCase * * Allows the accused driver to submit their defense statement for a protest. */ import { Result } from '@core/shared/application/Result'; import { Logger, UseCaseOutputPort } from '@core/shared/application'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository'; import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; export type SubmitProtestDefenseInput = { leagueId: string; protestId: string; driverId: string; defenseText: string; videoUrl?: string; }; export type SubmitProtestDefenseResult = { leagueId: string; protestId: string; driverId: string; status: 'defense_submitted'; }; export type SubmitProtestDefenseErrorCode = | 'LEAGUE_NOT_FOUND' | 'PROTEST_NOT_FOUND' | 'DRIVER_NOT_ALLOWED' | 'INVALID_PROTEST_STATE' | 'REPOSITORY_ERROR'; export class SubmitProtestDefenseUseCase { constructor( private readonly leagueRepository: ILeagueRepository, private readonly protestRepository: IProtestRepository, private readonly logger: Logger, private readonly output: UseCaseOutputPort, ) {} async execute( input: SubmitProtestDefenseInput, ): Promise>> { try { const league = await this.leagueRepository.findById(input.leagueId); if (!league) { return Result.err({ code: 'LEAGUE_NOT_FOUND', details: { message: 'League not found' }, }); } const protest = await this.protestRepository.findById(input.protestId); if (!protest) { return Result.err({ code: 'PROTEST_NOT_FOUND', details: { message: 'Protest not found' }, }); } if (protest.accusedDriverId !== input.driverId) { return Result.err({ code: 'DRIVER_NOT_ALLOWED', details: { message: 'Driver is not allowed to submit a defense for this protest' }, }); } if (!protest.canSubmitDefense()) { return Result.err({ code: 'INVALID_PROTEST_STATE', details: { message: 'Defense cannot be submitted for this protest' }, }); } const updatedProtest = protest.submitDefense(input.defenseText, input.videoUrl); await this.protestRepository.update(updatedProtest); const result: SubmitProtestDefenseResult = { leagueId: input.leagueId, protestId: protest.id, driverId: input.driverId, status: 'defense_submitted', }; this.output.present(result); return Result.ok(undefined); } catch (error: unknown) { const message = error instanceof Error && typeof error.message === 'string' ? error.message : 'Failed to submit protest defense'; this.logger.error( 'SubmitProtestDefenseUseCase.execute failed', error instanceof Error ? error : undefined, ); return Result.err({ code: 'REPOSITORY_ERROR', details: { message }, }); } } }