import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import type { IProtestRepository } from '../../domain/repositories/IProtestRepository';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { AsyncUseCase } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { GetLeagueProtestsResultDTO, ProtestDTO } from '../dto/GetLeagueProtestsResultDTO';

export interface GetLeagueProtestsUseCaseParams {
  leagueId: string;
}

export class GetLeagueProtestsUseCase implements AsyncUseCase<GetLeagueProtestsUseCaseParams, GetLeagueProtestsResultDTO, 'NO_ERROR'> {
  constructor(
    private readonly raceRepository: IRaceRepository,
    private readonly protestRepository: IProtestRepository,
    private readonly driverRepository: IDriverRepository,
  ) {}

  async execute(params: GetLeagueProtestsUseCaseParams): Promise<Result<GetLeagueProtestsResultDTO, ApplicationErrorCode<'NO_ERROR'>>> {
    const races = await this.raceRepository.findByLeagueId(params.leagueId);
    const protests: ProtestDTO[] = [];
    const raceMap = new Map();
    const driverIds = new Set<string>();

    for (const race of races) {
      raceMap.set(race.id, { id: race.id, name: race.track, date: race.scheduledAt.toISOString() });
      const raceProtests = await this.protestRepository.findByRaceId(race.id);
      for (const protest of raceProtests) {
        protests.push({
          id: protest.id,
          raceId: protest.raceId,
          protestingDriverId: protest.protestingDriverId,
          accusedDriverId: protest.accusedDriverId,
          submittedAt: protest.filedAt,
          description: protest.comment || '',
          status: protest.status,
        });
        driverIds.add(protest.protestingDriverId);
        driverIds.add(protest.accusedDriverId);
      }
    }

    const drivers: { id: string; name: string }[] = [];
    for (const driverId of driverIds) {
      const driver = await this.driverRepository.findById(driverId);
      if (driver) {
        drivers.push({ id: driver.id, name: driver.name });
      }
    }
    return Result.ok({
      protests,
      races: Array.from(raceMap.values()),
      drivers,
    });
  }
}