/** * 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 type { IDriverRepository } from '@gridpilot/racing-domain/ports/IDriverRepository'; import type { ILeagueRepository } from '@gridpilot/racing-domain/ports/ILeagueRepository'; import type { IRaceRepository } from '@gridpilot/racing-domain/ports/IRaceRepository'; import type { IResultRepository } from '@gridpilot/racing-domain/ports/IResultRepository'; import type { IStandingRepository } from '@gridpilot/racing-domain/ports/IStandingRepository'; 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'; /** * 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() { // Create sample drivers (matching membership-data.ts and team-data.ts) const driver1 = Driver.create({ id: 'driver-1', iracingId: '123456', name: 'Max Verstappen', country: 'NL', bio: 'Three-time world champion and team owner of Apex Racing', joinedAt: new Date('2024-01-15'), }); const driver2 = Driver.create({ id: 'driver-2', iracingId: '234567', name: 'Lewis Hamilton', country: 'GB', bio: 'Seven-time world champion leading Speed Demons', joinedAt: new Date('2024-01-20'), }); const driver3 = Driver.create({ id: 'driver-3', iracingId: '345678', name: 'Charles Leclerc', country: 'MC', bio: 'Ferrari race winner and Weekend Warriors team owner', joinedAt: new Date('2024-02-01'), }); const driver4 = Driver.create({ id: 'driver-4', iracingId: '456789', name: 'Lando Norris', country: 'GB', bio: 'Rising star in motorsport', joinedAt: new Date('2024-02-15'), }); // Initialize driver stats driverStats['driver-1'] = { driverId: 'driver-1', rating: 3245, totalRaces: 156, wins: 45, podiums: 89, dnfs: 8, avgFinish: 3.2, bestFinish: 1, worstFinish: 18, consistency: 87, overallRank: 1, percentile: 99 }; driverStats['driver-2'] = { driverId: 'driver-2', rating: 3198, totalRaces: 234, wins: 78, podiums: 145, dnfs: 12, avgFinish: 2.8, bestFinish: 1, worstFinish: 22, consistency: 92, overallRank: 2, percentile: 98 }; driverStats['driver-3'] = { driverId: 'driver-3', rating: 2912, totalRaces: 145, wins: 34, podiums: 67, dnfs: 9, avgFinish: 4.5, bestFinish: 1, worstFinish: 20, consistency: 84, overallRank: 3, percentile: 96 }; driverStats['driver-4'] = { driverId: 'driver-4', rating: 2789, totalRaces: 112, wins: 23, podiums: 56, dnfs: 7, avgFinish: 5.1, bestFinish: 1, worstFinish: 16, consistency: 81, overallRank: 5, percentile: 93 }; // Create sample league (matching membership-data.ts) const league1 = League.create({ id: 'league-1', name: 'European GT Championship', description: 'Weekly GT3 racing with professional drivers', ownerId: driver1.id, settings: { pointsSystem: 'f1-2024', sessionDuration: 60, qualifyingFormat: 'open', }, createdAt: new Date('2024-01-20'), }); // Create sample races const race1 = Race.create({ id: 'race-1', leagueId: league1.id, scheduledAt: new Date('2024-03-15T19:00:00Z'), track: 'Monza GP', car: 'Porsche 911 GT3 R', sessionType: 'race', status: 'completed', }); const race2 = Race.create({ id: 'race-2', leagueId: league1.id, scheduledAt: new Date('2024-03-22T19:00:00Z'), track: 'Spa-Francorchamps', car: 'Porsche 911 GT3 R', sessionType: 'race', status: 'scheduled', }); const race3 = Race.create({ id: 'race-3', leagueId: league1.id, scheduledAt: new Date('2024-04-05T19:00:00Z'), track: 'Nürburgring GP', car: 'Porsche 911 GT3 R', sessionType: 'race', status: 'scheduled', }); // Create sample standings const standing1 = Standing.create({ leagueId: league1.id, driverId: driver1.id, position: 1, points: 25, wins: 1, racesCompleted: 1, }); const standing2 = Standing.create({ leagueId: league1.id, driverId: driver2.id, position: 2, points: 18, wins: 0, racesCompleted: 1, }); const standing3 = Standing.create({ leagueId: league1.id, driverId: driver3.id, position: 3, points: 15, wins: 0, racesCompleted: 1, }); const standing4 = Standing.create({ leagueId: league1.id, driverId: driver4.id, position: 4, points: 12, wins: 0, racesCompleted: 1, }); return { drivers: [driver1, driver2, driver3, driver4], leagues: [league1], races: [race1, race2, race3], standings: [standing1, standing2, standing3, standing4], }; } /** * 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 constructor() { // Create seed data const seedData = createSeedData(); // 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( undefined, this._raceRepository ); // Standing repository needs all three for recalculation this._standingRepository = new InMemoryStandingRepository( seedData.standings, this._resultRepository, this._raceRepository, this._leagueRepository ); } /** * 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; } } /** * 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; } /** * 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 }; }