Files
gridpilot.gg/core/rating/application/use-cases/CalculateTeamContributionUseCase.ts
Marc Mintel 9ccecbf3bb
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
integration tests
2026-01-24 01:13:49 +01:00

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);
}
}