/** * Dependency Injection Container * * Initializes all in-memory repositories and provides accessor functions. * Allows easy swapping to persistent repositories later. */ import { Driver } from '@gridpilot/racing/domain/entities/Driver'; import { League } from '@gridpilot/racing/domain/entities/League'; import { Race } from '@gridpilot/racing/domain/entities/Race'; import { Result } from '@gridpilot/racing/domain/entities/Result'; import { Standing } from '@gridpilot/racing/domain/entities/Standing'; import { Game } from '@gridpilot/racing/domain/entities/Game'; import { Season } from '@gridpilot/racing/domain/entities/Season'; import type { IDriverRepository } from '@gridpilot/racing/domain/repositories/IDriverRepository'; import type { ILeagueRepository } from '@gridpilot/racing/domain/repositories/ILeagueRepository'; import type { IRaceRepository } from '@gridpilot/racing/domain/repositories/IRaceRepository'; import type { IResultRepository } from '@gridpilot/racing/domain/repositories/IResultRepository'; import type { IStandingRepository } from '@gridpilot/racing/domain/repositories/IStandingRepository'; import type { IPenaltyRepository } from '@gridpilot/racing/domain/repositories/IPenaltyRepository'; import type { IGameRepository } from '@gridpilot/racing/domain/repositories/IGameRepository'; import type { ISeasonRepository } from '@gridpilot/racing/domain/repositories/ISeasonRepository'; import type { ILeagueScoringConfigRepository } from '@gridpilot/racing/domain/repositories/ILeagueScoringConfigRepository'; import type { ITeamRepository, ITeamMembershipRepository, IRaceRegistrationRepository, } from '@gridpilot/racing'; import type { ILeagueMembershipRepository } from '@gridpilot/racing/domain/repositories/ILeagueMembershipRepository'; import type { LeagueMembership, JoinRequest } from '@gridpilot/racing/domain/entities/LeagueMembership'; import type { IFeedRepository } from '@gridpilot/social/domain/repositories/IFeedRepository'; import type { ISocialGraphRepository } from '@gridpilot/social/domain/repositories/ISocialGraphRepository'; import type { ImageServicePort } from '@gridpilot/media'; import { InMemoryDriverRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryDriverRepository'; import { InMemoryLeagueRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryLeagueRepository'; import { InMemoryRaceRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryRaceRepository'; import { InMemoryResultRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryResultRepository'; import { InMemoryStandingRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryStandingRepository'; import { InMemoryPenaltyRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryPenaltyRepository'; import { InMemoryGameRepository, InMemorySeasonRepository, InMemoryLeagueScoringConfigRepository, getLeagueScoringPresetById, } from '@gridpilot/racing/infrastructure/repositories/InMemoryScoringRepositories'; import { InMemoryLeagueScoringPresetProvider } from '@gridpilot/racing/infrastructure/repositories/InMemoryLeagueScoringPresetProvider'; import { InMemoryTeamRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryTeamRepository'; import { InMemoryTeamMembershipRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryTeamMembershipRepository'; import { InMemoryRaceRegistrationRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryRaceRegistrationRepository'; import { InMemoryLeagueMembershipRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryLeagueMembershipRepository'; import { JoinLeagueUseCase, RegisterForRaceUseCase, WithdrawFromRaceUseCase, IsDriverRegisteredForRaceQuery, GetRaceRegistrationsQuery, CreateTeamUseCase, JoinTeamUseCase, LeaveTeamUseCase, ApproveTeamJoinRequestUseCase, RejectTeamJoinRequestUseCase, UpdateTeamUseCase, GetAllTeamsQuery, GetTeamDetailsQuery, GetTeamMembersQuery, GetTeamJoinRequestsQuery, GetDriverTeamQuery, GetLeagueStandingsQuery, GetLeagueDriverSeasonStatsQuery, GetAllLeaguesWithCapacityQuery, GetAllLeaguesWithCapacityAndScoringQuery, ListLeagueScoringPresetsQuery, GetLeagueScoringConfigQuery, CreateLeagueWithSeasonAndScoringUseCase, GetLeagueFullConfigQuery, } from '@gridpilot/racing/application'; import { createStaticRacingSeed, type RacingSeedData, getDemoLeagueArchetypeByName, } from '@gridpilot/testing-support'; import type { LeagueScheduleDTO, LeagueSchedulePreviewDTO, } from '@gridpilot/racing/application'; import { PreviewLeagueScheduleQuery } from '@gridpilot/racing/application'; import { InMemoryFeedRepository, InMemorySocialGraphRepository, } from '@gridpilot/social/infrastructure/inmemory/InMemorySocialAndFeed'; import { DemoImageServiceAdapter } from '@gridpilot/demo-infrastructure'; import type { LeagueScoringPresetProvider } from '@gridpilot/racing/application/ports/LeagueScoringPresetProvider'; /** * Seed data for development */ /** * Driver statistics and ranking data */ export interface DriverStats { driverId: string; rating: number; totalRaces: number; wins: number; podiums: number; dnfs: number; avgFinish: number; bestFinish: number; worstFinish: number; consistency: number; overallRank: number; percentile: number; } /** * Mock driver stats with calculated rankings */ const driverStats: Record = {}; function createSeedData(): RacingSeedData { const seed = createStaticRacingSeed(42); const { drivers } = seed; drivers.forEach((driver, index) => { const totalRaces = 40 + index * 5; const wins = Math.max(0, Math.floor(totalRaces * 0.2) - index); const podiums = Math.max(wins * 2, 0); const dnfs = Math.max(0, Math.floor(index / 2)); const rating = 1500 + index * 25; driverStats[driver.id] = { driverId: driver.id, rating, totalRaces, wins, podiums, dnfs, avgFinish: 4, bestFinish: 1, worstFinish: 20, consistency: 80, overallRank: index + 1, percentile: Math.max(0, 100 - index), }; }); return seed; } /** * DI Container class */ class DIContainer { private static instance: DIContainer; private _driverRepository: IDriverRepository; private _leagueRepository: ILeagueRepository; private _raceRepository: IRaceRepository; private _resultRepository: IResultRepository; private _standingRepository: IStandingRepository; private _penaltyRepository: IPenaltyRepository; private _teamRepository: ITeamRepository; private _teamMembershipRepository: ITeamMembershipRepository; private _raceRegistrationRepository: IRaceRegistrationRepository; private _leagueMembershipRepository: ILeagueMembershipRepository; private _gameRepository: IGameRepository; private _seasonRepository: ISeasonRepository; private _leagueScoringConfigRepository: ILeagueScoringConfigRepository; private _leagueScoringPresetProvider: LeagueScoringPresetProvider; private _feedRepository: IFeedRepository; private _socialRepository: ISocialGraphRepository; private _imageService: ImageServicePort; // Racing application use-cases / queries private _joinLeagueUseCase: JoinLeagueUseCase; private _registerForRaceUseCase: RegisterForRaceUseCase; private _withdrawFromRaceUseCase: WithdrawFromRaceUseCase; private _isDriverRegisteredForRaceQuery: IsDriverRegisteredForRaceQuery; private _getRaceRegistrationsQuery: GetRaceRegistrationsQuery; private _getLeagueStandingsQuery: GetLeagueStandingsQuery; private _getLeagueDriverSeasonStatsQuery: GetLeagueDriverSeasonStatsQuery; private _getAllLeaguesWithCapacityQuery: GetAllLeaguesWithCapacityQuery; private _getAllLeaguesWithCapacityAndScoringQuery: GetAllLeaguesWithCapacityAndScoringQuery; private _listLeagueScoringPresetsQuery: ListLeagueScoringPresetsQuery; private _getLeagueScoringConfigQuery: GetLeagueScoringConfigQuery; private _createLeagueWithSeasonAndScoringUseCase: CreateLeagueWithSeasonAndScoringUseCase; private _getLeagueFullConfigQuery: GetLeagueFullConfigQuery; // Placeholder for future schedule preview wiring private _previewLeagueScheduleQuery: PreviewLeagueScheduleQuery; private _createTeamUseCase: CreateTeamUseCase; private _joinTeamUseCase: JoinTeamUseCase; private _leaveTeamUseCase: LeaveTeamUseCase; private _approveTeamJoinRequestUseCase: ApproveTeamJoinRequestUseCase; private _rejectTeamJoinRequestUseCase: RejectTeamJoinRequestUseCase; private _updateTeamUseCase: UpdateTeamUseCase; private _getAllTeamsQuery: GetAllTeamsQuery; private _getTeamDetailsQuery: GetTeamDetailsQuery; private _getTeamMembersQuery: GetTeamMembersQuery; private _getTeamJoinRequestsQuery: GetTeamJoinRequestsQuery; private _getDriverTeamQuery: GetDriverTeamQuery; private constructor() { // Create seed data const seedData = createSeedData(); const primaryDriverId = seedData.drivers[0]?.id ?? 'driver-1'; // Initialize repositories with seed data this._driverRepository = new InMemoryDriverRepository(seedData.drivers); this._leagueRepository = new InMemoryLeagueRepository(seedData.leagues); this._raceRepository = new InMemoryRaceRepository(seedData.races); // Result repository needs race repository for league-based queries this._resultRepository = new InMemoryResultRepository( seedData.results, this._raceRepository ); // Standing repository needs all three for recalculation this._standingRepository = new InMemoryStandingRepository( seedData.standings, this._resultRepository, this._raceRepository, this._leagueRepository ); // Race registrations (start empty; populated via use-cases) this._raceRegistrationRepository = new InMemoryRaceRegistrationRepository(); // Penalties (seeded in-memory adapter) this._penaltyRepository = new InMemoryPenaltyRepository(); // Scoring preset provider and seeded game/season/scoring config repositories this._leagueScoringPresetProvider = new InMemoryLeagueScoringPresetProvider(); const game = Game.create({ id: 'iracing', name: 'iRacing' }); const seededSeasons: Season[] = []; const seededScoringConfigs = []; for (const league of seedData.leagues) { const archetype = getDemoLeagueArchetypeByName(league.name); if (!archetype) continue; const season = Season.create({ id: `season-${league.id}-demo`, leagueId: league.id, gameId: game.id, name: `${league.name} Demo Season`, year: new Date().getFullYear(), order: 1, status: 'active', startDate: new Date(), endDate: new Date(), }); seededSeasons.push(season); const infraPreset = getLeagueScoringPresetById( archetype.scoringPresetId, ); if (!infraPreset) { // If a preset is missing, skip scoring config for this league in alpha seed. continue; } const config = infraPreset.createConfig({ seasonId: season.id }); seededScoringConfigs.push(config); } this._gameRepository = new InMemoryGameRepository([game]); this._seasonRepository = new InMemorySeasonRepository(seededSeasons); this._leagueScoringConfigRepository = new InMemoryLeagueScoringConfigRepository(seededScoringConfigs); // League memberships seeded from static memberships with guaranteed owner roles const seededMemberships: LeagueMembership[] = seedData.memberships.map((m) => ({ leagueId: m.leagueId, driverId: m.driverId, role: 'member', status: 'active', joinedAt: new Date(), })); // Ensure each league owner has an owner membership for (const league of seedData.leagues) { const existing = seededMemberships.find( (m) => m.leagueId === league.id && m.driverId === league.ownerId, ); if (!existing) { seededMemberships.push({ leagueId: league.id, driverId: league.ownerId, role: 'owner', status: 'active', joinedAt: new Date(), }); } else { existing.role = 'owner'; } } // Ensure the primary demo driver owns at least one league in memberships const hasPrimaryOwnerMembership = seededMemberships.some( (m: LeagueMembership) => m.driverId === primaryDriverId && m.role === 'owner', ); if (!hasPrimaryOwnerMembership && seedData.leagues.length > 0) { const targetLeague = seedData.leagues.find((l) => l.ownerId === primaryDriverId) ?? seedData.leagues[0]; const existingForPrimary = seededMemberships.find( (m) => m.leagueId === targetLeague.id && m.driverId === primaryDriverId, ); if (existingForPrimary) { existingForPrimary.role = 'owner'; } else { seededMemberships.push({ leagueId: targetLeague.id, driverId: primaryDriverId, role: 'owner', status: 'active', joinedAt: new Date(), }); } } // Seed sample league admins for the primary driver's league (alpha demo) const primaryLeagueForAdmins = seedData.leagues.find((l) => l.ownerId === primaryDriverId) ?? seedData.leagues[0]; if (primaryLeagueForAdmins) { const adminCandidates = seedData.drivers .filter((d) => d.id !== primaryLeagueForAdmins.ownerId) .slice(0, 2); adminCandidates.forEach((driver) => { const existing = seededMemberships.find( (m) => m.leagueId === primaryLeagueForAdmins.id && m.driverId === driver.id, ); if (existing) { if (existing.role !== 'owner') { existing.role = 'admin'; } } else { seededMemberships.push({ leagueId: primaryLeagueForAdmins.id, driverId: driver.id, role: 'admin', status: 'active', joinedAt: new Date(), }); } }); } // Seed a few pending join requests for demo leagues const seededJoinRequests: JoinRequest[] = []; const demoLeagues = seedData.leagues.slice(0, 2); const extraDrivers = seedData.drivers.slice(3, 8); demoLeagues.forEach((league) => { extraDrivers.forEach((driver, index) => { seededJoinRequests.push({ id: `join-${league.id}-${driver.id}`, leagueId: league.id, driverId: driver.id, requestedAt: new Date(Date.now() - (index + 1) * 24 * 60 * 60 * 1000), message: index % 2 === 0 ? 'Would love to race in this series!' : 'Looking to join for the upcoming season.', }); }); }); this._leagueMembershipRepository = new InMemoryLeagueMembershipRepository( seededMemberships, seededJoinRequests, ); // Team repositories seeded from static memberships/teams this._teamRepository = new InMemoryTeamRepository( seedData.teams.map((t) => ({ id: t.id, name: t.name, tag: t.tag, description: t.description, ownerId: seedData.drivers[0]?.id ?? 'driver-1', leagues: [t.primaryLeagueId], createdAt: new Date(), })), ); this._teamMembershipRepository = new InMemoryTeamMembershipRepository( seedData.memberships .filter((m) => m.teamId) .map((m) => ({ teamId: m.teamId!, driverId: m.driverId, role: 'driver', status: 'active', joinedAt: new Date(), })), ); // Application-layer use-cases and queries wired with repositories this._joinLeagueUseCase = new JoinLeagueUseCase(this._leagueMembershipRepository); this._registerForRaceUseCase = new RegisterForRaceUseCase( this._raceRegistrationRepository, this._leagueMembershipRepository, ); this._withdrawFromRaceUseCase = new WithdrawFromRaceUseCase( this._raceRegistrationRepository, ); this._isDriverRegisteredForRaceQuery = new IsDriverRegisteredForRaceQuery( this._raceRegistrationRepository, ); this._getRaceRegistrationsQuery = new GetRaceRegistrationsQuery( this._raceRegistrationRepository, ); this._getLeagueStandingsQuery = new GetLeagueStandingsQuery(this._standingRepository); this._getLeagueDriverSeasonStatsQuery = new GetLeagueDriverSeasonStatsQuery( this._standingRepository, this._resultRepository, this._penaltyRepository, { getRating: (driverId: string) => { const stats = driverStats[driverId]; if (!stats) { return { rating: null, ratingChange: null }; } // For alpha we expose current rating and a mock delta const baseline = 1500; const delta = stats.rating - baseline; return { rating: stats.rating, ratingChange: delta !== 0 ? delta : null, }; }, }, ); this._getAllLeaguesWithCapacityQuery = new GetAllLeaguesWithCapacityQuery( this._leagueRepository, this._leagueMembershipRepository, ); this._getAllLeaguesWithCapacityAndScoringQuery = new GetAllLeaguesWithCapacityAndScoringQuery( this._leagueRepository, this._leagueMembershipRepository, this._seasonRepository, this._leagueScoringConfigRepository, this._gameRepository, this._leagueScoringPresetProvider, ); this._listLeagueScoringPresetsQuery = new ListLeagueScoringPresetsQuery( this._leagueScoringPresetProvider, ); this._getLeagueScoringConfigQuery = new GetLeagueScoringConfigQuery( this._leagueRepository, this._seasonRepository, this._leagueScoringConfigRepository, this._gameRepository, this._leagueScoringPresetProvider, ); this._getLeagueFullConfigQuery = new GetLeagueFullConfigQuery( this._leagueRepository, this._seasonRepository, this._leagueScoringConfigRepository, this._gameRepository, ); this._createLeagueWithSeasonAndScoringUseCase = new CreateLeagueWithSeasonAndScoringUseCase( this._leagueRepository, this._seasonRepository, this._leagueScoringConfigRepository, this._leagueScoringPresetProvider, ); // Schedule preview query (used by league creation wizard step 3) this._previewLeagueScheduleQuery = new PreviewLeagueScheduleQuery(); this._createTeamUseCase = new CreateTeamUseCase( this._teamRepository, this._teamMembershipRepository, ); this._joinTeamUseCase = new JoinTeamUseCase( this._teamRepository, this._teamMembershipRepository, ); this._leaveTeamUseCase = new LeaveTeamUseCase(this._teamMembershipRepository); this._approveTeamJoinRequestUseCase = new ApproveTeamJoinRequestUseCase( this._teamMembershipRepository, ); this._rejectTeamJoinRequestUseCase = new RejectTeamJoinRequestUseCase( this._teamMembershipRepository, ); this._updateTeamUseCase = new UpdateTeamUseCase( this._teamRepository, this._teamMembershipRepository, ); this._getAllTeamsQuery = new GetAllTeamsQuery(this._teamRepository); this._getTeamDetailsQuery = new GetTeamDetailsQuery( this._teamRepository, this._teamMembershipRepository, ); this._getTeamMembersQuery = new GetTeamMembersQuery(this._teamMembershipRepository); this._getTeamJoinRequestsQuery = new GetTeamJoinRequestsQuery( this._teamMembershipRepository, ); this._getDriverTeamQuery = new GetDriverTeamQuery( this._teamRepository, this._teamMembershipRepository, ); // Social and feed adapters backed by static seed this._feedRepository = new InMemoryFeedRepository(seedData); this._socialRepository = new InMemorySocialGraphRepository(seedData); // Image service backed by demo adapter this._imageService = new DemoImageServiceAdapter(); } /** * Get singleton instance */ static getInstance(): DIContainer { if (!DIContainer.instance) { DIContainer.instance = new DIContainer(); } return DIContainer.instance; } /** * Reset the container (useful for testing) */ static reset(): void { DIContainer.instance = new DIContainer(); } /** * Repository getters */ get driverRepository(): IDriverRepository { return this._driverRepository; } get leagueRepository(): ILeagueRepository { return this._leagueRepository; } get raceRepository(): IRaceRepository { return this._raceRepository; } get resultRepository(): IResultRepository { return this._resultRepository; } get standingRepository(): IStandingRepository { return this._standingRepository; } get penaltyRepository(): IPenaltyRepository { return this._penaltyRepository; } get raceRegistrationRepository(): IRaceRegistrationRepository { return this._raceRegistrationRepository; } get leagueMembershipRepository(): ILeagueMembershipRepository { return this._leagueMembershipRepository; } get gameRepository(): IGameRepository { return this._gameRepository; } get seasonRepository(): ISeasonRepository { return this._seasonRepository; } get leagueScoringConfigRepository(): ILeagueScoringConfigRepository { return this._leagueScoringConfigRepository; } get leagueScoringPresetProvider(): LeagueScoringPresetProvider { return this._leagueScoringPresetProvider; } get joinLeagueUseCase(): JoinLeagueUseCase { return this._joinLeagueUseCase; } get registerForRaceUseCase(): RegisterForRaceUseCase { return this._registerForRaceUseCase; } get withdrawFromRaceUseCase(): WithdrawFromRaceUseCase { return this._withdrawFromRaceUseCase; } get isDriverRegisteredForRaceQuery(): IsDriverRegisteredForRaceQuery { return this._isDriverRegisteredForRaceQuery; } get getRaceRegistrationsQuery(): GetRaceRegistrationsQuery { return this._getRaceRegistrationsQuery; } get getLeagueStandingsQuery(): GetLeagueStandingsQuery { return this._getLeagueStandingsQuery; } get getLeagueDriverSeasonStatsQuery(): GetLeagueDriverSeasonStatsQuery { return this._getLeagueDriverSeasonStatsQuery; } get getAllLeaguesWithCapacityQuery(): GetAllLeaguesWithCapacityQuery { return this._getAllLeaguesWithCapacityQuery; } get getAllLeaguesWithCapacityAndScoringQuery(): GetAllLeaguesWithCapacityAndScoringQuery { return this._getAllLeaguesWithCapacityAndScoringQuery; } get listLeagueScoringPresetsQuery(): ListLeagueScoringPresetsQuery { return this._listLeagueScoringPresetsQuery; } get getLeagueScoringConfigQuery(): GetLeagueScoringConfigQuery { return this._getLeagueScoringConfigQuery; } get getLeagueFullConfigQuery(): GetLeagueFullConfigQuery { return this._getLeagueFullConfigQuery; } // Placeholder accessor for schedule preview; API route/UI can call this later. get previewLeagueScheduleQuery(): PreviewLeagueScheduleQuery { return this._previewLeagueScheduleQuery; } get createLeagueWithSeasonAndScoringUseCase(): CreateLeagueWithSeasonAndScoringUseCase { return this._createLeagueWithSeasonAndScoringUseCase; } get createTeamUseCase(): CreateTeamUseCase { return this._createTeamUseCase; } get joinTeamUseCase(): JoinTeamUseCase { return this._joinTeamUseCase; } get leaveTeamUseCase(): LeaveTeamUseCase { return this._leaveTeamUseCase; } get approveTeamJoinRequestUseCase(): ApproveTeamJoinRequestUseCase { return this._approveTeamJoinRequestUseCase; } get rejectTeamJoinRequestUseCase(): RejectTeamJoinRequestUseCase { return this._rejectTeamJoinRequestUseCase; } get updateTeamUseCase(): UpdateTeamUseCase { return this._updateTeamUseCase; } get getAllTeamsQuery(): GetAllTeamsQuery { return this._getAllTeamsQuery; } get getTeamDetailsQuery(): GetTeamDetailsQuery { return this._getTeamDetailsQuery; } get getTeamMembersQuery(): GetTeamMembersQuery { return this._getTeamMembersQuery; } get getTeamJoinRequestsQuery(): GetTeamJoinRequestsQuery { return this._getTeamJoinRequestsQuery; } get getDriverTeamQuery(): GetDriverTeamQuery { return this._getDriverTeamQuery; } get teamRepository(): ITeamRepository { return this._teamRepository; } get teamMembershipRepository(): ITeamMembershipRepository { return this._teamMembershipRepository; } get feedRepository(): IFeedRepository { return this._feedRepository; } get socialRepository(): ISocialGraphRepository { return this._socialRepository; } get imageService(): ImageServicePort { return this._imageService; } } /** * Exported accessor functions */ export function getDriverRepository(): IDriverRepository { return DIContainer.getInstance().driverRepository; } export function getLeagueRepository(): ILeagueRepository { return DIContainer.getInstance().leagueRepository; } export function getRaceRepository(): IRaceRepository { return DIContainer.getInstance().raceRepository; } export function getResultRepository(): IResultRepository { return DIContainer.getInstance().resultRepository; } export function getStandingRepository(): IStandingRepository { return DIContainer.getInstance().standingRepository; } export function getPenaltyRepository(): IPenaltyRepository { return DIContainer.getInstance().penaltyRepository; } export function getRaceRegistrationRepository(): IRaceRegistrationRepository { return DIContainer.getInstance().raceRegistrationRepository; } export function getLeagueMembershipRepository(): ILeagueMembershipRepository { return DIContainer.getInstance().leagueMembershipRepository; } export function getJoinLeagueUseCase(): JoinLeagueUseCase { return DIContainer.getInstance().joinLeagueUseCase; } export function getRegisterForRaceUseCase(): RegisterForRaceUseCase { return DIContainer.getInstance().registerForRaceUseCase; } export function getWithdrawFromRaceUseCase(): WithdrawFromRaceUseCase { return DIContainer.getInstance().withdrawFromRaceUseCase; } export function getIsDriverRegisteredForRaceQuery(): IsDriverRegisteredForRaceQuery { return DIContainer.getInstance().isDriverRegisteredForRaceQuery; } export function getGetRaceRegistrationsQuery(): GetRaceRegistrationsQuery { return DIContainer.getInstance().getRaceRegistrationsQuery; } export function getGetLeagueStandingsQuery(): GetLeagueStandingsQuery { return DIContainer.getInstance().getLeagueStandingsQuery; } export function getGetLeagueDriverSeasonStatsQuery(): GetLeagueDriverSeasonStatsQuery { return DIContainer.getInstance().getLeagueDriverSeasonStatsQuery; } export function getGetAllLeaguesWithCapacityQuery(): GetAllLeaguesWithCapacityQuery { return DIContainer.getInstance().getAllLeaguesWithCapacityQuery; } export function getGetAllLeaguesWithCapacityAndScoringQuery(): GetAllLeaguesWithCapacityAndScoringQuery { return DIContainer.getInstance().getAllLeaguesWithCapacityAndScoringQuery; } export function getGetLeagueScoringConfigQuery(): GetLeagueScoringConfigQuery { return DIContainer.getInstance().getLeagueScoringConfigQuery; } export function getGetLeagueFullConfigQuery(): GetLeagueFullConfigQuery { return DIContainer.getInstance().getLeagueFullConfigQuery; } // Placeholder export for future schedule preview API wiring. export function getPreviewLeagueScheduleQuery(): PreviewLeagueScheduleQuery { return DIContainer.getInstance().previewLeagueScheduleQuery; } export function getListLeagueScoringPresetsQuery(): ListLeagueScoringPresetsQuery { return DIContainer.getInstance().listLeagueScoringPresetsQuery; } export function getCreateLeagueWithSeasonAndScoringUseCase(): CreateLeagueWithSeasonAndScoringUseCase { return DIContainer.getInstance().createLeagueWithSeasonAndScoringUseCase; } export function getTeamRepository(): ITeamRepository { return DIContainer.getInstance().teamRepository; } export function getTeamMembershipRepository(): ITeamMembershipRepository { return DIContainer.getInstance().teamMembershipRepository; } export function getCreateTeamUseCase(): CreateTeamUseCase { return DIContainer.getInstance().createTeamUseCase; } export function getJoinTeamUseCase(): JoinTeamUseCase { return DIContainer.getInstance().joinTeamUseCase; } export function getLeaveTeamUseCase(): LeaveTeamUseCase { return DIContainer.getInstance().leaveTeamUseCase; } export function getApproveTeamJoinRequestUseCase(): ApproveTeamJoinRequestUseCase { return DIContainer.getInstance().approveTeamJoinRequestUseCase; } export function getRejectTeamJoinRequestUseCase(): RejectTeamJoinRequestUseCase { return DIContainer.getInstance().rejectTeamJoinRequestUseCase; } export function getUpdateTeamUseCase(): UpdateTeamUseCase { return DIContainer.getInstance().updateTeamUseCase; } export function getGetAllTeamsQuery(): GetAllTeamsQuery { return DIContainer.getInstance().getAllTeamsQuery; } export function getGetTeamDetailsQuery(): GetTeamDetailsQuery { return DIContainer.getInstance().getTeamDetailsQuery; } export function getGetTeamMembersQuery(): GetTeamMembersQuery { return DIContainer.getInstance().getTeamMembersQuery; } export function getGetTeamJoinRequestsQuery(): GetTeamJoinRequestsQuery { return DIContainer.getInstance().getTeamJoinRequestsQuery; } export function getGetDriverTeamQuery(): GetDriverTeamQuery { return DIContainer.getInstance().getDriverTeamQuery; } export function getFeedRepository(): IFeedRepository { return DIContainer.getInstance().feedRepository; } export function getSocialRepository(): ISocialGraphRepository { return DIContainer.getInstance().socialRepository; } export function getImageService(): ImageServicePort { return DIContainer.getInstance().imageService; } /** * Reset function for testing */ export function resetContainer(): void { DIContainer.reset(); } /** * Get driver statistics and rankings */ export function getDriverStats(driverId: string): DriverStats | null { return driverStats[driverId] || null; } /** * Get all driver rankings sorted by rating */ export function getAllDriverRankings(): DriverStats[] { return Object.values(driverStats).sort((a, b) => b.rating - a.rating); } /** * Get league-specific rankings for a driver */ export function getLeagueRankings(driverId: string, leagueId: string): { rank: number; totalDrivers: number; percentile: number; } { // Mock league rankings (in production, calculate from actual league membership) const mockLeagueRanks: Record> = { 'league-1': { 'driver-1': { rank: 1, totalDrivers: 12, percentile: 92 }, 'driver-2': { rank: 2, totalDrivers: 12, percentile: 84 }, 'driver-3': { rank: 4, totalDrivers: 12, percentile: 67 }, 'driver-4': { rank: 5, totalDrivers: 12, percentile: 58 } } }; return mockLeagueRanks[leagueId]?.[driverId] || { rank: 0, totalDrivers: 0, percentile: 0 }; }