import type { LeagueVisibilityType } from '../../domain/value-objects/LeagueVisibility'; import type { StewardingDecisionMode } from '../../domain/entities/League'; export type LeagueStructureMode = 'solo' | 'fixedTeams'; /** * League visibility determines public visibility and ranking status. * - 'ranked': Public, competitive, affects driver ratings. Requires min 10 drivers. * - 'unranked': Private, casual with friends. No rating impact. Any number of drivers. * * For backward compatibility, 'public'/'private' are also supported in the form, * but the domain uses 'ranked'/'unranked'. */ export type LeagueVisibilityFormValue = LeagueVisibilityType | 'public' | 'private'; export interface LeagueStructureFormDTO { mode: LeagueStructureMode; maxDrivers: number; maxTeams?: number; driversPerTeam?: number; multiClassEnabled?: boolean; } export interface LeagueChampionshipsFormDTO { enableDriverChampionship: boolean; enableTeamChampionship: boolean; enableNationsChampionship: boolean; enableTrophyChampionship: boolean; } export interface LeagueScoringFormDTO { patternId?: string; // e.g. 'sprint-main-driver', 'club-ladder-solo' // For now, keep customScoring optional and simple: customScoringEnabled?: boolean; } export interface LeagueDropPolicyFormDTO { strategy: 'none' | 'bestNResults' | 'dropWorstN'; n?: number; } export interface LeagueTimingsFormDTO { practiceMinutes?: number; qualifyingMinutes: number; sprintRaceMinutes?: number; mainRaceMinutes: number; sessionCount: number; roundsPlanned?: number; seasonStartDate?: string; // ISO date YYYY-MM-DD seasonEndDate?: string; // ISO date YYYY-MM-DD raceStartTime?: string; // "HH:MM" 24h timezoneId?: string; // IANA ID, e.g. "Europe/Berlin", or "track" for track local time recurrenceStrategy?: 'weekly' | 'everyNWeeks' | 'monthlyNthWeekday'; intervalWeeks?: number; weekdays?: import('../../domain/types/Weekday').Weekday[]; monthlyOrdinal?: 1 | 2 | 3 | 4; monthlyWeekday?: import('../../domain/types/Weekday').Weekday; } /** * Stewarding configuration for protests and penalties. */ export interface LeagueStewardingFormDTO { /** * How protest decisions are made */ decisionMode: StewardingDecisionMode; /** * Number of votes required to uphold/reject a protest * Used with steward_vote, member_vote, steward_veto, member_veto modes */ requiredVotes?: number; /** * Whether to require a defense from the accused before deciding */ requireDefense: boolean; /** * Time limit (hours) for accused to submit defense */ defenseTimeLimit: number; /** * Time limit (hours) for voting to complete */ voteTimeLimit: number; /** * Time limit (hours) after race ends when protests can be filed */ protestDeadlineHours: number; /** * Time limit (hours) after race ends when stewarding is closed */ stewardingClosesHours: number; /** * Whether to notify the accused when a protest is filed */ notifyAccusedOnProtest: boolean; /** * Whether to notify eligible voters when a vote is required */ notifyOnVoteRequired: boolean; } export interface LeagueConfigFormModel { leagueId?: string; // present for admin, omitted for create basics: { name: string; description?: string; /** * League visibility/ranking mode. * - 'ranked' (or legacy 'public'): Competitive, public, affects ratings. Min 10 drivers. * - 'unranked' (or legacy 'private'): Casual with friends, no rating impact. */ visibility: LeagueVisibilityFormValue; gameId: string; /** * League logo as base64 data URL (optional). * Format: data:image/png;base64,... or data:image/jpeg;base64,... */ logoDataUrl?: string; }; structure: LeagueStructureFormDTO; championships: LeagueChampionshipsFormDTO; scoring: LeagueScoringFormDTO; dropPolicy: LeagueDropPolicyFormDTO; timings: LeagueTimingsFormDTO; stewarding: LeagueStewardingFormDTO; } /** * Helper to normalize visibility values to new terminology. * Maps 'public' -> 'ranked' and 'private' -> 'unranked'. */ export function normalizeVisibility(value: LeagueVisibilityFormValue): LeagueVisibilityType { if (value === 'public' || value === 'ranked') return 'ranked'; return 'unranked'; } /** * Helper to convert new terminology to legacy for backward compatibility. * Maps 'ranked' -> 'public' and 'unranked' -> 'private'. */ export function toLegacyVisibility(value: LeagueVisibilityFormValue): 'public' | 'private' { if (value === 'ranked' || value === 'public') return 'public'; return 'private'; }