import type { AsyncUseCase } from '@core/shared/application'; import type { Logger } from '@core/shared/application'; import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository'; import type { IDomainEventPublisher } from '@core/shared/domain/IDomainEvent'; import { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed'; import { Result } from '@core/shared/result/Result'; import { RacingDomainValidationError } from '../../domain/errors/RacingDomainError'; import type { CloseRaceEventStewardingCommand } from './CloseRaceEventStewardingCommand'; import type { RaceEvent } from '../../domain/entities/RaceEvent'; /** * Use Case: CloseRaceEventStewardingUseCase * * Scheduled job that checks for race events with expired stewarding windows * and closes them, triggering final results notifications. * * This would typically be run by a scheduled job (e.g., every 5 minutes) * to automatically close stewarding windows based on league configuration. */ export class CloseRaceEventStewardingUseCase implements AsyncUseCase> { constructor( private readonly logger: Logger, private readonly raceEventRepository: IRaceEventRepository, private readonly domainEventPublisher: IDomainEventPublisher, ) {} // eslint-disable-next-line @typescript-eslint/no-unused-vars async execute(_command: CloseRaceEventStewardingCommand): Promise> { try { // Find all race events awaiting stewarding that have expired windows const expiredEvents = await this.raceEventRepository.findAwaitingStewardingClose(); for (const raceEvent of expiredEvents) { await this.closeStewardingForRaceEvent(raceEvent); } return Result.ok(undefined); } catch (error) { this.logger.error('Failed to close race event stewarding', error instanceof Error ? error : new Error(String(error))); return Result.err(new RacingDomainValidationError('Failed to close stewarding for race events')); } } private async closeStewardingForRaceEvent(raceEvent: RaceEvent): Promise { try { // Close the stewarding window const closedRaceEvent = raceEvent.closeStewarding(); await this.raceEventRepository.update(closedRaceEvent); // Get list of participating drivers (would need to be implemented) const driverIds = await this.getParticipatingDriverIds(); // Check if any penalties were applied during stewarding const hadPenaltiesApplied = await this.checkForAppliedPenalties(); // Publish domain event to trigger final results notifications const event = new RaceEventStewardingClosedEvent({ raceEventId: raceEvent.id, leagueId: raceEvent.leagueId, seasonId: raceEvent.seasonId, closedAt: new Date(), driverIds, hadPenaltiesApplied, }); await this.domainEventPublisher.publish(event); } catch (error) { this.logger.error(`Failed to close stewarding for race event ${raceEvent.id}`, error instanceof Error ? error : new Error(String(error))); // TODO: In production, this would trigger alerts/monitoring } } private async getParticipatingDriverIds(): Promise { // TODO: Implement query for participating driver IDs from race event registrations // This would typically involve querying race registrations for the event return []; } private async checkForAppliedPenalties(): Promise { // TODO: Implement check for applied penalties during stewarding window // This would query the penalty repository for penalties related to this race event return false; } }