118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
import { injectable, unmanaged } from 'inversify';
|
|
import { Result } from '@/lib/contracts/Result';
|
|
import { Service, type DomainError } from '@/lib/contracts/services/Service';
|
|
import { type StewardingApiDto } from '@/lib/types/tbd/StewardingApiDto';
|
|
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 } from '@/lib/view-models/LeagueStewardingViewModel';
|
|
|
|
@injectable()
|
|
export class LeagueStewardingService implements Service {
|
|
constructor(
|
|
@unmanaged() private readonly raceService?: RaceService,
|
|
@unmanaged() private readonly protestService?: ProtestService,
|
|
@unmanaged() private readonly penaltyService?: PenaltyService,
|
|
@unmanaged() private readonly driverService?: DriverService,
|
|
@unmanaged() private readonly leagueMembershipService?: LeagueMembershipService,
|
|
) {}
|
|
|
|
async getLeagueStewardingData(leagueId: string): Promise<LeagueStewardingViewModel> {
|
|
if (!this.raceService || !this.protestService || !this.penaltyService || !this.driverService) {
|
|
return new LeagueStewardingViewModel([], {});
|
|
}
|
|
|
|
const racesRes = await this.raceService.findByLeagueId(leagueId);
|
|
const races = (racesRes as any).value || racesRes;
|
|
const racesWithData = await Promise.all(
|
|
races.map(async (race: any) => {
|
|
const [protestsRes, penaltiesRes] = await Promise.all([
|
|
this.protestService!.findByRaceId(race.id),
|
|
this.penaltyService!.findByRaceId(race.id),
|
|
]);
|
|
const protests = (protestsRes as any).value || protestsRes;
|
|
const penalties = (penaltiesRes as any).value || penaltiesRes;
|
|
return {
|
|
race: {
|
|
id: race.id,
|
|
track: race.track,
|
|
scheduledAt: new Date(race.scheduledAt),
|
|
},
|
|
pendingProtests: protests.filter((p: any) => p.status === 'pending' || p.status === 'under_review'),
|
|
resolvedProtests: protests.filter((p: any) => p.status !== 'pending' && p.status !== 'under_review'),
|
|
penalties: penalties,
|
|
};
|
|
}),
|
|
);
|
|
|
|
const driverIds = new Set<string>();
|
|
racesWithData.forEach((r: any) => {
|
|
r.pendingProtests.forEach((p: any) => {
|
|
driverIds.add(p.protestingDriverId);
|
|
driverIds.add(p.accusedDriverId);
|
|
});
|
|
r.resolvedProtests.forEach((p: any) => {
|
|
driverIds.add(p.protestingDriverId);
|
|
driverIds.add(p.accusedDriverId);
|
|
});
|
|
r.penalties.forEach((p: any) => driverIds.add(p.driverId));
|
|
});
|
|
|
|
const driversRes = await this.driverService.findByIds(Array.from(driverIds));
|
|
const drivers = (driversRes as any).value || driversRes;
|
|
|
|
const driverMap: Record<string, any> = {};
|
|
drivers.forEach((d: any) => {
|
|
driverMap[d.id] = d;
|
|
});
|
|
|
|
return new LeagueStewardingViewModel(racesWithData as any, driverMap);
|
|
}
|
|
|
|
async reviewProtest(input: any): Promise<void> {
|
|
if (this.protestService) {
|
|
await this.protestService.reviewProtest(input);
|
|
}
|
|
}
|
|
|
|
async applyPenalty(input: any): Promise<void> {
|
|
if (this.penaltyService) {
|
|
await this.penaltyService.applyPenalty(input);
|
|
}
|
|
}
|
|
|
|
async getStewardingData(leagueId: string): Promise<Result<StewardingApiDto, DomainError>> {
|
|
// Mock data since backend not implemented
|
|
const mockData: StewardingApiDto = {
|
|
leagueId,
|
|
totalPending: 0,
|
|
totalResolved: 0,
|
|
totalPenalties: 0,
|
|
races: [],
|
|
drivers: []
|
|
};
|
|
return Result.ok(mockData);
|
|
}
|
|
|
|
async getProtestDetailViewModel(leagueId: string, protestId: string): Promise<any> {
|
|
if (!this.protestService || !this.penaltyService) return null;
|
|
|
|
const [protestRes, penaltyTypesRes] = await Promise.all([
|
|
this.protestService.getProtestById(leagueId, protestId),
|
|
this.penaltyService.getPenaltyTypesReference(),
|
|
]);
|
|
|
|
const protestData = (protestRes as any).value || protestRes;
|
|
const penaltyTypesData = (penaltyTypesRes as any).value || penaltyTypesRes;
|
|
|
|
return {
|
|
...protestData,
|
|
penaltyTypes: penaltyTypesData.penaltyTypes,
|
|
defaultReasons: penaltyTypesData.defaultReasons,
|
|
initialPenaltyType: penaltyTypesData.penaltyTypes[0]?.type,
|
|
};
|
|
}
|
|
}
|