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

import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { RacePenaltiesResultDTO } from '../presenters/IRacePenaltiesPresenter';
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 GetRacePenaltiesInput {
  raceId: string;
}

export class GetRacePenaltiesUseCase implements AsyncUseCase<GetRacePenaltiesInput, RacePenaltiesResultDTO, 'NO_ERROR'> {
  constructor(
    private readonly penaltyRepository: IPenaltyRepository,
    private readonly driverRepository: IDriverRepository,
  ) {}

  async execute(input: GetRacePenaltiesInput): Promise<Result<RacePenaltiesResultDTO, ApplicationErrorCode<'NO_ERROR'>>> {
    const penalties = await this.penaltyRepository.findByRaceId(input.raceId);

    const driverIds = new Set<string>();
    penalties.forEach((penalty) => {
      driverIds.add(penalty.driverId);
      driverIds.add(penalty.issuedBy);
    });

    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: RacePenaltiesResultDTO = {
      penalties,
      driverMap,
    };
    return Result.ok(dto);
  }
}