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

// Import core interfaces
import type { MemberPaymentRepository, MembershipFeeRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';
import type { PaymentRepository } from '@core/payments/domain/repositories/PaymentRepository';
import type { PrizeRepository } from '@core/payments/domain/repositories/PrizeRepository';
import type { TransactionRepository, WalletRepository } from '@core/payments/domain/repositories/WalletRepository';

// Import use cases
import { AwardPrizeUseCase } from '@core/payments/application/use-cases/AwardPrizeUseCase';
import { CreatePaymentUseCase } from '@core/payments/application/use-cases/CreatePaymentUseCase';
import { CreatePrizeUseCase } from '@core/payments/application/use-cases/CreatePrizeUseCase';
import { DeletePrizeUseCase } from '@core/payments/application/use-cases/DeletePrizeUseCase';
import { GetMembershipFeesUseCase } from '@core/payments/application/use-cases/GetMembershipFeesUseCase';
import { GetPaymentsUseCase } from '@core/payments/application/use-cases/GetPaymentsUseCase';
import { GetPrizesUseCase } from '@core/payments/application/use-cases/GetPrizesUseCase';
import { GetWalletUseCase } from '@core/payments/application/use-cases/GetWalletUseCase';
import { ProcessWalletTransactionUseCase } from '@core/payments/application/use-cases/ProcessWalletTransactionUseCase';
import { UpdateMemberPaymentUseCase } from '@core/payments/application/use-cases/UpdateMemberPaymentUseCase';
import { UpdatePaymentStatusUseCase } from '@core/payments/application/use-cases/UpdatePaymentStatusUseCase';
import { UpsertMembershipFeeUseCase } from '@core/payments/application/use-cases/UpsertMembershipFeeUseCase';

// Import concrete in-memory implementations
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';

import {
    AWARD_PRIZE_USE_CASE_TOKEN,
    CREATE_PAYMENT_USE_CASE_TOKEN,
    CREATE_PRIZE_USE_CASE_TOKEN,
    DELETE_PRIZE_USE_CASE_TOKEN,
    GET_MEMBERSHIP_FEES_USE_CASE_TOKEN,
    GET_PAYMENTS_USE_CASE_TOKEN,
    GET_PRIZES_USE_CASE_TOKEN,
    GET_WALLET_USE_CASE_TOKEN,
    LOGGER_TOKEN,
    MEMBERSHIP_FEE_REPOSITORY_TOKEN,
    MEMBER_PAYMENT_REPOSITORY_TOKEN,
    PAYMENT_REPOSITORY_TOKEN,
    PRIZE_REPOSITORY_TOKEN,
    PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
    TRANSACTION_REPOSITORY_TOKEN,
    UPDATE_MEMBER_PAYMENT_USE_CASE_TOKEN,
    UPDATE_PAYMENT_STATUS_USE_CASE_TOKEN,
    UPSERT_MEMBERSHIP_FEE_USE_CASE_TOKEN,
    WALLET_REPOSITORY_TOKEN,
} from './PaymentsTokens';

export * from './PaymentsTokens';

export const PaymentsProviders: Provider[] = [

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

  // Repositories are provided by PaymentsPersistenceModule behind tokens.

  // Use cases (use cases receive repositories, services receive use cases)
  {
    provide: GET_PAYMENTS_USE_CASE_TOKEN,
    useFactory: (paymentRepo: PaymentRepository) => new GetPaymentsUseCase(paymentRepo),
    inject: [PAYMENT_REPOSITORY_TOKEN],
  },
  {
    provide: CREATE_PAYMENT_USE_CASE_TOKEN,
    useFactory: (paymentRepo: PaymentRepository) => new CreatePaymentUseCase(paymentRepo),
    inject: [PAYMENT_REPOSITORY_TOKEN],
  },
  {
    provide: UPDATE_PAYMENT_STATUS_USE_CASE_TOKEN,
    useFactory: (paymentRepo: PaymentRepository) => new UpdatePaymentStatusUseCase(paymentRepo),
    inject: [PAYMENT_REPOSITORY_TOKEN],
  },
  {
    provide: GET_MEMBERSHIP_FEES_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: MembershipFeeRepository, memberPaymentRepo: MemberPaymentRepository) =>
      new GetMembershipFeesUseCase(membershipFeeRepo, memberPaymentRepo),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN],
  },
  {
    provide: UPSERT_MEMBERSHIP_FEE_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: MembershipFeeRepository) => new UpsertMembershipFeeUseCase(membershipFeeRepo),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN],
  },
  {
    provide: UPDATE_MEMBER_PAYMENT_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: MembershipFeeRepository, memberPaymentRepo: MemberPaymentRepository) =>
      new UpdateMemberPaymentUseCase(membershipFeeRepo, memberPaymentRepo),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN],
  },
  {
    provide: GET_PRIZES_USE_CASE_TOKEN,
    useFactory: (prizeRepo: PrizeRepository) => new GetPrizesUseCase(prizeRepo),
    inject: [PRIZE_REPOSITORY_TOKEN],
  },
  {
    provide: CREATE_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: PrizeRepository) => new CreatePrizeUseCase(prizeRepo),
    inject: [PRIZE_REPOSITORY_TOKEN],
  },
  {
    provide: AWARD_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: PrizeRepository) => new AwardPrizeUseCase(prizeRepo),
    inject: [PRIZE_REPOSITORY_TOKEN],
  },
  {
    provide: DELETE_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: PrizeRepository) => new DeletePrizeUseCase(prizeRepo),
    inject: [PRIZE_REPOSITORY_TOKEN],
  },
  {
    provide: GET_WALLET_USE_CASE_TOKEN,
    useFactory: (walletRepo: WalletRepository, transactionRepo: TransactionRepository) =>
      new GetWalletUseCase(walletRepo, transactionRepo),
    inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN],
  },
  {
    provide: PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
    useFactory: (walletRepo: WalletRepository, transactionRepo: TransactionRepository) =>
      new ProcessWalletTransactionUseCase(walletRepo, transactionRepo),
    inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN],
  },
];