/** * Application Use Case: TeamRatingFactoryUseCase * * Factory use case for creating team rating events from race results. * This replaces direct team rating calculations with event-based approach. * Mirrors the user rating factory pattern. */ import { TeamRatingEvent } from '@core/racing/domain/entities/TeamRatingEvent'; import { TeamRatingDelta } from '@core/racing/domain/value-objects/TeamRatingDelta'; import { TeamRatingDimensionKey } from '@core/racing/domain/value-objects/TeamRatingDimensionKey'; import { TeamRatingEventId } from '@core/racing/domain/value-objects/TeamRatingEventId'; import type { Logger } from '@core/shared/domain/Logger'; import { TeamDrivingRatingEventFactory } from '../../domain/services/TeamDrivingRatingEventFactory'; import { TeamRaceResultsProvider } from '../ports/TeamRaceResultsProvider'; export interface TeamRatingFactoryInput { raceId: string; } export interface TeamRatingFactoryOutput { success: boolean; raceId: string; events: TeamRatingEvent[]; errors: string[]; } export class TeamRatingFactoryUseCase { constructor( private readonly teamRaceResultsProvider: TeamRaceResultsProvider, private readonly logger: Logger ) { this.logger.info('[TeamRatingFactoryUseCase] Initialized'); } async execute(input: TeamRatingFactoryInput): Promise { this.logger.debug(`[TeamRatingFactoryUseCase] Creating rating events for race ${input.raceId}`); try { // Load team race results const teamRaceResults = await this.teamRaceResultsProvider.getTeamRaceResults(input.raceId); if (!teamRaceResults) { return { success: false, raceId: input.raceId, events: [], errors: ['Team race results not found'], }; } // Use factory to create events const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(teamRaceResults); // Flatten events from all teams const allEvents: TeamRatingEvent[] = []; for (const [, events] of eventsByTeam) { allEvents.push(...events); } if (allEvents.length === 0) { this.logger.info(`[TeamRatingFactoryUseCase] No events generated for race ${input.raceId}`); return { success: true, raceId: input.raceId, events: [], errors: [], }; } this.logger.info(`[TeamRatingFactoryUseCase] Generated ${allEvents.length} events for race ${input.raceId}`); return { success: true, raceId: input.raceId, events: allEvents, errors: [], }; } catch (error) { const errorMsg = `Failed to create rating events: ${error instanceof Error ? error.message : 'Unknown error'}`; this.logger.error('[TeamRatingFactoryUseCase] Error:', error instanceof Error ? error : new Error(String(error))); return { success: false, raceId: input.raceId, events: [], errors: [errorMsg], }; } } /** * Create team rating events manually (for testing or manual adjustments) */ createManualEvents( teamId: string, dimension: string, delta: number, reason: string, sourceType: 'race' | 'penalty' | 'vote' | 'adminAction' | 'manualAdjustment', sourceId?: string ): TeamRatingEvent[] { const source = sourceId ? { type: sourceType, id: sourceId } : { type: sourceType }; const event = TeamRatingEvent.create({ id: TeamRatingEventId.generate(), teamId, dimension: TeamRatingDimensionKey.create(dimension), delta: TeamRatingDelta.create(delta), occurredAt: new Date(), createdAt: new Date(), source: source, reason: { code: reason }, visibility: { public: true }, version: 1, }); return [event]; } }