import type { Provider } from '@nestjs/common';

// Import core interfaces
import type { DriverRatingProvider } from '@core/racing/application/ports/DriverRatingProvider';
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
import type { IPenaltyRepository } from '@core/racing/domain/repositories/IPenaltyRepository';
import type { IProtestRepository } from '@core/racing/domain/repositories/IProtestRepository';
import type { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository';
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository';
import type { Logger } from '@core/shared/application/Logger';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { Result } from '@core/shared/application/Result';

// Import concrete in-memory implementations
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider';

// Import use cases
import { ApplyPenaltyUseCase } from '@core/racing/application/use-cases/ApplyPenaltyUseCase';
import { CancelRaceUseCase } from '@core/racing/application/use-cases/CancelRaceUseCase';
import { CompleteRaceUseCase } from '@core/racing/application/use-cases/CompleteRaceUseCase';
import { FileProtestUseCase } from '@core/racing/application/use-cases/FileProtestUseCase';
import { GetAllRacesPageDataUseCase } from '@core/racing/application/use-cases/GetAllRacesPageDataUseCase';
import { GetAllRacesUseCase } from '@core/racing/application/use-cases/GetAllRacesUseCase';
import { GetRaceDetailUseCase } from '@core/racing/application/use-cases/GetRaceDetailUseCase';
import { GetRacePenaltiesUseCase } from '@core/racing/application/use-cases/GetRacePenaltiesUseCase';
import { GetRaceProtestsUseCase } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
import { GetRaceResultsDetailUseCase } from '@core/racing/application/use-cases/GetRaceResultsDetailUseCase';
import { GetRacesPageDataUseCase } from '@core/racing/application/use-cases/GetRacesPageDataUseCase';
import { GetRaceWithSOFUseCase } from '@core/racing/application/use-cases/GetRaceWithSOFUseCase';
import { GetTotalRacesUseCase } from '@core/racing/application/use-cases/GetTotalRacesUseCase';
import { ImportRaceResultsApiUseCase } from '@core/racing/application/use-cases/ImportRaceResultsApiUseCase';
import { ImportRaceResultsUseCase } from '@core/racing/application/use-cases/ImportRaceResultsUseCase';
import { QuickPenaltyUseCase } from '@core/racing/application/use-cases/QuickPenaltyUseCase';
import { RegisterForRaceUseCase } from '@core/racing/application/use-cases/RegisterForRaceUseCase';
import { ReopenRaceUseCase } from '@core/racing/application/use-cases/ReopenRaceUseCase';
import { RequestProtestDefenseUseCase } from '@core/racing/application/use-cases/RequestProtestDefenseUseCase';
import { ReviewProtestUseCase } from '@core/racing/application/use-cases/ReviewProtestUseCase';
import { WithdrawFromRaceUseCase } from '@core/racing/application/use-cases/WithdrawFromRaceUseCase';

// Import use case result types
import type { GetAllRacesResult } from '@core/racing/application/use-cases/GetAllRacesUseCase';
import type { GetTotalRacesResult } from '@core/racing/application/use-cases/GetTotalRacesUseCase';
import type { ImportRaceResultsApiResult } from '@core/racing/application/use-cases/ImportRaceResultsApiUseCase';
import type { GetRaceDetailResult } from '@core/racing/application/use-cases/GetRaceDetailUseCase';
import type { GetRacesPageDataResult } from '@core/racing/application/use-cases/GetRacesPageDataUseCase';
import type { GetAllRacesPageDataResult } from '@core/racing/application/use-cases/GetAllRacesPageDataUseCase';
import type { GetRaceResultsDetailResult } from '@core/racing/application/use-cases/GetRaceResultsDetailUseCase';
import type { GetRaceWithSOFResult } from '@core/racing/application/use-cases/GetRaceWithSOFUseCase';
import type { GetRaceProtestsResult } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
import type { GetRacePenaltiesResult } from '@core/racing/application/use-cases/GetRacePenaltiesUseCase';
import type { RegisterForRaceResult } from '@core/racing/application/use-cases/RegisterForRaceUseCase';
import type { WithdrawFromRaceResult } from '@core/racing/application/use-cases/WithdrawFromRaceUseCase';
import type { CancelRaceResult } from '@core/racing/application/use-cases/CancelRaceUseCase';
import type { CompleteRaceResult } from '@core/racing/application/use-cases/CompleteRaceUseCase';
import type { ReopenRaceResult } from '@core/racing/application/use-cases/ReopenRaceUseCase';
import type { ImportRaceResultsResult } from '@core/racing/application/use-cases/ImportRaceResultsUseCase';
import type { FileProtestResult } from '@core/racing/application/use-cases/FileProtestUseCase';
import type { QuickPenaltyResult } from '@core/racing/application/use-cases/QuickPenaltyUseCase';
import type { ApplyPenaltyResult } from '@core/racing/application/use-cases/ApplyPenaltyUseCase';
import type { RequestProtestDefenseResult } from '@core/racing/application/use-cases/RequestProtestDefenseUseCase';
import type { ReviewProtestResult } from '@core/racing/application/use-cases/ReviewProtestUseCase';

// Import presenters
import { AllRacesPageDataPresenter } from './presenters/AllRacesPageDataPresenter';
import { CommandResultPresenter } from './presenters/CommandResultPresenter';
import { GetAllRacesPresenter } from './presenters/GetAllRacesPresenter';
import { GetTotalRacesPresenter } from './presenters/GetTotalRacesPresenter';
import { ImportRaceResultsApiPresenter } from './presenters/ImportRaceResultsApiPresenter';
import { RaceDetailPresenter } from './presenters/RaceDetailPresenter';
import { RacePenaltiesPresenter } from './presenters/RacePenaltiesPresenter';
import { RaceProtestsPresenter } from './presenters/RaceProtestsPresenter';
import { RaceResultsDetailPresenter } from './presenters/RaceResultsDetailPresenter';
import { RacesPageDataPresenter } from './presenters/RacesPageDataPresenter';
import { RaceWithSOFPresenter } from './presenters/RaceWithSOFPresenter';

import {
  RACE_REPOSITORY_TOKEN,
  LEAGUE_REPOSITORY_TOKEN,
  DRIVER_REPOSITORY_TOKEN,
  RACE_REGISTRATION_REPOSITORY_TOKEN,
  RESULT_REPOSITORY_TOKEN,
  LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
  PENALTY_REPOSITORY_TOKEN,
  PROTEST_REPOSITORY_TOKEN,
  STANDING_REPOSITORY_TOKEN,
  DRIVER_RATING_PROVIDER_TOKEN,
  IMAGE_SERVICE_TOKEN,
  LOGGER_TOKEN,
  GET_ALL_RACES_PRESENTER_TOKEN,
  GET_TOTAL_RACES_PRESENTER_TOKEN,
  IMPORT_RACE_RESULTS_API_PRESENTER_TOKEN,
  RACE_DETAIL_PRESENTER_TOKEN,
  RACES_PAGE_DATA_PRESENTER_TOKEN,
  ALL_RACES_PAGE_DATA_PRESENTER_TOKEN,
  RACE_RESULTS_DETAIL_PRESENTER_TOKEN,
  RACE_WITH_SOF_PRESENTER_TOKEN,
  RACE_PROTESTS_PRESENTER_TOKEN,
  RACE_PENALTIES_PRESENTER_TOKEN,
  COMMAND_RESULT_PRESENTER_TOKEN,
} from './RaceTokens';

export * from './RaceTokens';

// Adapter classes to bridge presenters with UseCaseOutputPort interface
class GetAllRacesOutputAdapter implements UseCaseOutputPort<GetAllRacesResult> {
  constructor(private presenter: GetAllRacesPresenter) {}
  
  present(result: GetAllRacesResult): void {
    this.presenter.present(result);
  }
}

class GetTotalRacesOutputAdapter implements UseCaseOutputPort<GetTotalRacesResult> {
  constructor(private presenter: GetTotalRacesPresenter) {}
  
  present(result: GetTotalRacesResult): void {
    // Wrap the result in a Result.ok() to match presenter expectations
    const resultWrapper = Result.ok<GetTotalRacesResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class ImportRaceResultsApiOutputAdapter implements UseCaseOutputPort<ImportRaceResultsApiResult> {
  constructor(private presenter: ImportRaceResultsApiPresenter) {}
  
  present(result: ImportRaceResultsApiResult): void {
    const resultWrapper = Result.ok<ImportRaceResultsApiResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class RaceDetailOutputAdapter implements UseCaseOutputPort<GetRaceDetailResult> {
  constructor(private presenter: RaceDetailPresenter) {}
  
  present(result: GetRaceDetailResult): void {
    this.presenter.present(result);
  }
}

class RacesPageDataOutputAdapter implements UseCaseOutputPort<GetRacesPageDataResult> {
  constructor(private presenter: RacesPageDataPresenter) {}
  
  present(result: GetRacesPageDataResult): void {
    const resultWrapper = Result.ok<GetRacesPageDataResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class AllRacesPageDataOutputAdapter implements UseCaseOutputPort<GetAllRacesPageDataResult> {
  constructor(private presenter: AllRacesPageDataPresenter) {}
  
  present(result: GetAllRacesPageDataResult): void {
    const resultWrapper = Result.ok<GetAllRacesPageDataResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class RaceResultsDetailOutputAdapter implements UseCaseOutputPort<GetRaceResultsDetailResult> {
  constructor(private presenter: RaceResultsDetailPresenter) {}
  
  present(result: GetRaceResultsDetailResult): void {
    this.presenter.present(result);
  }
}

class RaceWithSOFOutputAdapter implements UseCaseOutputPort<GetRaceWithSOFResult> {
  constructor(private presenter: RaceWithSOFPresenter) {}
  
  present(result: GetRaceWithSOFResult): void {
    const resultWrapper = Result.ok<GetRaceWithSOFResult, { code: 'RACE_NOT_FOUND' | 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class RaceProtestsOutputAdapter implements UseCaseOutputPort<GetRaceProtestsResult> {
  constructor(private presenter: RaceProtestsPresenter) {}
  
  present(result: GetRaceProtestsResult): void {
    const resultWrapper = Result.ok<GetRaceProtestsResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class RacePenaltiesOutputAdapter implements UseCaseOutputPort<GetRacePenaltiesResult> {
  constructor(private presenter: RacePenaltiesPresenter) {}
  
  present(result: GetRacePenaltiesResult): void {
    const resultWrapper = Result.ok<GetRacePenaltiesResult, { code: 'REPOSITORY_ERROR'; details: { message: string } }>(result);
    this.presenter.present(resultWrapper);
  }
}

class RegisterForRaceOutputAdapter implements UseCaseOutputPort<RegisterForRaceResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race registered successfully');
  }
}

class WithdrawFromRaceOutputAdapter implements UseCaseOutputPort<WithdrawFromRaceResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race withdrawal successful');
  }
}

class CancelRaceOutputAdapter implements UseCaseOutputPort<CancelRaceResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race cancelled successfully');
  }
}

class CompleteRaceOutputAdapter implements UseCaseOutputPort<CompleteRaceResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race completed successfully');
  }
}

class ReopenRaceOutputAdapter implements UseCaseOutputPort<ReopenRaceResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race reopened successfully');
  }
}

class ImportRaceResultsOutputAdapter implements UseCaseOutputPort<ImportRaceResultsResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Race results imported successfully');
  }
}

class FileProtestOutputAdapter implements UseCaseOutputPort<FileProtestResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Protest filed successfully');
  }
}

