import type { DropScorePolicy } from '@gridpilot/racing/domain/types/DropScorePolicy'; import type { ILeagueFullConfigPresenter, LeagueFullConfigData, LeagueConfigFormViewModel, } from '@gridpilot/racing/application/presenters/ILeagueFullConfigPresenter'; export class LeagueFullConfigPresenter implements ILeagueFullConfigPresenter { private viewModel: LeagueConfigFormViewModel | null = null; reset(): void { this.viewModel = null; } present(data: LeagueFullConfigData): void { const { league, activeSeason, scoringConfig, game } = data; const patternId = scoringConfig?.scoringPresetId; const primaryChampionship = scoringConfig && scoringConfig.championships && scoringConfig.championships.length > 0 ? scoringConfig.championships[0] : undefined; const dropPolicy = primaryChampionship?.dropScorePolicy ?? undefined; const dropPolicyForm = this.mapDropPolicy(dropPolicy); const defaultQualifyingMinutes = 30; const defaultMainRaceMinutes = 40; const mainRaceMinutes = typeof league.settings.sessionDuration === 'number' ? league.settings.sessionDuration : defaultMainRaceMinutes; const qualifyingMinutes = defaultQualifyingMinutes; const roundsPlanned = 8; let sessionCount = 2; if (primaryChampionship && Array.isArray(primaryChampionship.sessionTypes)) { sessionCount = primaryChampionship.sessionTypes.length; } const practiceMinutes = 20; const sprintRaceMinutes = patternId === 'sprint-main-driver' ? 20 : undefined; this.viewModel = { leagueId: league.id, basics: { name: league.name, description: league.description, visibility: 'public', gameId: game?.id ?? 'iracing', }, structure: { mode: 'solo', maxDrivers: league.settings.maxDrivers ?? 32, multiClassEnabled: false, }, championships: { enableDriverChampionship: true, enableTeamChampionship: false, enableNationsChampionship: false, enableTrophyChampionship: false, }, scoring: { customScoringEnabled: !patternId, ...(patternId ? { patternId } : {}), }, dropPolicy: dropPolicyForm, timings: { practiceMinutes, qualifyingMinutes, mainRaceMinutes, sessionCount, roundsPlanned, ...(typeof sprintRaceMinutes === 'number' ? { sprintRaceMinutes } : {}), }, stewarding: { decisionMode: 'admin_only', requireDefense: true, defenseTimeLimit: 48, voteTimeLimit: 72, protestDeadlineHours: 72, stewardingClosesHours: 168, notifyAccusedOnProtest: true, notifyOnVoteRequired: true, }, }; } getViewModel(): LeagueConfigFormViewModel | null { if (!this.viewModel) { throw new Error('Presenter has not been called yet'); } return this.viewModel; } private mapDropPolicy(policy: DropScorePolicy | undefined): { strategy: string; n?: number } { if (!policy || policy.strategy === 'none') { return { strategy: 'none' }; } if (policy.strategy === 'bestNResults') { const n = typeof policy.count === 'number' ? policy.count : undefined; return n !== undefined ? { strategy: 'bestNResults', n } : { strategy: 'none' }; } if (policy.strategy === 'dropWorstN') { const n = typeof policy.dropCount === 'number' ? policy.dropCount : undefined; return n !== undefined ? { strategy: 'dropWorstN', n } : { strategy: 'none' }; } return { strategy: 'none' }; } }