import { RacesApiClient } from '../../api/races/RacesApiClient';
import { RaceDetailEntryViewModel } from '../../view-models/RaceDetailEntryViewModel';
import { RaceDetailUserResultViewModel } from '../../view-models/RaceDetailUserResultViewModel';
import { RaceDetailViewModel } from '../../view-models/RaceDetailViewModel';
import { RacesPageViewModel } from '../../view-models/RacesPageViewModel';
import { RaceStatsViewModel } from '../../view-models/RaceStatsViewModel';
import type { RaceDetailsViewModel } from '../../view-models/RaceDetailsViewModel';
import type { FileProtestCommandDTO } from '../../types/generated/FileProtestCommandDTO';
import type { RaceStatsDTO } from '../../types/generated/RaceStatsDTO';
/**
 * Race Service
 *
 * Orchestrates race operations by coordinating API calls and view model creation.
 * All dependencies are injected via constructor.
 */
export class RaceService {
  constructor(
    private readonly apiClient: RacesApiClient
  ) {}

  /**
   * Get race detail with view model transformation
   */
  async getRaceDetail(
    raceId: string,
    driverId: string
  ): Promise<RaceDetailViewModel> {
    const dto = await this.apiClient.getDetail(raceId, driverId);
    return new RaceDetailViewModel(dto, driverId);
  }

  /**
   * Get race details for pages/components (DTO-free shape)
   */
  async getRaceDetails(
    raceId: string,
    driverId: string
  ): Promise<RaceDetailsViewModel> {
    const dto: any = await this.apiClient.getDetail(raceId, driverId);

    const raceDto: any = dto?.race ?? null;
    const leagueDto: any = dto?.league ?? null;

    const registrationDto: any = dto?.registration ?? {};
    const isUserRegistered = Boolean(registrationDto.isUserRegistered ?? registrationDto.isRegistered ?? false);
    const canRegister = Boolean(registrationDto.canRegister);

    const status = String(raceDto?.status ?? '');
    const canReopenRace = status === 'completed' || status === 'cancelled';

    return {
      race: raceDto
        ? {
            id: String(raceDto.id ?? ''),
            track: String(raceDto.track ?? ''),
            car: String(raceDto.car ?? ''),
            scheduledAt: String(raceDto.scheduledAt ?? ''),
            status,
            sessionType: String(raceDto.sessionType ?? ''),
          }
        : null,
      league: leagueDto
        ? {
            id: String(leagueDto.id ?? ''),
            name: String(leagueDto.name ?? ''),
            description: leagueDto.description ?? null,
            settings: leagueDto.settings,
          }
        : null,
      entryList: (dto?.entryList ?? []).map((entry: any) => new RaceDetailEntryViewModel(entry, driverId)),
      registration: {
        canRegister,
        isUserRegistered,
      },
      userResult: dto?.userResult ? new RaceDetailUserResultViewModel(dto.userResult) : null,
      canReopenRace,
      error: dto?.error,
    };
  }

  /**
   * Get races page data with view model transformation
   */
  async getRacesPageData(): Promise<RacesPageViewModel> {
    const dto = await this.apiClient.getPageData();
    return new RacesPageViewModel(dto);
  }

  /**
   * Get races page data filtered by league
   */
  async getLeagueRacesPageData(leagueId: string): Promise<RacesPageViewModel> {
    const dto = await this.apiClient.getPageData(leagueId);
    return new RacesPageViewModel(dto);
  }

  /**
   * Get all races page data with view model transformation
   * Currently same as getRacesPageData, but can be extended for different filtering
   */
  async getAllRacesPageData(): Promise<RacesPageViewModel> {
    const dto = await this.apiClient.getPageData();
    return new RacesPageViewModel(dto);
  }

  /**
   * Get total races statistics with view model transformation
   */
  async getRacesTotal(): Promise<RaceStatsViewModel> {
    const dto: RaceStatsDTO = await this.apiClient.getTotal();
    return new RaceStatsViewModel(dto);
  }

  /**
   * Register for a race
   */
  async registerForRace(raceId: string, leagueId: string, driverId: string): Promise<void> {
    await this.apiClient.register(raceId, { raceId, leagueId, driverId });
  }

  /**
   * Withdraw from a race
   */
  async withdrawFromRace(raceId: string, driverId: string): Promise<void> {
    await this.apiClient.withdraw(raceId, { raceId, driverId });
  }

  /**
   * Cancel a race
   */
  async cancelRace(raceId: string): Promise<void> {
    await this.apiClient.cancel(raceId);
  }

  /**
   * Complete a race
   */
  async completeRace(raceId: string): Promise<void> {
    await this.apiClient.complete(raceId);
  }

  /**
   * Re-open a race
   */
  async reopenRace(raceId: string): Promise<void> {
    await this.apiClient.reopen(raceId);
  }

  /**
   * File a protest
   */
  async fileProtest(input: FileProtestCommandDTO): Promise<void> {
    await this.apiClient.fileProtest(input);
  }

  /**
   * Find races by league ID
   *
   * The races API does not currently expose a league-filtered listing endpoint in this build,
   * so this method deliberately signals that the operation is unavailable instead of making
   * assumptions about URL structure.
   */
  async findByLeagueId(leagueId: string): Promise<RacesPageViewModel['races']> {
    const page = await this.getLeagueRacesPageData(leagueId);
    return page.races;
  }
}
