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

// Import core interfaces
import type { NotificationService } from '@core/notifications/application/ports/NotificationService';
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
import type { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
// Remove the missing import
// import { IPaymentGateway } from '@core/payments/domain/ports/IPaymentGateway';
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
import { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
import { ILeagueWalletRepository } from '@core/racing/domain/repositories/ILeagueWalletRepository';
import { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository';
import { ISeasonRepository } from '@core/racing/domain/repositories/ISeasonRepository';
import { ISeasonSponsorshipRepository } from '@core/racing/domain/repositories/ISeasonSponsorshipRepository';
import { ISponsorRepository } from '@core/racing/domain/repositories/ISponsorRepository';
import { ISponsorshipPricingRepository } from '@core/racing/domain/repositories/ISponsorshipPricingRepository';
import { ISponsorshipRequestRepository } from '@core/racing/domain/repositories/ISponsorshipRequestRepository';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';

import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase';
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
import { GetEntitySponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
import { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';

// Import concrete in-memory implementations
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { InMemoryPaymentRepository } from '@adapters/payments/persistence/inmemory/InMemoryPaymentRepository';
import { InMemoryWalletRepository } from '@adapters/payments/persistence/inmemory/InMemoryWalletRepository';

// Import presenters
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';

// Define injection tokens
export const SPONSOR_REPOSITORY_TOKEN = 'ISponsorRepository';
export const SEASON_SPONSORSHIP_REPOSITORY_TOKEN = 'ISeasonSponsorshipRepository';
export const SEASON_REPOSITORY_TOKEN = 'ISeasonRepository';
export const LEAGUE_REPOSITORY_TOKEN = 'ILeagueRepository';
export const LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN = 'ILeagueMembershipRepository';
export const RACE_REPOSITORY_TOKEN = 'IRaceRepository';
export const SPONSORSHIP_PRICING_REPOSITORY_TOKEN = 'ISponsorshipPricingRepository';
export const SPONSORSHIP_REQUEST_REPOSITORY_TOKEN = 'ISponsorshipRequestRepository';
export const PAYMENT_REPOSITORY_TOKEN = 'IPaymentRepository';
export const WALLET_REPOSITORY_TOKEN = 'IWalletRepository';
export const LEAGUE_WALLET_REPOSITORY_TOKEN = 'ILeagueWalletRepository';
export const NOTIFICATION_SERVICE_TOKEN = 'INotificationService';
export const LOGGER_TOKEN = 'Logger';

// Presenter tokens
export const GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN = 'GetEntitySponsorshipPricingPresenter';
export const GET_SPONSORS_PRESENTER_TOKEN = 'GetSponsorsPresenter';
export const CREATE_SPONSOR_PRESENTER_TOKEN = 'CreateSponsorPresenter';
export const GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN = 'GetSponsorDashboardPresenter';
export const GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN = 'GetSponsorSponsorshipsPresenter';
export const GET_SPONSOR_PRESENTER_TOKEN = 'GetSponsorPresenter';
export const GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN = 'GetPendingSponsorshipRequestsPresenter';
export const ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'AcceptSponsorshipRequestPresenter';
export const REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'RejectSponsorshipRequestPresenter';
export const GET_SPONSOR_BILLING_PRESENTER_TOKEN = 'SponsorBillingPresenter';

// Use case / application service tokens
export const GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN = 'GetSponsorshipPricingUseCase';
export const GET_SPONSORS_USE_CASE_TOKEN = 'GetSponsorsUseCase';
export const CREATE_SPONSOR_USE_CASE_TOKEN = 'CreateSponsorUseCase';
export const GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN = 'GetSponsorDashboardUseCase';
export const GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN = 'GetSponsorSponsorshipsUseCase';
export const GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN = 'GetEntitySponsorshipPricingUseCase';
export const GET_SPONSOR_USE_CASE_TOKEN = 'GetSponsorUseCase';
export const GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN = 'GetPendingSponsorshipRequestsUseCase';
export const ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'AcceptSponsorshipRequestUseCase';
export const REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'RejectSponsorshipRequestUseCase';
export const GET_SPONSOR_BILLING_USE_CASE_TOKEN = 'GetSponsorBillingUseCase';

// Output port tokens
export const GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetSponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSORS_OUTPUT_PORT_TOKEN = 'GetSponsorsOutputPort_TOKEN';
export const CREATE_SPONSOR_OUTPUT_PORT_TOKEN = 'CreateSponsorOutputPort_TOKEN';
export const GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN = 'GetSponsorDashboardOutputPort_TOKEN';
export const GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN = 'GetSponsorSponsorshipsOutputPort_TOKEN';
export const GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetEntitySponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSOR_OUTPUT_PORT_TOKEN = 'GetSponsorOutputPort_TOKEN';
export const GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN = 'GetPendingSponsorshipRequestsOutputPort_TOKEN';
export const ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'AcceptSponsorshipRequestOutputPort_TOKEN';
export const REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'RejectSponsorshipRequestOutputPort_TOKEN';
export const GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN = 'GetSponsorBillingOutputPort_TOKEN';

export const SponsorProviders: Provider[] = [
  SponsorService,
  // Repositories (payments repos are local to this module; racing repos come from InMemoryRacingPersistenceModule)
  {
    provide: PAYMENT_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryPaymentRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: WALLET_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => new InMemoryWalletRepository(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: NOTIFICATION_SERVICE_TOKEN,
    useFactory: (logger: Logger): NotificationService => ({
      async sendNotification(command: Parameters<NotificationService['sendNotification']>[0]): Promise<void> {
        logger.info('[InMemoryNotificationService] sendNotification', { command });
      },
    }),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LOGGER_TOKEN,
    useClass: ConsoleLogger,
  },
  // Presenters
  GetEntitySponsorshipPricingPresenter,
  GetSponsorsPresenter,
  CreateSponsorPresenter,
  GetSponsorDashboardPresenter,
  GetSponsorSponsorshipsPresenter,
  GetSponsorPresenter,
  GetPendingSponsorshipRequestsPresenter,
  AcceptSponsorshipRequestPresenter,
  RejectSponsorshipRequestPresenter,
  SponsorBillingPresenter,
  // Output ports
  {
    provide: GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
    useExisting: GetEntitySponsorshipPricingPresenter,
  },
  {
    provide: GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
    useExisting: GetEntitySponsorshipPricingPresenter,
  },
  {
    provide: GET_SPONSORS_OUTPUT_PORT_TOKEN,
    useExisting: GetSponsorsPresenter,
  },
  {
    provide: CREATE_SPONSOR_OUTPUT_PORT_TOKEN,
    useExisting: CreateSponsorPresenter,
  },
  {
    provide: GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN,
    useExisting: GetSponsorDashboardPresenter,
  },
  {
    provide: GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN,
    useExisting: GetSponsorSponsorshipsPresenter,
  },
  {
    provide: GET_SPONSOR_OUTPUT_PORT_TOKEN,
    useExisting: GetSponsorPresenter,
  },
  {
    provide: GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN,
    useExisting: GetPendingSponsorshipRequestsPresenter,
  },
  {
    provide: ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
    useExisting: AcceptSponsorshipRequestPresenter,
  },
  {
    provide: REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
    useExisting: RejectSponsorshipRequestPresenter,
  },
  {
    provide: GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN,
    useExisting: SponsorBillingPresenter,
  },
  // Use cases
  {
    provide: GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
    useFactory: (output: UseCaseOutputPort<unknown>) => new GetSponsorshipPricingUseCase(output),
    inject: [GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_SPONSORS_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<unknown>) => new GetSponsorsUseCase(sponsorRepo, output),
    inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSORS_OUTPUT_PORT_TOKEN],
  },
  {
    provide: CREATE_SPONSOR_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: ISponsorRepository, logger: Logger, output: UseCaseOutputPort<unknown>) => new CreateSponsorUseCase(sponsorRepo, logger, output),
    inject: [SPONSOR_REPOSITORY_TOKEN, LOGGER_TOKEN, CREATE_SPONSOR_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
    useFactory: (
      sponsorRepo: ISponsorRepository,
      seasonSponsorshipRepo: ISeasonSponsorshipRepository,
      seasonRepo: ISeasonRepository,
      leagueRepo: ILeagueRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      raceRepo: IRaceRepository,
      output: UseCaseOutputPort<unknown>,
    ) => new GetSponsorDashboardUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
    inject: [
      SPONSOR_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      RACE_REPOSITORY_TOKEN,
      GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
    useFactory: (
      sponsorRepo: ISponsorRepository,
      seasonSponsorshipRepo: ISeasonSponsorshipRepository,
      seasonRepo: ISeasonRepository,
      leagueRepo: ILeagueRepository,
      leagueMembershipRepo: ILeagueMembershipRepository,
      raceRepo: IRaceRepository,
      output: UseCaseOutputPort<unknown>,
    ) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
    inject: [
      SPONSOR_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      RACE_REPOSITORY_TOKEN,
      GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_BILLING_USE_CASE_TOKEN,
    useFactory: (
      paymentRepo: IPaymentRepository,
      seasonSponsorshipRepo: ISeasonSponsorshipRepository,
    ) => {
      return new GetSponsorBillingUseCase(paymentRepo, seasonSponsorshipRepo);
    },
    inject: [PAYMENT_REPOSITORY_TOKEN, SEASON_SPONSORSHIP_REPOSITORY_TOKEN],
  },
  {
    provide: GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipPricingRepo: ISponsorshipPricingRepository,
      logger: Logger,
      output: UseCaseOutputPort<unknown>,
    ) => new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, logger, output),
    inject: [
      SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
      GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<unknown>) => new GetSponsorUseCase(sponsorRepo, output),
    inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSOR_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: ISponsorshipRequestRepository,
      sponsorRepo: ISponsorRepository,
      output: UseCaseOutputPort<unknown>,
    ) => new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo, output),
    inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN],
  },
  {
    provide: ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: ISponsorshipRequestRepository,
      seasonSponsorshipRepo: ISeasonSponsorshipRepository,
      seasonRepo: ISeasonRepository,
      notificationService: NotificationService,
      walletRepository: IWalletRepository,
      leagueWalletRepository: ILeagueWalletRepository,
      logger: Logger,
      output: UseCaseOutputPort<unknown>,
    ) => {
      // Create a mock payment processor function
      const paymentProcessor = async (input: unknown) => {
        void input;
        return { success: true, transactionId: `txn_${Date.now()}` };
      };
      
      return new AcceptSponsorshipRequestUseCase(
        sponsorshipRequestRepo,
        seasonSponsorshipRepo,
        seasonRepo,
        notificationService,
        paymentProcessor,
        walletRepository,
        leagueWalletRepository,
        logger,
        output
      );
    },
    inject: [
      SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      NOTIFICATION_SERVICE_TOKEN,
      WALLET_REPOSITORY_TOKEN,
      LEAGUE_WALLET_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
      ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
    ],
  },
  {
    provide: REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: ISponsorshipRequestRepository,
      logger: Logger,
      output: UseCaseOutputPort<unknown>,
    ) => new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger, output),
    inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN, REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN],
  },
];