import { MediaReference } from '@core/domain/media/MediaReference'; import type { UseCase } from '@core/shared/application/UseCase'; import type { Logger } from '@core/shared/domain/Logger'; import { Result } from '@core/shared/domain/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { Driver } from '../../domain/entities/Driver'; import type { Team } from '../../domain/entities/Team'; import type { DriverRepository } from '../../domain/repositories/DriverRepository'; import { SkillLevelService, type SkillLevel } from '../../domain/services/SkillLevelService'; import type { DriverStats, DriverStatsUseCase } from './DriverStatsUseCase'; import type { RankingUseCase } from './RankingUseCase'; export type GetDriversLeaderboardInput = { leagueId?: string; seasonId?: string; }; export interface DriverLeaderboardItem { driver: Driver; team?: Team; rating: number; skillLevel: SkillLevel; racesCompleted: number; wins: number; podiums: number; isActive: boolean; rank: number; avatarRef?: MediaReference; } export interface GetDriversLeaderboardResult { items: DriverLeaderboardItem[]; totalRaces: number; totalWins: number; activeCount: number; } export type GetDriversLeaderboardErrorCode = | 'LEAGUE_NOT_FOUND' | 'SEASON_NOT_FOUND' | 'REPOSITORY_ERROR'; /** * Use Case for retrieving driver leaderboard data. * Returns a Result containing the domain leaderboard model. */ export class GetDriversLeaderboardUseCase implements UseCase { constructor( private readonly driverRepository: DriverRepository, private readonly rankingUseCase: RankingUseCase, private readonly driverStatsUseCase: DriverStatsUseCase, private readonly logger: Logger, ) {} async execute( input: GetDriversLeaderboardInput, ): Promise< Result< GetDriversLeaderboardResult, ApplicationErrorCode > > { this.logger.debug('Executing GetDriversLeaderboardUseCase', { input }); try { const drivers = await this.driverRepository.findAll(); const rankings = await this.rankingUseCase.getAllDriverRankings(); // Get stats for all drivers const statsPromises = drivers.map(driver => this.driverStatsUseCase.getDriverStats(driver.id) ); const statsResults = await Promise.all(statsPromises); const statsMap = new Map(); drivers.forEach((driver, idx) => { const stats = statsResults[idx]; if (stats) { statsMap.set(driver.id, stats); } }); const items: DriverLeaderboardItem[] = drivers.map((driver) => { const ranking = rankings.find((r) => r.driverId === driver.id); const stats = statsMap.get(driver.id); const rating = ranking?.rating ?? 0; const racesCompleted = stats?.totalRaces ?? 0; const skillLevel: SkillLevel = SkillLevelService.getSkillLevel(rating); return { driver, rating, skillLevel, racesCompleted, wins: stats?.wins ?? 0, podiums: stats?.podiums ?? 0, isActive: racesCompleted > 0, rank: ranking?.overallRank ?? 0, avatarRef: driver.avatarRef, }; }); const totalRaces = items.reduce((sum, d) => sum + d.racesCompleted, 0); const totalWins = items.reduce((sum, d) => sum + d.wins, 0); const activeCount = items.filter(d => d.isActive).length; const result: GetDriversLeaderboardResult = { items: items.sort((a, b) => b.rating - a.rating), totalRaces, totalWins, activeCount, }; this.logger.debug('Successfully computed drivers leaderboard'); return Result.ok(result); } catch (error) { const err = error instanceof Error ? error : new Error(String(error)); this.logger.error('Error executing GetDriversLeaderboardUseCase', err); return Result.err({ code: 'REPOSITORY_ERROR', details: { message: err.message ?? 'Unknown error occurred' }, }); } } }