/** * 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 { 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); } }