import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl'; import { Service } from '@/lib/contracts/services/Service'; import { ProtestsApiClient } from '@/lib/gateways/api/protests/ProtestsApiClient'; import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter'; import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger'; import type { ApplyPenaltyCommandDTO } from '@/lib/types/generated/ApplyPenaltyCommandDTO'; import type { RequestProtestDefenseCommandDTO } from '@/lib/types/generated/RequestProtestDefenseCommandDTO'; import type { ReviewProtestCommandDTO } from '@/lib/types/generated/ReviewProtestCommandDTO'; import { ProtestDriverViewModel } from '@/lib/view-models/ProtestDriverViewModel'; import { ProtestViewModel } from '@/lib/view-models/ProtestViewModel'; import { RaceViewModel } from '@/lib/view-models/RaceViewModel'; import { injectable, unmanaged } from 'inversify'; /** * Protest Service - DTO Only * * Returns raw API DTOs. No ViewModels or UX logic. * All client-side presentation logic must be handled by hooks/components. * @server-safe */ @injectable() export class ProtestService implements Service { private readonly apiClient: ProtestsApiClient; constructor(@unmanaged() apiClient?: ProtestsApiClient) { if (apiClient) { this.apiClient = apiClient; } else { const baseUrl = getWebsiteApiBaseUrl(); const logger = new ConsoleLogger(); const errorReporter = new EnhancedErrorReporter(logger); this.apiClient = new ProtestsApiClient(baseUrl, errorReporter, logger); } } async getLeagueProtests(leagueId: string): Promise { try { const data = await this.apiClient.getLeagueProtests(leagueId); const protests = (data as any).protests || []; return { ...data, protests: protests.map((p: any) => new ProtestViewModel(p)), }; } catch (error: unknown) { throw error; } } async getProtestById(leagueId: string, protestId: string): Promise { try { const data = await this.apiClient.getLeagueProtest(leagueId, protestId); const protests = (data as any).protests || []; const protest = protests.find((p: any) => p.id === protestId); if (!protest) return null; const raceData = (data as any).racesById?.[protest.raceId] || (data as any).races?.[0] || Object.values((data as any).racesById || {})[0]; const protestingDriverData = (data as any).driversById?.[protest.protestingDriverId] || (data as any).drivers?.[0] || Object.values((data as any).driversById || {})[0]; const accusedDriverData = (data as any).driversById?.[protest.accusedDriverId] || (data as any).drivers?.[1] || Object.values((data as any).driversById || {})[1]; return { protest: new ProtestViewModel(protest), race: raceData ? new RaceViewModel(raceData) : null, protestingDriver: protestingDriverData ? new ProtestDriverViewModel(protestingDriverData) : null, accusedDriver: accusedDriverData ? new ProtestDriverViewModel(accusedDriverData) : null, }; } catch (error: unknown) { throw error; } } async applyPenalty(input: ApplyPenaltyCommandDTO): Promise { try { const res = await this.apiClient.applyPenalty(input); return (res as any)?.value || res; } catch (error: unknown) { throw error; } } async requestDefense(input: RequestProtestDefenseCommandDTO): Promise { try { const res = await this.apiClient.requestDefense(input); return (res as any)?.value || res; } catch (error: unknown) { throw error; } } async reviewProtest(input: ReviewProtestCommandDTO): Promise { try { const res = await this.apiClient.reviewProtest(input); return (res as any)?.value || res; } catch (error: unknown) { throw error; } } async findByRaceId(raceId: string): Promise { try { const res = await this.apiClient.getRaceProtests(raceId); const data = (res as any).value || res; return data.protests; } catch (error: unknown) { throw error; } } }