wip
This commit is contained in:
@@ -6,6 +6,7 @@ import type { DriverRatingProvider } from '../ports/DriverRatingProvider';
|
||||
import { Result } from '../../domain/entities/Result';
|
||||
import { Standing } from '../../domain/entities/Standing';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import type { ILogger } from '../../../shared/src/logging/ILogger';
|
||||
|
||||
/**
|
||||
* Use Case: CompleteRaceUseCase
|
||||
@@ -30,39 +31,55 @@ export class CompleteRaceUseCase
|
||||
private readonly resultRepository: IResultRepository,
|
||||
private readonly standingRepository: IStandingRepository,
|
||||
private readonly driverRatingProvider: DriverRatingProvider,
|
||||
private readonly logger: ILogger,
|
||||
) {}
|
||||
|
||||
async execute(command: CompleteRaceCommandDTO): Promise<void> {
|
||||
this.logger.debug(`Executing CompleteRaceUseCase for raceId: ${command.raceId}`);
|
||||
const { raceId } = command;
|
||||
|
||||
const race = await this.raceRepository.findById(raceId);
|
||||
if (!race) {
|
||||
throw new Error('Race not found');
|
||||
try {
|
||||
const race = await this.raceRepository.findById(raceId);
|
||||
if (!race) {
|
||||
this.logger.error(`Race with id ${raceId} not found.`);
|
||||
throw new Error('Race not found');
|
||||
}
|
||||
this.logger.debug(`Race ${raceId} found. Status: ${race.status}`);
|
||||
|
||||
// Get registered drivers for this race
|
||||
const registeredDriverIds = await this.raceRegistrationRepository.getRegisteredDrivers(raceId);
|
||||
if (registeredDriverIds.length === 0) {
|
||||
this.logger.warn(`No registered drivers found for race ${raceId}.`);
|
||||
throw new Error('Cannot complete race with no registered drivers');
|
||||
}
|
||||
this.logger.info(`${registeredDriverIds.length} drivers registered for race ${raceId}. Generating results.`);
|
||||
|
||||
// Get driver ratings
|
||||
const driverRatings = this.driverRatingProvider.getRatings(registeredDriverIds);
|
||||
this.logger.debug(`Driver ratings fetched for ${registeredDriverIds.length} drivers.`);
|
||||
|
||||
// Generate realistic race results
|
||||
const results = this.generateRaceResults(raceId, registeredDriverIds, driverRatings);
|
||||
this.logger.debug(`Generated ${results.length} race results for race ${raceId}.`);
|
||||
|
||||
// Save results
|
||||
for (const result of results) {
|
||||
await this.resultRepository.create(result);
|
||||
}
|
||||
this.logger.info(`Persisted ${results.length} race results for race ${raceId}.`);
|
||||
|
||||
// Update standings
|
||||
await this.updateStandings(race.leagueId, results);
|
||||
this.logger.info(`Standings updated for league ${race.leagueId}.`);
|
||||
|
||||
// Complete the race
|
||||
const completedRace = race.complete();
|
||||
await this.raceRepository.update(completedRace);
|
||||
this.logger.info(`Race ${raceId} successfully completed and updated.`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to complete race ${raceId}: ${error.message}`, error as Error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Get registered drivers for this race
|
||||
const registeredDriverIds = await this.raceRegistrationRepository.getRegisteredDrivers(raceId);
|
||||
if (registeredDriverIds.length === 0) {
|
||||
throw new Error('Cannot complete race with no registered drivers');
|
||||
}
|
||||
|
||||
// Get driver ratings
|
||||
const driverRatings = this.driverRatingProvider.getRatings(registeredDriverIds);
|
||||
|
||||
// Generate realistic race results
|
||||
const results = this.generateRaceResults(raceId, registeredDriverIds, driverRatings);
|
||||
|
||||
// Save results
|
||||
for (const result of results) {
|
||||
await this.resultRepository.create(result);
|
||||
}
|
||||
|
||||
// Update standings
|
||||
await this.updateStandings(race.leagueId, results);
|
||||
|
||||
// Complete the race
|
||||
const completedRace = race.complete();
|
||||
await this.raceRepository.update(completedRace);
|
||||
}
|
||||
|
||||
private generateRaceResults(
|
||||
@@ -70,6 +87,7 @@ export class CompleteRaceUseCase
|
||||
driverIds: string[],
|
||||
driverRatings: Map<string, number>
|
||||
): Result[] {
|
||||
this.logger.debug(`Generating race results for race ${raceId} with ${driverIds.length} drivers.`);
|
||||
// Create driver performance data
|
||||
const driverPerformances = driverIds.map(driverId => ({
|
||||
driverId,
|
||||
@@ -83,6 +101,7 @@ export class CompleteRaceUseCase
|
||||
const perfB = b.rating + (b.randomFactor * 200);
|
||||
return perfB - perfA; // Higher performance first
|
||||
});
|
||||
this.logger.debug(`Driver performances sorted for race ${raceId}.`);
|
||||
|
||||
// Generate qualifying results for start positions (similar but different from race results)
|
||||
const qualiPerformances = driverPerformances.map(p => ({
|
||||
@@ -94,6 +113,7 @@ export class CompleteRaceUseCase
|
||||
const perfB = b.rating + (b.randomFactor * 150);
|
||||
return perfB - perfA;
|
||||
});
|
||||
this.logger.debug(`Qualifying performances generated for race ${raceId}.`);
|
||||
|
||||
// Generate results
|
||||
const results: Result[] = [];
|
||||
@@ -123,11 +143,13 @@ export class CompleteRaceUseCase
|
||||
})
|
||||
);
|
||||
}
|
||||
this.logger.debug(`Individual results created for race ${raceId}.`);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private async updateStandings(leagueId: string, results: Result[]): Promise<void> {
|
||||
this.logger.debug(`Updating standings for league ${leagueId} with ${results.length} results.`);
|
||||
// Group results by driver
|
||||
const resultsByDriver = new Map<string, Result[]>();
|
||||
for (const result of results) {
|
||||
@@ -135,6 +157,7 @@ export class CompleteRaceUseCase
|
||||
existing.push(result);
|
||||
resultsByDriver.set(result.driverId, existing);
|
||||
}
|
||||
this.logger.debug(`Results grouped by driver for league ${leagueId}.`);
|
||||
|
||||
// Update or create standings for each driver
|
||||
for (const [driverId, driverResults] of resultsByDriver) {
|
||||
@@ -145,6 +168,9 @@ export class CompleteRaceUseCase
|
||||
leagueId,
|
||||
driverId,
|
||||
});
|
||||
this.logger.debug(`Created new standing for driver ${driverId} in league ${leagueId}.`);
|
||||
} else {
|
||||
this.logger.debug(`Found existing standing for driver ${driverId} in league ${leagueId}.`);
|
||||
}
|
||||
|
||||
// Add all results for this driver (should be just one for this race)
|
||||
@@ -155,6 +181,8 @@ export class CompleteRaceUseCase
|
||||
}
|
||||
|
||||
await this.standingRepository.save(standing);
|
||||
this.logger.debug(`Standing saved for driver ${driverId} in league ${leagueId}.`);
|
||||
}
|
||||
this.logger.info(`Standings update complete for league ${leagueId}.`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user