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

import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Driver } from '../../domain/entities/Driver';
import type { Penalty } from '../../domain/entities/penalty/Penalty';
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
import type { PenaltyRepository } from '../../domain/repositories/PenaltyRepository';

export type GetRacePenaltiesInput = {
  raceId: string;
};

export type GetRacePenaltiesResult = {
  penalties: Penalty[];
  drivers: Driver[];
};

export type GetRacePenaltiesErrorCode = 'REPOSITORY_ERROR';

export class GetRacePenaltiesUseCase {
  constructor(
    private readonly penaltyRepository: PenaltyRepository,
    private readonly driverRepository: DriverRepository,
  ) {}

  async execute(
    input: GetRacePenaltiesInput,
  ): Promise<Result<GetRacePenaltiesResult, ApplicationErrorCode<GetRacePenaltiesErrorCode, { message: string }>>> {
    try {
      const penalties = await this.penaltyRepository.findByRaceId(input.raceId);

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

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

      const validDrivers = drivers.filter((driver): driver is NonNullable<typeof driver> => driver !== null);

      return Result.ok({ penalties, drivers: validDrivers });
    } catch (error: unknown) {
      const message =
        error instanceof Error && error.message
          ? error.message
          : 'Failed to load race penalties';

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message },
      });
    }
  }
}