import type { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type {
  GetRacePenaltiesResult,
  GetRacePenaltiesErrorCode,
} from '@core/racing/application/use-cases/GetRacePenaltiesUseCase';
import type { RacePenaltiesDTO } from '../dtos/RacePenaltiesDTO';
import type { RacePenaltyDTO } from '../dtos/RacePenaltyDTO';

export type GetRacePenaltiesResponseModel = RacePenaltiesDTO;

export type GetRacePenaltiesApplicationError = ApplicationErrorCode<
  GetRacePenaltiesErrorCode,
  { message: string }
>;

export class RacePenaltiesPresenter {
  private model: GetRacePenaltiesResponseModel | null = null;

  reset(): void {
    this.model = null;
  }

  present(result: Result<GetRacePenaltiesResult, GetRacePenaltiesApplicationError>): void {
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to get race penalties');
    }

    const output = result.unwrap();

    const penalties: RacePenaltyDTO[] = output.penalties.map(penalty => ({
      id: penalty.id,
      driverId: penalty.driverId,
      type: penalty.type,
      value: penalty.value ?? 0,
      reason: penalty.reason,
      issuedBy: penalty.issuedBy,
      issuedAt: penalty.issuedAt.toISOString(),
      notes: penalty.notes,
    } as RacePenaltyDTO));

    const driverMap: Record<string, string> = {};
    output.drivers.forEach(driver => {
      driverMap[driver.id] = driver.name.toString();
    });

    this.model = {
      penalties,
      driverMap,
    } as RacePenaltiesDTO;
  }

  getResponseModel(): GetRacePenaltiesResponseModel | null {
    return this.model;
  }

  get responseModel(): GetRacePenaltiesResponseModel {
    if (!this.model) {
      throw new Error('Presenter not presented');
    }

    return this.model;
  }

  get viewModel(): GetRacePenaltiesResponseModel {
    return this.responseModel;
  }
}
