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,
    };
  }
}
