/**
 * Use Case: GetRaceProtestsUseCase
 *
 * Returns all protests filed for a specific race, with driver details.
 * Orchestrates domain logic and delegates presentation to the presenter.
 */

import type { IProtestRepository } from '../../domain/repositories/IProtestRepository';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { RaceProtestsResultDTO } from '../presenters/IRaceProtestsPresenter';
import type { AsyncUseCase } from '@core/shared/application/AsyncUseCase';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';

export interface GetRaceProtestsInput {
  raceId: string;
}

export class GetRaceProtestsUseCase implements AsyncUseCase<GetRaceProtestsInput, RaceProtestsResultDTO, 'NO_ERROR'> {
  constructor(
    private readonly protestRepository: IProtestRepository,
    private readonly driverRepository: IDriverRepository,
  ) {}

  async execute(input: GetRaceProtestsInput): Promise<Result<RaceProtestsResultDTO, ApplicationErrorCode<'NO_ERROR'>>> {
    const protests = await this.protestRepository.findByRaceId(input.raceId);

    const driverIds = new Set<string>();
    protests.forEach((protest) => {
      driverIds.add(protest.protestingDriverId);
      driverIds.add(protest.accusedDriverId);
      if (protest.reviewedBy) {
        driverIds.add(protest.reviewedBy);
      }
    });

    const drivers = await Promise.all(
      Array.from(driverIds).map((id) => this.driverRepository.findById(id)),
    );

    const driverMap = new Map<string, string>();
    drivers.forEach((driver) => {
      if (driver) {
        driverMap.set(driver.id, driver.name);
      }
    });

    const dto: RaceProtestsResultDTO = {
      protests,
      driverMap,
    };
    return Result.ok(dto);
  }
}