import { RaceService } from '../races/RaceService'; import { ProtestService } from '../protests/ProtestService'; import { PenaltyService } from '../penalties/PenaltyService'; import { DriverService } from '../drivers/DriverService'; import { LeagueMembershipService } from './LeagueMembershipService'; import { LeagueStewardingViewModel, RaceWithProtests } from '../../view-models/LeagueStewardingViewModel'; /** * League Stewarding Service * * Orchestrates league stewarding operations by coordinating calls to race, protest, penalty, driver, and membership services. * All dependencies are injected via constructor. */ export class LeagueStewardingService { constructor( private readonly raceService: RaceService, private readonly protestService: ProtestService, private readonly penaltyService: PenaltyService, private readonly driverService: DriverService, private readonly leagueMembershipService: LeagueMembershipService ) {} /** * Get league stewarding data for all races in a league */ async getLeagueStewardingData(leagueId: string): Promise { // Get all races for this league const leagueRaces = await this.raceService.findByLeagueId(leagueId); // Get protests and penalties for each race const protestsMap: Record = {}; const penaltiesMap: Record = {}; const driverIds = new Set(); for (const race of leagueRaces) { const raceProtests = await this.protestService.findByRaceId(race.id); const racePenalties = await this.penaltyService.findByRaceId(race.id); protestsMap[race.id] = raceProtests; penaltiesMap[race.id] = racePenalties; // Collect driver IDs raceProtests.forEach((p: any) => { driverIds.add(p.protestingDriverId); driverIds.add(p.accusedDriverId); }); racePenalties.forEach((p: any) => { driverIds.add(p.driverId); }); } // Load driver info const driverEntities = await this.driverService.findByIds(Array.from(driverIds)); const driverMap: Record = {}; driverEntities.forEach((driver) => { if (driver) { driverMap[driver.id] = driver; } }); // Compute race data with protest/penalty info const racesWithData: RaceWithProtests[] = leagueRaces.map(race => { const protests = protestsMap[race.id] || []; const penalties = penaltiesMap[race.id] || []; return { race: { id: race.id, track: race.track, scheduledAt: new Date(race.scheduledAt), }, pendingProtests: protests.filter(p => p.status === 'pending' || p.status === 'under_review'), resolvedProtests: protests.filter(p => p.status === 'upheld' || p.status === 'dismissed' || p.status === 'withdrawn'), penalties }; }).sort((a, b) => b.race.scheduledAt.getTime() - a.race.scheduledAt.getTime()); return new LeagueStewardingViewModel(racesWithData, driverMap); } /** * Review a protest */ async reviewProtest(input: { protestId: string; stewardId: string; decision: string; decisionNotes: string }): Promise { await this.protestService.reviewProtest(input); } /** * Apply a penalty */ async applyPenalty(input: any): Promise { await this.penaltyService.applyPenalty(input); } }