/**
 * 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 { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { UseCaseOutputPort } from '@core/shared/application';
import type { Driver } from '../../domain/entities/Driver';
import type { Penalty } from '../../domain/entities/penalty/Penalty';

export type GetRacePenaltiesInput = {
  raceId: string;
};

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

export type GetRacePenaltiesErrorCode = 'REPOSITORY_ERROR';

export class GetRacePenaltiesUseCase {
  constructor(
    private readonly penaltyRepository: IPenaltyRepository,
    private readonly driverRepository: IDriverRepository,
    private readonly output: UseCaseOutputPort<GetRacePenaltiesResult>,
  ) {}

  async execute(
    input: GetRacePenaltiesInput,
  ): Promise<Result<void, 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);

      this.output.present({ penalties, drivers: validDrivers });

      return Result.ok(undefined);
    } 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 },
      });
    }
  }
}