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

// Import core interfaces
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
import { IRankingService } from '@core/racing/domain/services/IRankingService';
import { IDriverStatsService } from '@core/racing/domain/services/IDriverStatsService';
import { DriverRatingProvider } from '@core/racing/application/ports/DriverRatingProvider';
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
import { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
import { INotificationPreferenceRepository } from '@core/notifications/domain/repositories/INotificationPreferenceRepository';
import type { Logger } from "@gridpilot/core/shared/application";

// Import use cases
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
import { GetProfileOverviewUseCase } from '@core/racing/application/use-cases/GetProfileOverviewUseCase';
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';

// Import concrete in-memory implementations
import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryRankingService } from '../../..//racing/services/InMemoryRankingService';
import { InMemoryDriverStatsService } from '../../..//racing/services/InMemoryDriverStatsService';
import { InMemoryDriverRatingProvider } from '../../..//racing/ports/InMemoryDriverRatingProvider';
import { InMemoryImageServiceAdapter } from '../../..//media/ports/InMemoryImageServiceAdapter';
import { InMemoryRaceRegistrationRepository } from '../../..//racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
import { InMemoryNotificationPreferenceRepository } from '../../..//notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
import { ConsoleLogger } from '../../..//logging/ConsoleLogger';

// Define injection tokens
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
export const RANKING_SERVICE_TOKEN = 'IRankingService';
export const DRIVER_STATS_SERVICE_TOKEN = 'IDriverStatsService';
export const DRIVER_RATING_PROVIDER_TOKEN = 'DriverRatingProvider';
export const IMAGE_SERVICE_PORT_TOKEN = 'IImageServicePort';
export const RACE_REGISTRATION_REPOSITORY_TOKEN = 'IRaceRegistrationRepository';
export const NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN = 'INotificationPreferenceRepository';
export const LOGGER_TOKEN = 'Logger'; // Already defined in AuthProviders, but good to have here too

// Use case tokens
export const GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN = 'GetDriversLeaderboardUseCase';
export const GET_TOTAL_DRIVERS_USE_CASE_TOKEN = 'GetTotalDriversUseCase';
export const COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN = 'CompleteDriverOnboardingUseCase';
export const IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN = 'IsDriverRegisteredForRaceUseCase';
export const GET_PROFILE_OVERVIEW_USE_CASE_TOKEN = 'GetProfileOverviewUseCase';
export const GET_DRIVER_TEAM_USE_CASE_TOKEN = 'GetDriverTeamUseCase';
export const UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN = 'UpdateDriverProfileUseCase';

export const DriverProviders: Provider[] = [
  DriverService, // Provide the service itself
  {
    provide: DRIVER_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), // Factory for InMemoryDriverRepository
    inject: [LOGGER_TOKEN],
  },
  {
    provide: RANKING_SERVICE_TOKEN,
    useFactory: (logger: Logger) => new InMemoryRankingService(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: DRIVER_STATS_SERVICE_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverStatsService(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: DRIVER_RATING_PROVIDER_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverRatingProvider(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: IMAGE_SERVICE_PORT_TOKEN,
    useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: RACE_REGISTRATION_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryNotificationPreferenceRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LOGGER_TOKEN,
    useClass: ConsoleLogger,
  },
  // Use cases
  {
    provide: GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository, rankingService: IRankingService, driverStatsService: IDriverStatsService, imageService: IImageServicePort) =>
      new GetDriversLeaderboardUseCase(driverRepo, rankingService, driverStatsService, imageService),
    inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, IMAGE_SERVICE_PORT_TOKEN],
  },
  {
    provide: GET_TOTAL_DRIVERS_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository) => new GetTotalDriversUseCase(driverRepo),
    inject: [DRIVER_REPOSITORY_TOKEN],
  },
  {
    provide: COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository) => new CompleteDriverOnboardingUseCase(driverRepo),
    inject: [DRIVER_REPOSITORY_TOKEN],
  },
  {
    provide: IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN,
    useFactory: (registrationRepo: IRaceRegistrationRepository) => new IsDriverRegisteredForRaceUseCase(registrationRepo),
    inject: [RACE_REGISTRATION_REPOSITORY_TOKEN],
  },
  {
    provide: UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository) => new UpdateDriverProfileUseCase(driverRepo),
    inject: [DRIVER_REPOSITORY_TOKEN],
  },
];
