import type { GetLeagueProtestsResult } from '@core/racing/application/use-cases/GetLeagueProtestsUseCase';
import type { Presenter } from '../../../shared/presentation/Presenter';
import { DriverDTO } from '../../driver/dtos/DriverDTO';
import { RaceDTO } from '../../race/dtos/RaceDTO';
import { LeagueAdminProtestsDTO } from '../dtos/LeagueAdminProtestsDTO';
import { ProtestDTO } from '../dtos/ProtestDTO';

function mapProtestStatus(status: string): ProtestDTO['status'] {
  switch (status) {
    case 'pending':
    case 'awaiting_defense':
    case 'under_review':
      return 'pending';
    case 'upheld':
      return 'accepted';
    case 'dismissed':
    case 'withdrawn':
      return 'rejected';
    default:
      return 'pending';
  }
}

export class GetLeagueProtestsPresenter implements Presenter<GetLeagueProtestsResult, LeagueAdminProtestsDTO> {
  private result: LeagueAdminProtestsDTO | null = null;

  reset() {
    this.result = null;
  }

  present(input: GetLeagueProtestsResult) {
    const protests: ProtestDTO[] = input.protests.map((protestWithEntities) => {
      const { protest, race } = protestWithEntities;

      return {
        id: protest.id.toString(),
        leagueId: race?.leagueId.toString() || '',
        raceId: protest.raceId.toString(),
        protestingDriverId: protest.protestingDriverId.toString(),
        accusedDriverId: protest.accusedDriverId.toString(),
        submittedAt: new Date(protest.filedAt),
        description: protest.incident.description.toString(),
        status: mapProtestStatus(protest.status.toString()),
      };
    });

    const racesById: { [raceId: string]: RaceDTO } = {};
    for (const protestWithEntities of input.protests) {
      const { race } = protestWithEntities;
      if (race) {
        racesById[race.id.toString()] = {
          id: race.id.toString(),
          name: race.track.toString(),
          date: race.scheduledAt.toISOString(),
          leagueName: input.league.name.toString(),
        };
      }
    }

    const driversById: { [driverId: string]: DriverDTO } = {};
    for (const protestWithEntities of input.protests) {
      const { protestingDriver, accusedDriver } = protestWithEntities;
      if (protestingDriver) {
        driversById[protestingDriver.id.toString()] = {
          id: protestingDriver.id.toString(),
          iracingId: protestingDriver.iracingId.toString(),
          name: protestingDriver.name.toString(),
          country: protestingDriver.country.toString(),
          bio: protestingDriver.bio?.toString() || '',
          joinedAt: protestingDriver.joinedAt.toDate().toISOString(),
        };
      }
      if (accusedDriver) {
        driversById[accusedDriver.id.toString()] = {
          id: accusedDriver.id.toString(),
          iracingId: accusedDriver.iracingId.toString(),
          name: accusedDriver.name.toString(),
          country: accusedDriver.country.toString(),
          bio: accusedDriver.bio?.toString() || '',
          joinedAt: accusedDriver.joinedAt.toDate().toISOString(),
        };
      }
    }

    this.result = {
      protests,
      racesById,
      driversById,
    };
  }

  getResponseModel(): LeagueAdminProtestsDTO | null {
    return this.result;
  }
}