import type { Driver } from '@gridpilot/racing/domain/entities/Driver'; import type { SkillLevel } from '@gridpilot/racing/domain/services/SkillLevelService'; import { SkillLevelService } from '@gridpilot/racing/domain/services/SkillLevelService'; import type { IDriversLeaderboardPresenter, DriverLeaderboardItemViewModel, DriversLeaderboardViewModel, } from '@gridpilot/racing/application/presenters/IDriversLeaderboardPresenter'; export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter { private viewModel: DriversLeaderboardViewModel | null = null; present( drivers: Driver[], rankings: Array<{ driverId: string; rating: number; overallRank: number }>, stats: Record, avatarUrls: Record ): DriversLeaderboardViewModel { const items: DriverLeaderboardItemViewModel[] = drivers.map((driver) => { const driverStats = stats[driver.id]; const rating = driverStats?.rating ?? 0; const wins = driverStats?.wins ?? 0; const podiums = driverStats?.podiums ?? 0; const totalRaces = driverStats?.totalRaces ?? 0; let effectiveRank = Number.POSITIVE_INFINITY; if (typeof driverStats?.overallRank === 'number' && driverStats.overallRank > 0) { effectiveRank = driverStats.overallRank; } else { const indexInGlobal = rankings.findIndex((entry) => entry.driverId === driver.id); if (indexInGlobal !== -1) { effectiveRank = indexInGlobal + 1; } } const skillLevel = SkillLevelService.getSkillLevel(rating); const isActive = rankings.some((r) => r.driverId === driver.id); return { id: driver.id, name: driver.name, rating, skillLevel, nationality: driver.country, racesCompleted: totalRaces, wins, podiums, isActive, rank: effectiveRank, avatarUrl: avatarUrls[driver.id] ?? '', }; }); items.sort((a, b) => { const rankA = Number.isFinite(a.rank) && a.rank > 0 ? a.rank : Number.POSITIVE_INFINITY; const rankB = Number.isFinite(b.rank) && b.rank > 0 ? b.rank : Number.POSITIVE_INFINITY; if (rankA !== rankB) return rankA - rankB; return b.rating - a.rating; }); 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; this.viewModel = { drivers: items, totalRaces, totalWins, activeCount, }; return this.viewModel; } getViewModel(): DriversLeaderboardViewModel { if (!this.viewModel) { throw new Error('Presenter has not been called yet'); } return this.viewModel; } }