class QuickPenaltyOutputAdapter implements UseCaseOutputPort<QuickPenaltyResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Penalty applied successfully');
  }
}

class ApplyPenaltyOutputAdapter implements UseCaseOutputPort<ApplyPenaltyResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Penalty applied successfully');
  }
}

class RequestProtestDefenseOutputAdapter implements UseCaseOutputPort<RequestProtestDefenseResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Defense request sent successfully');
  }
}

class ReviewProtestOutputAdapter implements UseCaseOutputPort<ReviewProtestResult> {
  constructor(private presenter: CommandResultPresenter) {}
  
  present(): void {
    this.presenter.presentSuccess('Protest reviewed successfully');
  }
}

export const RaceProviders: Provider[] = [
  {
    provide: DRIVER_RATING_PROVIDER_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverRatingProvider(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: IMAGE_SERVICE_TOKEN,
    useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LOGGER_TOKEN,
    useClass: ConsoleLogger,
  },
  // Presenters
  {
    provide: GET_ALL_RACES_PRESENTER_TOKEN,
    useClass: GetAllRacesPresenter,
  },
  {
    provide: GET_TOTAL_RACES_PRESENTER_TOKEN,
    useClass: GetTotalRacesPresenter,
  },
  {
    provide: IMPORT_RACE_RESULTS_API_PRESENTER_TOKEN,
    useClass: ImportRaceResultsApiPresenter,
  },
  {
    provide: RACE_DETAIL_PRESENTER_TOKEN,
    useFactory: (driverRatingProvider: DriverRatingProvider, imageService: InMemoryImageServiceAdapter) => 
      new RaceDetailPresenter(driverRatingProvider, imageService, { raceId: '', driverId: '' }),
    inject: [DRIVER_RATING_PROVIDER_TOKEN, IMAGE_SERVICE_TOKEN],
  },
  {
    provide: RACES_PAGE_DATA_PRESENTER_TOKEN,
    useClass: RacesPageDataPresenter,
  },
  {
    provide: ALL_RACES_PAGE_DATA_PRESENTER_TOKEN,
    useClass: AllRacesPageDataPresenter,
  },
  {
    provide: RACE_RESULTS_DETAIL_PRESENTER_TOKEN,
    useFactory: (imageService: InMemoryImageServiceAdapter) => new RaceResultsDetailPresenter(imageService),
    inject: [IMAGE_SERVICE_TOKEN],
  },
  {
    provide: RACE_WITH_SOF_PRESENTER_TOKEN,
    useClass: RaceWithSOFPresenter,
  },
  {
    provide: RACE_PROTESTS_PRESENTER_TOKEN,
    useClass: RaceProtestsPresenter,
  },
  {
    provide: RACE_PENALTIES_PRESENTER_TOKEN,
    useClass: RacePenaltiesPresenter,
  },
  {
    provide: COMMAND_RESULT_PRESENTER_TOKEN,
    useClass: CommandResultPresenter,
  },
  // Use cases
  {
    provide: GetAllRacesUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      logger: Logger,
      presenter: GetAllRacesPresenter,
    ) => {
      const useCase = new GetAllRacesUseCase(raceRepo, leagueRepo, logger);
      useCase.setOutput(new GetAllRacesOutputAdapter(presenter));
      return useCase;
    },
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN, LOGGER_TOKEN, GET_ALL_RACES_PRESENTER_TOKEN],
  },
  {
    provide: GetTotalRacesUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      logger: Logger,
      presenter: GetTotalRacesPresenter,
    ) => {
      return new GetTotalRacesUseCase(raceRepo, logger, new GetTotalRacesOutputAdapter(presenter));
    },
    inject: [RACE_REPOSITORY_TOKEN, LOGGER_TOKEN, GET_TOTAL_RACES_PRESENTER_TOKEN],
  },
  {
    provide: ImportRaceResultsApiUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      resultRepo: IResultRepository,
      driverRepo: IDriverRepository,
      standingRepo: IStandingRepository,
      logger: Logger,
      presenter: ImportRaceResultsApiPresenter,
    ) => {
      return new ImportRaceResultsApiUseCase(
        raceRepo,
        leagueRepo,
        resultRepo,
        driverRepo,
        standingRepo,
        logger,
        new ImportRaceResultsApiOutputAdapter(presenter)
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      DRIVER_REPOSITORY_TOKEN,
      STANDING_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
      IMPORT_RACE_RESULTS_API_PRESENTER_TOKEN,
    ],
  },
  {
    provide: GetRaceDetailUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      driverRepo: IDriverRepository,
      raceRegRepo: IRaceRegistrationRepository,
      resultRepo: IResultRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      presenter: RaceDetailPresenter,
    ) => {
      return new GetRaceDetailUseCase(
        raceRepo,
        leagueRepo,
        driverRepo,
        raceRegRepo,
        resultRepo,
        leagueMembershipRepo,
        new RaceDetailOutputAdapter(presenter),
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      DRIVER_REPOSITORY_TOKEN,
      RACE_REGISTRATION_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      RACE_DETAIL_PRESENTER_TOKEN,
    ],
  },
  {
    provide: GetRacesPageDataUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      logger: Logger,
      presenter: RacesPageDataPresenter,
    ) => {
      return new GetRacesPageDataUseCase(
        raceRepo,
        leagueRepo,
        logger,
        new RacesPageDataOutputAdapter(presenter)
      );
    },
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN, LOGGER_TOKEN, RACES_PAGE_DATA_PRESENTER_TOKEN],
  },
  {
    provide: GetAllRacesPageDataUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      logger: Logger,
      presenter: AllRacesPageDataPresenter,
    ) => {
      return new GetAllRacesPageDataUseCase(
        raceRepo,
        leagueRepo,
        logger,
        new AllRacesPageDataOutputAdapter(presenter)
      );
    },
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN, LOGGER_TOKEN, ALL_RACES_PAGE_DATA_PRESENTER_TOKEN],
  },
  {
    provide: GetRaceResultsDetailUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      resultRepo: IResultRepository,
      driverRepo: IDriverRepository,
      penaltyRepo: IPenaltyRepository,
      presenter: RaceResultsDetailPresenter,
    ) => {
      return new GetRaceResultsDetailUseCase(
        raceRepo,
        leagueRepo,
        resultRepo,
        driverRepo,
        penaltyRepo,
        new RaceResultsDetailOutputAdapter(presenter)
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      DRIVER_REPOSITORY_TOKEN,
      PENALTY_REPOSITORY_TOKEN,
      RACE_RESULTS_DETAIL_PRESENTER_TOKEN,
    ],
  },
  {
    provide: GetRaceWithSOFUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      raceRegRepo: IRaceRegistrationRepository,
      resultRepo: IResultRepository,
      driverRatingProvider: DriverRatingProvider,
      presenter: RaceWithSOFPresenter,
    ) => {
      return new GetRaceWithSOFUseCase(
        raceRepo,
        raceRegRepo,
        resultRepo,
        async (input: { driverId: string }) => {
          const rating = driverRatingProvider.getRating(input.driverId);
          return { rating };
        },
        new RaceWithSOFOutputAdapter(presenter)
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      RACE_REGISTRATION_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      DRIVER_RATING_PROVIDER_TOKEN,
      RACE_WITH_SOF_PRESENTER_TOKEN,
    ],
  },
  {
    provide: GetRaceProtestsUseCase,
    useFactory: (
      protestRepo: IProtestRepository,
      driverRepo: IDriverRepository,
      presenter: RaceProtestsPresenter,
    ) => {
      return new GetRaceProtestsUseCase(
        protestRepo,
        driverRepo,
        new RaceProtestsOutputAdapter(presenter)
      );
    },
    inject: [PROTEST_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, RACE_PROTESTS_PRESENTER_TOKEN],
  },
  {
    provide: GetRacePenaltiesUseCase,
    useFactory: (
      penaltyRepo: IPenaltyRepository,
      driverRepo: IDriverRepository,
      presenter: RacePenaltiesPresenter,
    ) => {
      return new GetRacePenaltiesUseCase(
        penaltyRepo,
        driverRepo,
        new RacePenaltiesOutputAdapter(presenter)
      );
    },
    inject: [PENALTY_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, RACE_PENALTIES_PRESENTER_TOKEN],
  },
  {
    provide: RegisterForRaceUseCase,
    useFactory: (
      raceRegRepo: IRaceRegistrationRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new RegisterForRaceUseCase(
        raceRegRepo,
        leagueMembershipRepo,
        logger,
        new RegisterForRaceOutputAdapter(presenter)
      );
    },
    inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: WithdrawFromRaceUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      raceRegRepo: IRaceRegistrationRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new WithdrawFromRaceUseCase(
        raceRepo,
        raceRegRepo,
        logger,
        new WithdrawFromRaceOutputAdapter(presenter)
      );
    },
    inject: [RACE_REPOSITORY_TOKEN, RACE_REGISTRATION_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: CancelRaceUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new CancelRaceUseCase(
        raceRepo,
        logger,
        new CancelRaceOutputAdapter(presenter)
      );
    },
    inject: [RACE_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: CompleteRaceUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      raceRegRepo: IRaceRegistrationRepository,
      resultRepo: IResultRepository,
      standingRepo: IStandingRepository,
      driverRatingProvider: DriverRatingProvider,
      presenter: CommandResultPresenter,
    ) => {
      return new CompleteRaceUseCase(
        raceRepo,
        raceRegRepo,
        resultRepo,
        standingRepo,
        async (input: { driverId: string }) => {
          const rating = driverRatingProvider.getRating(input.driverId);
          return { rating, ratingChange: null };
        },
        new CompleteRaceOutputAdapter(presenter)
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      RACE_REGISTRATION_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      STANDING_REPOSITORY_TOKEN,
      DRIVER_RATING_PROVIDER_TOKEN,
      COMMAND_RESULT_PRESENTER_TOKEN,
    ],
  },
  {
    provide: ReopenRaceUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new ReopenRaceUseCase(
        raceRepo,
        logger,
        new ReopenRaceOutputAdapter(presenter)
      );
    },
    inject: [RACE_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: ImportRaceResultsUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      resultRepo: IResultRepository,
      driverRepo: IDriverRepository,
      standingRepo: IStandingRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new ImportRaceResultsUseCase(
        raceRepo,
        leagueRepo,
        resultRepo,
        driverRepo,
        standingRepo,
        logger,
        new ImportRaceResultsOutputAdapter(presenter)
      );
    },
    inject: [
      RACE_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      DRIVER_REPOSITORY_TOKEN,
      STANDING_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
      COMMAND_RESULT_PRESENTER_TOKEN,
    ],
  },
  {
    provide: FileProtestUseCase,
    useFactory: (
      protestRepo: IProtestRepository,
      raceRepo: IRaceRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      presenter: CommandResultPresenter,
    ) => {
      return new FileProtestUseCase(
        protestRepo,
        raceRepo,
        leagueMembershipRepo,
        new FileProtestOutputAdapter(presenter)
      );
    },
    inject: [PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: QuickPenaltyUseCase,
    useFactory: (
      penaltyRepo: IPenaltyRepository,
      raceRepo: IRaceRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new QuickPenaltyUseCase(
        penaltyRepo,
        raceRepo,
        leagueMembershipRepo,
        logger,
        new QuickPenaltyOutputAdapter(presenter)
      );
    },
    inject: [PENALTY_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: ApplyPenaltyUseCase,
    useFactory: (
      penaltyRepo: IPenaltyRepository,
      protestRepo: IProtestRepository,
      raceRepo: IRaceRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new ApplyPenaltyUseCase(
        penaltyRepo,
        protestRepo,
        raceRepo,
        leagueMembershipRepo,
        logger,
        new ApplyPenaltyOutputAdapter(presenter)
      );
    },
    inject: [PENALTY_REPOSITORY_TOKEN, PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: RequestProtestDefenseUseCase,
    useFactory: (
      protestRepo: IProtestRepository,
      raceRepo: IRaceRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new RequestProtestDefenseUseCase(
        protestRepo,
        raceRepo,
        leagueMembershipRepo,
        logger,
        new RequestProtestDefenseOutputAdapter(presenter)
      );
    },
    inject: [PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
  {
    provide: ReviewProtestUseCase,
    useFactory: (
      protestRepo: IProtestRepository,
      raceRepo: IRaceRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      logger: Logger,
      presenter: CommandResultPresenter,
    ) => {
      return new ReviewProtestUseCase(
        protestRepo,
        raceRepo,
        leagueMembershipRepo,
        logger,
        new ReviewProtestOutputAdapter(presenter)
      );
    },
    inject: [PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
  },
];