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

// Import core interfaces
import type { NotificationService } from '@core/notifications/application/ports/NotificationService';
import type { PaymentRepository } from '@core/payments/domain/repositories/PaymentRepository';
import type { WalletRepository } from '@core/payments/domain/repositories/WalletRepository';
import { LeagueMembershipRepository } from '@core/racing/domain/repositories/LeagueMembershipRepository';
import { LeagueRepository } from '@core/racing/domain/repositories/LeagueRepository';
import { LeagueWalletRepository } from '@core/racing/domain/repositories/LeagueWalletRepository';
import { RaceRepository } from '@core/racing/domain/repositories/RaceRepository';
import { SeasonRepository } from '@core/racing/domain/repositories/SeasonRepository';
import { SeasonSponsorshipRepository } from '@core/racing/domain/repositories/SeasonSponsorshipRepository';
import { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository';
import { SponsorshipPricingRepository } from '@core/racing/domain/repositories/SponsorshipPricingRepository';
import { SponsorshipRequestRepository } from '@core/racing/domain/repositories/SponsorshipRequestRepository';
import type { Logger } from '@core/shared/domain/Logger';

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 { 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 {
  SPONSOR_REPOSITORY_TOKEN,
  SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
  SEASON_REPOSITORY_TOKEN,
  LEAGUE_REPOSITORY_TOKEN,
  LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
  RACE_REPOSITORY_TOKEN,
  SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
  SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
  LOGGER_TOKEN,
  GET_SPONSORS_USE_CASE_TOKEN,
  CREATE_SPONSOR_USE_CASE_TOKEN,
  GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
  GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
  GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
  GET_SPONSOR_USE_CASE_TOKEN,
  GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
  ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
  REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
  GET_SPONSOR_BILLING_USE_CASE_TOKEN
} from './SponsorTokens';

// Define local injection tokens
export const PAYMENT_REPOSITORY_TOKEN = 'PaymentRepository';
export const WALLET_REPOSITORY_TOKEN = 'WalletRepository';
export const LEAGUE_WALLET_REPOSITORY_TOKEN = 'ILeagueWalletRepository';
export const NOTIFICATION_SERVICE_TOKEN = 'NotificationService';

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,
  },
  // Use cases
  {
    provide: GET_SPONSORS_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: SponsorRepository) => new GetSponsorsUseCase(sponsorRepo),
    inject: [SPONSOR_REPOSITORY_TOKEN],
  },
  {
    provide: CREATE_SPONSOR_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: SponsorRepository, logger: Logger) => new CreateSponsorUseCase(sponsorRepo, logger),
    inject: [SPONSOR_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
    useFactory: (
      sponsorRepo: SponsorRepository,
      seasonSponsorshipRepo: SeasonSponsorshipRepository,
      seasonRepo: SeasonRepository,
      leagueRepo: LeagueRepository,
      leagueMembershipRepo: LeagueMembershipRepository,
      raceRepo: RaceRepository,
    ) => new GetSponsorDashboardUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
    inject: [
      SPONSOR_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      RACE_REPOSITORY_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
    useFactory: (
      sponsorRepo: SponsorRepository,
      seasonSponsorshipRepo: SeasonSponsorshipRepository,
      seasonRepo: SeasonRepository,
      leagueRepo: LeagueRepository,
      leagueMembershipRepo: LeagueMembershipRepository,
      raceRepo: RaceRepository,
    ) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
    inject: [
      SPONSOR_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      LEAGUE_REPOSITORY_TOKEN,
      LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      RACE_REPOSITORY_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_BILLING_USE_CASE_TOKEN,
    useFactory: (
      paymentRepo: PaymentRepository,
      seasonSponsorshipRepo: SeasonSponsorshipRepository,
    ) => {
      return new GetSponsorBillingUseCase(paymentRepo, seasonSponsorshipRepo);
    },
    inject: [PAYMENT_REPOSITORY_TOKEN, SEASON_SPONSORSHIP_REPOSITORY_TOKEN],
  },
  {
    provide: GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipPricingRepo: SponsorshipPricingRepository,
      logger: Logger,
    ) => new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, logger),
    inject: [
      SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
    ],
  },
  {
    provide: GET_SPONSOR_USE_CASE_TOKEN,
    useFactory: (sponsorRepo: SponsorRepository) => new GetSponsorUseCase(sponsorRepo),
    inject: [SPONSOR_REPOSITORY_TOKEN],
  },
  {
    provide: GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: SponsorshipRequestRepository,
      sponsorRepo: SponsorRepository,
    ) => new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo),
    inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN],
  },
  {
    provide: ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: SponsorshipRequestRepository,
      seasonSponsorshipRepo: SeasonSponsorshipRepository,
      seasonRepo: SeasonRepository,
      notificationService: NotificationService,
      walletRepository: WalletRepository,
      leagueWalletRepository: LeagueWalletRepository,
      logger: Logger,
    ) => {
      // 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
      );
    },
    inject: [
      SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
      SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      SEASON_REPOSITORY_TOKEN,
      NOTIFICATION_SERVICE_TOKEN,
      WALLET_REPOSITORY_TOKEN,
      LEAGUE_WALLET_REPOSITORY_TOKEN,
      LOGGER_TOKEN,
    ],
  },
  {
    provide: REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
    useFactory: (
      sponsorshipRequestRepo: SponsorshipRequestRepository,
      logger: Logger,
    ) => new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger),
    inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
];