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

export interface GetRaceProtestsInput {
  raceId: string;
}

export type GetRaceProtestsErrorCode = 'REPOSITORY_ERROR';

export interface GetRaceProtestsResult {
  protests: Protest[];
  drivers: Driver[];
}

export class GetRaceProtestsUseCase {
  constructor(
    private readonly protestRepository: IProtestRepository,
    private readonly driverRepository: IDriverRepository,
    private readonly output: UseCaseOutputPort<GetRaceProtestsResult>,
  ) {}

  async execute(
    input: GetRaceProtestsInput,
  ): Promise<Result<void, ApplicationErrorCode<GetRaceProtestsErrorCode, { message: string }>>> {
    try {
      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 validDrivers = drivers.filter((driver): driver is NonNullable<typeof driver> => driver !== null);

      const result: GetRaceProtestsResult = {
        protests,
        drivers: validDrivers,
      };

      this.output.present(result);

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

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