/** * 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 type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; export interface RequestProtestDefenseCommand { protestId: string; stewardId: string; } export interface RequestProtestDefenseResult { success: boolean; accusedDriverId: string; protestId: string; } export class RequestProtestDefenseUseCase { constructor( private readonly protestRepository: IProtestRepository, private readonly raceRepository: IRaceRepository, private readonly membershipRepository: ILeagueMembershipRepository, ) {} async execute(command: RequestProtestDefenseCommand): Promise>> { // Get the protest const protest = await this.protestRepository.findById(command.protestId); if (!protest) { return Result.err({ code: 'PROTEST_NOT_FOUND' }); } // Get the race to find the league const race = await this.raceRepository.findById(protest.raceId); if (!race) { return Result.err({ code: 'RACE_NOT_FOUND' }); } // Verify the steward has permission const membership = await this.membershipRepository.getMembership(race.leagueId, command.stewardId); if (!membership || !isLeagueStewardOrHigherRole(membership.role)) { return Result.err({ code: 'INSUFFICIENT_PERMISSIONS' }); } // Check if defense can be requested if (!protest.canRequestDefense()) { return Result.err({ code: 'DEFENSE_CANNOT_BE_REQUESTED' }); } // Request defense const updatedProtest = protest.requestDefense(command.stewardId); await this.protestRepository.update(updatedProtest); return Result.ok({ success: true, accusedDriverId: protest.accusedDriverId, protestId: protest.id, }); } }