Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m51s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
123 lines
3.8 KiB
TypeScript
123 lines
3.8 KiB
TypeScript
/**
|
|
* CalculateTeamContributionUseCase
|
|
*
|
|
* Calculates team contribution rating for a driver.
|
|
*/
|
|
|
|
import { RatingRepository } from '../../ports/RatingRepository';
|
|
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
|
import { RaceRepository } from '../../../racing/domain/repositories/RaceRepository';
|
|
import { ResultRepository } from '../../../racing/domain/repositories/ResultRepository';
|
|
import { Rating } from '../../domain/Rating';
|
|
import { RatingComponents } from '../../domain/RatingComponents';
|
|
import { DriverId } from '../../../racing/domain/entities/DriverId';
|
|
import { RaceId } from '../../../racing/domain/entities/RaceId';
|
|
|
|
export interface CalculateTeamContributionUseCasePorts {
|
|
ratingRepository: RatingRepository;
|
|
driverRepository: DriverRepository;
|
|
raceRepository: RaceRepository;
|
|
resultRepository: ResultRepository;
|
|
}
|
|
|
|
export interface CalculateTeamContributionRequest {
|
|
driverId: string;
|
|
raceId: string;
|
|
}
|
|
|
|
export interface TeamContributionResult {
|
|
driverId: string;
|
|
raceId: string;
|
|
teamContribution: number;
|
|
components: RatingComponents;
|
|
}
|
|
|
|
export class CalculateTeamContributionUseCase {
|
|
constructor(private readonly ports: CalculateTeamContributionUseCasePorts) {}
|
|
|
|
async execute(request: CalculateTeamContributionRequest): Promise<TeamContributionResult> {
|
|
const { ratingRepository, driverRepository, raceRepository, resultRepository } = this.ports;
|
|
const { driverId, raceId } = request;
|
|
|
|
try {
|
|
// Validate driver exists
|
|
const driver = await driverRepository.findById(driverId);
|
|
if (!driver) {
|
|
throw new Error('Driver not found');
|
|
}
|
|
|
|
// Validate race exists
|
|
const race = await raceRepository.findById(raceId);
|
|
if (!race) {
|
|
throw new Error('Race not found');
|
|
}
|
|
|
|
// Get race results
|
|
const results = await resultRepository.findByRaceId(raceId);
|
|
if (results.length === 0) {
|
|
throw new Error('No results found for race');
|
|
}
|
|
|
|
// Get driver's result
|
|
const driverResult = results.find(r => r.driverId.toString() === driverId);
|
|
if (!driverResult) {
|
|
throw new Error('Driver not found in race results');
|
|
}
|
|
|
|
// Calculate team contribution component
|
|
const teamContribution = this.calculateTeamContribution(driverResult.points);
|
|
|
|
// Get existing rating or create new one
|
|
let existingRating = await ratingRepository.findByDriverAndRace(driverId, raceId);
|
|
|
|
if (!existingRating) {
|
|
// Create a new rating with default components
|
|
existingRating = Rating.create({
|
|
driverId: DriverId.create(driverId),
|
|
raceId: RaceId.create(raceId),
|
|
rating: 0,
|
|
components: {
|
|
resultsStrength: 0,
|
|
consistency: 0,
|
|
cleanDriving: 0,
|
|
racecraft: 0,
|
|
reliability: 0,
|
|
teamContribution: teamContribution,
|
|
},
|
|
timestamp: new Date(),
|
|
});
|
|
} else {
|
|
// Update existing rating with new team contribution
|
|
existingRating = Rating.create({
|
|
driverId: DriverId.create(driverId),
|
|
raceId: RaceId.create(raceId),
|
|
rating: existingRating.rating,
|
|
components: {
|
|
...existingRating.components,
|
|
teamContribution: teamContribution,
|
|
},
|
|
timestamp: new Date(),
|
|
});
|
|
}
|
|
|
|
// Save the rating
|
|
await ratingRepository.save(existingRating);
|
|
|
|
return {
|
|
driverId,
|
|
raceId,
|
|
teamContribution,
|
|
components: existingRating.components,
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to calculate team contribution: ${error}`);
|
|
}
|
|
}
|
|
|
|
private calculateTeamContribution(points: number): number {
|
|
if (points === 0) return 20;
|
|
if (points >= 25) return 100;
|
|
return Math.round((points / 25) * 100);
|
|
}
|
|
}
|