import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository'; import type { IResultRepository } from '../../domain/repositories/IResultRepository'; import type { IStandingRepository } from '../../domain/repositories/IStandingRepository'; import type { DriverRatingProvider } from '../ports/DriverRatingProvider'; import { Result } from '../../domain/entities/Result'; import { Standing } from '../../domain/entities/Standing'; import { RaceResultGenerator } from '../utils/RaceResultGenerator'; import { RatingUpdateService } from '@core/identity/domain/services/RatingUpdateService'; import type { AsyncUseCase } from '@core/shared/application'; import { Result as SharedResult } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { CompleteRaceCommandDTO } from '../dto/CompleteRaceCommandDTO'; /** * Enhanced CompleteRaceUseCase that includes rating updates */ export class CompleteRaceUseCaseWithRatings implements AsyncUseCase { constructor( private readonly raceRepository: IRaceRepository, private readonly raceRegistrationRepository: IRaceRegistrationRepository, private readonly resultRepository: IResultRepository, private readonly standingRepository: IStandingRepository, private readonly driverRatingProvider: DriverRatingProvider, private readonly ratingUpdateService: RatingUpdateService, ) {} async execute(command: CompleteRaceCommandDTO): Promise>> { try { const { raceId } = command; const race = await this.raceRepository.findById(raceId); if (!race) { return SharedResult.err({ code: 'RACE_NOT_FOUND' }); } // Get registered drivers for this race const registeredDriverIds = await this.raceRegistrationRepository.getRegisteredDrivers(raceId); if (registeredDriverIds.length === 0) { return SharedResult.err({ code: 'NO_REGISTERED_DRIVERS' }); } // Get driver ratings const driverRatings = this.driverRatingProvider.getRatings(registeredDriverIds); // Generate realistic race results const results = RaceResultGenerator.generateRaceResults(raceId, registeredDriverIds, driverRatings); // Save results for (const result of results) { await this.resultRepository.create(result); } // Update standings await this.updateStandings(race.leagueId, results); // Update driver ratings based on performance await this.updateDriverRatings(results, registeredDriverIds.length); // Complete the race const completedRace = race.complete(); await this.raceRepository.update(completedRace); return SharedResult.ok(undefined); } catch { return SharedResult.err({ code: 'UNKNOWN_ERROR' }); } } private async updateStandings(leagueId: string, results: Result[]): Promise { // Group results by driver const resultsByDriver = new Map(); for (const result of results) { const existing = resultsByDriver.get(result.driverId) || []; existing.push(result); resultsByDriver.set(result.driverId, existing); } // Update or create standings for each driver for (const [driverId, driverResults] of resultsByDriver) { let standing = await this.standingRepository.findByDriverIdAndLeagueId(driverId, leagueId); if (!standing) { standing = Standing.create({ leagueId, driverId, }); } // Add all results for this driver (should be just one for this race) for (const result of driverResults) { standing = standing.addRaceResult(result.position, { 1: 25, 2: 18, 3: 15, 4: 12, 5: 10, 6: 8, 7: 6, 8: 4, 9: 2, 10: 1 }); } await this.standingRepository.save(standing); } } private async updateDriverRatings(results: Result[], totalDrivers: number): Promise { const driverResults = results.map(result => ({ driverId: result.driverId, position: result.position, totalDrivers, incidents: result.incidents, startPosition: result.startPosition, })); await this.ratingUpdateService.updateDriverRatingsAfterRace(driverResults); } }