import { Provider } from '@nestjs/common';
import { RaceService } from './RaceService';

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

// Import concrete in-memory implementations
import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository';
import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository';
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository';
import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository';
import { InMemoryPenaltyRepository } from '@adapters/racing/persistence/inmemory/InMemoryPenaltyRepository';
import { InMemoryProtestRepository } from '@adapters/racing/persistence/inmemory/InMemoryProtestRepository';
import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';

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

// Define injection tokens
export const RACE_REPOSITORY_TOKEN = 'IRaceRepository';
export const LEAGUE_REPOSITORY_TOKEN = 'ILeagueRepository';
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
export const RACE_REGISTRATION_REPOSITORY_TOKEN = 'IRaceRegistrationRepository';
export const RESULT_REPOSITORY_TOKEN = 'IResultRepository';
export const LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN = 'ILeagueMembershipRepository';
export const PENALTY_REPOSITORY_TOKEN = 'IPenaltyRepository';
export const PROTEST_REPOSITORY_TOKEN = 'IProtestRepository';
export const DRIVER_RATING_PROVIDER_TOKEN = 'DriverRatingProvider';
export const IMAGE_SERVICE_TOKEN = 'IImageServicePort';
export const LOGGER_TOKEN = 'Logger';

export const RaceProviders: Provider[] = [
  RaceService,
  {
    provide: RACE_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryRaceRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LEAGUE_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: DRIVER_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: RACE_REGISTRATION_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: RESULT_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryResultRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: PENALTY_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryPenaltyRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: PROTEST_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryProtestRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    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,
  },
  // Use cases
  {
    provide: GetAllRacesUseCase,
    useFactory: (raceRepo: IRaceRepository, leagueRepo: ILeagueRepository) => new GetAllRacesUseCase(raceRepo, leagueRepo),
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN],
  },
  {
    provide: GetTotalRacesUseCase,
    useFactory: (raceRepo: IRaceRepository) => new GetTotalRacesUseCase(raceRepo),
    inject: [RACE_REPOSITORY_TOKEN],
  },
  {
    provide: GetRaceDetailUseCase,
    useFactory: (
      raceRepo: IRaceRepository,
      leagueRepo: ILeagueRepository,
      driverRepo: IDriverRepository,
      raceRegRepo: IRaceRegistrationRepository,
      resultRepo: IResultRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      driverRatingProvider: DriverRatingProvider,
      imageService: IImageServicePort,
    ) => new GetRaceDetailUseCase(
      raceRepo,
      leagueRepo,
      driverRepo,
      raceRegRepo,
      resultRepo,
      leagueMembershipRepo,
      driverRatingProvider,
      imageService,
    ),
    inject: [
      RACE_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      DRIVER_REPOSITORY_TOKEN,
      RACE_REGISTRATION_REPOSITORY_TOKEN,
      RESULT_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      DRIVER_RATING_PROVIDER_TOKEN,
      IMAGE_SERVICE_TOKEN,
    ],
  },
  {
    provide: GetRacesPageDataUseCase,
    useFactory: (raceRepo: IRaceRepository, leagueRepo: ILeagueRepository) => new GetRacesPageDataUseCase(raceRepo, leagueRepo),
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN],
  },
  {
    provide: GetAllRacesPageDataUseCase,
    useFactory: (raceRepo: IRaceRepository, leagueRepo: ILeagueRepository) => new GetAllRacesPageDataUseCase(raceRepo, leagueRepo),
    inject: [RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN],
  },
  {
    provide: GetRaceResultsDetailUseCase,
    useFactory: (resultRepo: IResultRepository, driverRepo: IDriverRepository, imageService: IImageServicePort) =>
      new GetRaceResultsDetailUseCase(resultRepo, driverRepo, imageService),
    inject: [RESULT_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, IMAGE_SERVICE_TOKEN],
  },
  {
    provide: GetRaceWithSOFUseCase,
    useFactory: (raceRepo: IRaceRepository) => new GetRaceWithSOFUseCase(raceRepo),
    inject: [RACE_REPOSITORY_TOKEN],
  },
  {
    provide: GetRaceProtestsUseCase,
    useFactory: (protestRepo: IProtestRepository, driverRepo: IDriverRepository) => new GetRaceProtestsUseCase(protestRepo, driverRepo),
    inject: [PROTEST_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN],
  },
  {
    provide: GetRacePenaltiesUseCase,
    useFactory: (penaltyRepo: IPenaltyRepository, driverRepo: IDriverRepository) => new GetRacePenaltiesUseCase(penaltyRepo, driverRepo),
    inject: [PENALTY_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN],
  },
  {
    provide: RegisterForRaceUseCase,
    useFactory: (raceRegRepo: IRaceRegistrationRepository, leagueMembershipRepo: ILeagueMembershipRepository, logger: Logger) =>
      new RegisterForRaceUseCase(raceRegRepo, leagueMembershipRepo, logger),
    inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: WithdrawFromRaceUseCase,
    useFactory: (raceRegRepo: IRaceRegistrationRepository, logger: Logger) => new WithdrawFromRaceUseCase(raceRegRepo, logger),
    inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: CancelRaceUseCase,
    useFactory: (raceRepo: IRaceRepository, logger: Logger) => new CancelRaceUseCase(raceRepo, logger),
    inject: [RACE_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: CompleteRaceUseCase,
    useFactory: (raceRepo: IRaceRepository, logger: Logger) => new CompleteRaceUseCase(raceRepo, logger),
    inject: [RACE_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  ImportRaceResultsApiUseCase,
  ImportRaceResultsUseCase,
  {
    provide: FileProtestUseCase,
    useFactory: (protestRepo: IProtestRepository, raceRepo: IRaceRepository, driverRepo: IDriverRepository, logger: Logger) =>
      new FileProtestUseCase(protestRepo, raceRepo, driverRepo, logger),
    inject: [PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: QuickPenaltyUseCase,
    useFactory: (penaltyRepo: IPenaltyRepository, raceRepo: IRaceRepository, leagueMembershipRepo: ILeagueMembershipRepository, logger: Logger) =>
      new QuickPenaltyUseCase(penaltyRepo, raceRepo, leagueMembershipRepo, logger),
    inject: [PENALTY_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: ApplyPenaltyUseCase,
    useFactory: (penaltyRepo: IPenaltyRepository, protestRepo: IProtestRepository, raceRepo: IRaceRepository, leagueMembershipRepo: ILeagueMembershipRepository, logger: Logger) =>
      new ApplyPenaltyUseCase(penaltyRepo, protestRepo, raceRepo, leagueMembershipRepo, logger),
    inject: [PENALTY_REPOSITORY_TOKEN, PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: RequestProtestDefenseUseCase,
    useFactory: (protestRepo: IProtestRepository, raceRepo: IRaceRepository, leagueMembershipRepo: ILeagueMembershipRepository) =>
      new RequestProtestDefenseUseCase(protestRepo, raceRepo, leagueMembershipRepo),
    inject: [PROTEST_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN],
  },
];
