import type { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type {
  GetRacesPageDataResult,
  GetRacesPageDataErrorCode,
} from '@core/racing/application/use-cases/GetRacesPageDataUseCase';
import type { RacesPageDataDTO } from '../dtos/RacesPageDataDTO';
import type { RacesPageDataRaceDTO } from '../dtos/RacesPageDataRaceDTO';

export type GetRacesPageDataResponseModel = RacesPageDataDTO;

export type GetRacesPageDataApplicationError = ApplicationErrorCode<
  GetRacesPageDataErrorCode,
  { message: string }
>;

export class RacesPageDataPresenter {
  private model: GetRacesPageDataResponseModel | null = null;

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

  present(
    result: Result<GetRacesPageDataResult, GetRacesPageDataApplicationError>,
  ): void {
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to get races page data');
    }

    const output = result.unwrap();

    const races: RacesPageDataRaceDTO[] = output.races.map(({ race, leagueName }) => ({
      id: race.id,
      track: race.track,
      car: race.car,
      scheduledAt: race.scheduledAt.toISOString(),
      status: race.status.toString(),
      leagueId: race.leagueId,
      leagueName,
      strengthOfField: race.strengthOfField?.toNumber() ?? null,
      isUpcoming: race.scheduledAt > new Date(),
      isLive: race.status.isRunning(),
      isPast: race.scheduledAt < new Date() && race.status.isCompleted(),
    }));

    this.model = { races } as RacesPageDataDTO;
  }

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

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

    return this.model;
  }

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