/** * 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/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 { IFeedRepository } from '@gridpilot/social/domain/repositories/IFeedRepository'; import type { ISocialGraphRepository } from '@gridpilot/social/domain/repositories/ISocialGraphRepository'; 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 { createStaticRacingSeed, type RacingSeedData } from '@gridpilot/testing-support'; import { InMemoryFeedRepository, InMemorySocialGraphRepository, } from '@gridpilot/social/infrastructure/inmemory/InMemorySocialAndFeed'; /** * 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 _feedRepository: IFeedRepository; private _socialRepository: ISocialGraphRepository; 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( seedData.results, this._raceRepository ); // Standing repository needs all three for recalculation this._standingRepository = new InMemoryStandingRepository( seedData.standings, this._resultRepository, this._raceRepository, this._leagueRepository ); // Social and feed adapters backed by static seed this._feedRepository = new InMemoryFeedRepository(seedData); this._socialRepository = new InMemorySocialGraphRepository(seedData); } /** * 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 feedRepository(): IFeedRepository { return this._feedRepository; } get socialRepository(): ISocialGraphRepository { return this._socialRepository; } } /** * 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 getFeedRepository(): IFeedRepository { return DIContainer.getInstance().feedRepository; } export function getSocialRepository(): ISocialGraphRepository { return DIContainer.getInstance().socialRepository; } /** * 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 }; }