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

// Import core interfaces
import { DriverExtendedProfileProvider } from '@core/racing/application/ports/DriverExtendedProfileProvider';
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
import { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository';
import type { MediaResolverPort } from '@core/ports/media/MediaResolverPort';

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

// Import concrete in-memory implementations
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { InMemoryNotificationPreferenceRepository } from '@adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
import { InMemoryDriverExtendedProfileProvider } from '@adapters/racing/ports/InMemoryDriverExtendedProfileProvider';
import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider';
// Import new use cases
import { RankingUseCase } from '@core/racing/application/use-cases/RankingUseCase';
import { DriverStatsUseCase } from '@core/racing/application/use-cases/DriverStatsUseCase';
// Import new repositories
import { InMemoryDriverStatsRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverStatsRepository';
import { InMemoryMediaRepository } from '@adapters/racing/persistence/media/InMemoryMediaRepository';
import { MediaResolverAdapter } from '@adapters/media/MediaResolverAdapter';
// Import repository tokens
import { IDriverStatsRepository } from '@core/racing/domain/repositories/IDriverStatsRepository';
// Import use case interfaces
import type { IRankingUseCase } from '@core/racing/application/use-cases/IRankingUseCase';
import type { IDriverStatsUseCase } from '@core/racing/application/use-cases/IDriverStatsUseCase';

// Import presenters
import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPresenter';
import { DriverPresenter } from './presenters/DriverPresenter';
import { DriverProfilePresenter } from './presenters/DriverProfilePresenter';
import { DriverRegistrationStatusPresenter } from './presenters/DriverRegistrationStatusPresenter';
import { DriversLeaderboardPresenter } from './presenters/DriversLeaderboardPresenter';
import { DriverStatsPresenter } from './presenters/DriverStatsPresenter';

import {
  DRIVER_REPOSITORY_TOKEN,
  DRIVER_RATING_PROVIDER_TOKEN,
  DRIVER_EXTENDED_PROFILE_PROVIDER_TOKEN,
  IMAGE_SERVICE_PORT_TOKEN,
  RACE_REGISTRATION_REPOSITORY_TOKEN,
  NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
  TEAM_REPOSITORY_TOKEN,
  TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
  SOCIAL_GRAPH_REPOSITORY_TOKEN,
  LOGGER_TOKEN,
  GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN,
  GET_TOTAL_DRIVERS_USE_CASE_TOKEN,
  COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN,
  IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN,
  UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,
  GET_PROFILE_OVERVIEW_USE_CASE_TOKEN,
  GET_DRIVERS_LEADERBOARD_OUTPUT_PORT_TOKEN,
  GET_TOTAL_DRIVERS_OUTPUT_PORT_TOKEN,
  COMPLETE_DRIVER_ONBOARDING_OUTPUT_PORT_TOKEN,
  IS_DRIVER_REGISTERED_FOR_RACE_OUTPUT_PORT_TOKEN,
  UPDATE_DRIVER_PROFILE_OUTPUT_PORT_TOKEN,
  GET_PROFILE_OVERVIEW_OUTPUT_PORT_TOKEN,
  DRIVER_STATS_REPOSITORY_TOKEN,
  MEDIA_REPOSITORY_TOKEN,
  RANKING_SERVICE_TOKEN,
  DRIVER_STATS_SERVICE_TOKEN,
  MEDIA_RESOLVER_TOKEN,
} from './DriverTokens';

export * from './DriverTokens';

export const DriverProviders: Provider[] = [
  
  // Presenters
  {
    provide: DriversLeaderboardPresenter,
    useFactory: (mediaResolver: MediaResolverPort) => {
      const presenter = new DriversLeaderboardPresenter();
      presenter.setMediaResolver(mediaResolver);
      return presenter;
    },
    inject: [MEDIA_RESOLVER_TOKEN],
  },
  DriverStatsPresenter,
  CompleteOnboardingPresenter,
  DriverRegistrationStatusPresenter,
  {
    provide: DriverPresenter,
    useFactory: (driverStatsRepository: IDriverStatsRepository, mediaResolver: MediaResolverPort) => {
      const presenter = new DriverPresenter(driverStatsRepository, mediaResolver);
      return presenter;
    },
    inject: [DRIVER_STATS_REPOSITORY_TOKEN, MEDIA_RESOLVER_TOKEN],
  },
  {
    provide: DriverProfilePresenter,
    useFactory: (mediaResolver: MediaResolverPort) => {
      const presenter = new DriverProfilePresenter(mediaResolver);
      return presenter;
    },
    inject: [MEDIA_RESOLVER_TOKEN],
  },

  // Output ports (point to presenters)
  {
    provide: GET_DRIVERS_LEADERBOARD_OUTPUT_PORT_TOKEN,
    useExisting: DriversLeaderboardPresenter,
  },
  {
    provide: GET_TOTAL_DRIVERS_OUTPUT_PORT_TOKEN,
    useExisting: DriverStatsPresenter,
  },
  {
    provide: COMPLETE_DRIVER_ONBOARDING_OUTPUT_PORT_TOKEN,
    useExisting: CompleteOnboardingPresenter,
  },
  {
    provide: IS_DRIVER_REGISTERED_FOR_RACE_OUTPUT_PORT_TOKEN,
    useExisting: DriverRegistrationStatusPresenter,
  },
  {
    provide: UPDATE_DRIVER_PROFILE_OUTPUT_PORT_TOKEN,
    useExisting: DriverPresenter,
  },
  {
    provide: GET_PROFILE_OVERVIEW_OUTPUT_PORT_TOKEN,
    useExisting: DriverProfilePresenter,
  },

  // Logger
  {
    provide: LOGGER_TOKEN,
    useClass: ConsoleLogger,
  },

  // Media Resolver (real adapter, path-only)
  {
    provide: MEDIA_RESOLVER_TOKEN,
    useFactory: () => new MediaResolverAdapter({}),
  },

  // Repositories (racing + social repos are provided by imported persistence modules)
  {
    provide: DRIVER_STATS_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverStatsRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: MEDIA_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => {
      const mediaRepo = new InMemoryMediaRepository(logger);
      
      // Override getTeamLogo to provide fallback URLs
      const originalGetTeamLogo = mediaRepo.getTeamLogo.bind(mediaRepo);
      mediaRepo.getTeamLogo = async (teamId: string): Promise<string | null> => {
        const logo = await originalGetTeamLogo(teamId);
        if (logo) return logo;
        
        // Fallback: generate deterministic team logo URL
        // Use path-only URL
        return `/media/teams/${teamId}/logo`;
      };
      
      return mediaRepo;
    },
    inject: [LOGGER_TOKEN],
  },
  {
    provide: RANKING_SERVICE_TOKEN,
    useFactory: (
      standingRepo: IStandingRepository,
      driverRepo: IDriverRepository,
      logger: Logger
    ) => new RankingUseCase(standingRepo, driverRepo, logger),
    inject: ['IStandingRepository', DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: DRIVER_STATS_SERVICE_TOKEN,
    useFactory: (
      resultRepo: IResultRepository,
      standingRepo: IStandingRepository,
      logger: Logger
    ) => new DriverStatsUseCase(resultRepo, standingRepo, logger),
    inject: ['IResultRepository', 'IStandingRepository', LOGGER_TOKEN],
  },
  {
    provide: DRIVER_RATING_PROVIDER_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverRatingProvider(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: DRIVER_EXTENDED_PROFILE_PROVIDER_TOKEN,
    useFactory: (logger: Logger) => new InMemoryDriverExtendedProfileProvider(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: IMAGE_SERVICE_PORT_TOKEN,
    useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryNotificationPreferenceRepository(logger),
    inject: [LOGGER_TOKEN],
  },

  // Use cases
  {
    provide: GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN,
    useFactory: (
      driverRepo: IDriverRepository,
      rankingUseCase: IRankingUseCase,
      driverStatsUseCase: IDriverStatsUseCase,
      logger: Logger,
      output: UseCaseOutputPort<unknown>,
    ) => new GetDriversLeaderboardUseCase(
      driverRepo,
      rankingUseCase,
      driverStatsUseCase,
      logger,
      output
    ),
    inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, LOGGER_TOKEN, GET_DRIVERS_LEADERBOARD_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_TOTAL_DRIVERS_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository, output: UseCaseOutputPort<unknown>) => new GetTotalDriversUseCase(driverRepo, output),
    inject: [DRIVER_REPOSITORY_TOKEN, GET_TOTAL_DRIVERS_OUTPUT_PORT_TOKEN],
  },
  {
    provide: COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository, logger: Logger, output: UseCaseOutputPort<unknown>) => new CompleteDriverOnboardingUseCase(driverRepo, logger, output),
    inject: [DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN, COMPLETE_DRIVER_ONBOARDING_OUTPUT_PORT_TOKEN],
  },
  {
    provide: IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN,
    useFactory: (registrationRepo: IRaceRegistrationRepository, logger: Logger, output: UseCaseOutputPort<unknown>) =>
      new IsDriverRegisteredForRaceUseCase(registrationRepo, logger, output),
    inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LOGGER_TOKEN, IS_DRIVER_REGISTERED_FOR_RACE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,
    useFactory: (driverRepo: IDriverRepository, logger: Logger, output: UseCaseOutputPort<unknown>) =>
      new UpdateDriverProfileUseCase(driverRepo, logger, output),
    inject: [DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN, UPDATE_DRIVER_PROFILE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_PROFILE_OVERVIEW_USE_CASE_TOKEN,
    useFactory: (
      driverRepo: IDriverRepository,
      teamRepository: ITeamRepository,
      teamMembershipRepository: ITeamMembershipRepository,
      socialRepository: ISocialGraphRepository,
      driverExtendedProfileProvider: DriverExtendedProfileProvider,
      driverStatsUseCase: IDriverStatsUseCase,
      rankingUseCase: IRankingUseCase,
      output: UseCaseOutputPort<unknown>,
    ) =>
      new GetProfileOverviewUseCase(
        driverRepo,
        teamRepository,
        teamMembershipRepository,
        socialRepository,
        driverExtendedProfileProvider,
        driverStatsUseCase,
        rankingUseCase,
        output,
      ),
    inject: [
      DRIVER_REPOSITORY_TOKEN,
      TEAM_REPOSITORY_TOKEN,
      TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
      SOCIAL_GRAPH_REPOSITORY_TOKEN,
      DRIVER_EXTENDED_PROFILE_PROVIDER_TOKEN,
      DRIVER_STATS_SERVICE_TOKEN,
      RANKING_SERVICE_TOKEN,
      GET_PROFILE_OVERVIEW_OUTPUT_PORT_TOKEN,
    ],
  },
];