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

// Import core interfaces
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
import type { IMembershipFeeRepository, IMemberPaymentRepository } from '@core/payments/domain/repositories/IMembershipFeeRepository';
import type { IPrizeRepository } from '@core/payments/domain/repositories/IPrizeRepository';
import type { IWalletRepository, ITransactionRepository } from '@core/payments/domain/repositories/IWalletRepository';
import type { UseCaseOutputPort } from '@core/shared/application';

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

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

// Presenters
import { GetPaymentsPresenter } from './presenters/GetPaymentsPresenter';
import { CreatePaymentPresenter } from './presenters/CreatePaymentPresenter';
import { UpdatePaymentStatusPresenter } from './presenters/UpdatePaymentStatusPresenter';
import { GetMembershipFeesPresenter } from './presenters/GetMembershipFeesPresenter';
import { UpsertMembershipFeePresenter } from './presenters/UpsertMembershipFeePresenter';
import { UpdateMemberPaymentPresenter } from './presenters/UpdateMemberPaymentPresenter';
import { GetPrizesPresenter } from './presenters/GetPrizesPresenter';
import { CreatePrizePresenter } from './presenters/CreatePrizePresenter';
import { AwardPrizePresenter } from './presenters/AwardPrizePresenter';
import { DeletePrizePresenter } from './presenters/DeletePrizePresenter';
import { GetWalletPresenter } from './presenters/GetWalletPresenter';
import { ProcessWalletTransactionPresenter } from './presenters/ProcessWalletTransactionPresenter';

import {
  PAYMENT_REPOSITORY_TOKEN,
  MEMBERSHIP_FEE_REPOSITORY_TOKEN,
  MEMBER_PAYMENT_REPOSITORY_TOKEN,
  PRIZE_REPOSITORY_TOKEN,
  WALLET_REPOSITORY_TOKEN,
  TRANSACTION_REPOSITORY_TOKEN,
  LOGGER_TOKEN,
  GET_PAYMENTS_USE_CASE_TOKEN,
  CREATE_PAYMENT_USE_CASE_TOKEN,
  UPDATE_PAYMENT_STATUS_USE_CASE_TOKEN,
  GET_MEMBERSHIP_FEES_USE_CASE_TOKEN,
  UPSERT_MEMBERSHIP_FEE_USE_CASE_TOKEN,
  UPDATE_MEMBER_PAYMENT_USE_CASE_TOKEN,
  GET_PRIZES_USE_CASE_TOKEN,
  CREATE_PRIZE_USE_CASE_TOKEN,
  AWARD_PRIZE_USE_CASE_TOKEN,
  DELETE_PRIZE_USE_CASE_TOKEN,
  GET_WALLET_USE_CASE_TOKEN,
  PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
  GET_PAYMENTS_OUTPUT_PORT_TOKEN,
  CREATE_PAYMENT_OUTPUT_PORT_TOKEN,
  UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN,
  GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN,
  UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN,
  UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN,
  GET_PRIZES_OUTPUT_PORT_TOKEN,
  CREATE_PRIZE_OUTPUT_PORT_TOKEN,
  AWARD_PRIZE_OUTPUT_PORT_TOKEN,
  DELETE_PRIZE_OUTPUT_PORT_TOKEN,
  GET_WALLET_OUTPUT_PORT_TOKEN,
  PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN,
} from './PaymentsTokens';

export * from './PaymentsTokens';

export const PaymentsProviders: Provider[] = [

  // Presenters
  GetPaymentsPresenter,
  CreatePaymentPresenter,
  UpdatePaymentStatusPresenter,
  GetMembershipFeesPresenter,
  UpsertMembershipFeePresenter,
  UpdateMemberPaymentPresenter,
  GetPrizesPresenter,
  CreatePrizePresenter,
  AwardPrizePresenter,
  DeletePrizePresenter,
  GetWalletPresenter,
  ProcessWalletTransactionPresenter,

  // Output ports
  {
    provide: GET_PAYMENTS_OUTPUT_PORT_TOKEN,
    useExisting: GetPaymentsPresenter,
  },
  {
    provide: CREATE_PAYMENT_OUTPUT_PORT_TOKEN,
    useExisting: CreatePaymentPresenter,
  },
  {
    provide: UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN,
    useExisting: UpdatePaymentStatusPresenter,
  },
  {
    provide: GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN,
    useExisting: GetMembershipFeesPresenter,
  },
  {
    provide: UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN,
    useExisting: UpsertMembershipFeePresenter,
  },
  {
    provide: UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN,
    useExisting: UpdateMemberPaymentPresenter,
  },
  {
    provide: GET_PRIZES_OUTPUT_PORT_TOKEN,
    useExisting: GetPrizesPresenter,
  },
  {
    provide: CREATE_PRIZE_OUTPUT_PORT_TOKEN,
    useExisting: CreatePrizePresenter,
  },
  {
    provide: AWARD_PRIZE_OUTPUT_PORT_TOKEN,
    useExisting: AwardPrizePresenter,
  },
  {
    provide: DELETE_PRIZE_OUTPUT_PORT_TOKEN,
    useExisting: DeletePrizePresenter,
  },
  {
    provide: GET_WALLET_OUTPUT_PORT_TOKEN,
    useExisting: GetWalletPresenter,
  },
  {
    provide: PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN,
    useExisting: ProcessWalletTransactionPresenter,
  },

  // 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: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new GetPaymentsUseCase(paymentRepo, output),
    inject: [PAYMENT_REPOSITORY_TOKEN, GET_PAYMENTS_OUTPUT_PORT_TOKEN],
  },
  {
    provide: CREATE_PAYMENT_USE_CASE_TOKEN,
    useFactory: (paymentRepo: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new CreatePaymentUseCase(paymentRepo, output),
    inject: [PAYMENT_REPOSITORY_TOKEN, CREATE_PAYMENT_OUTPUT_PORT_TOKEN],
  },
  {
    provide: UPDATE_PAYMENT_STATUS_USE_CASE_TOKEN,
    useFactory: (paymentRepo: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new UpdatePaymentStatusUseCase(paymentRepo, output),
    inject: [PAYMENT_REPOSITORY_TOKEN, UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_MEMBERSHIP_FEES_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository, output: UseCaseOutputPort<unknown>) =>
      new GetMembershipFeesUseCase(membershipFeeRepo, memberPaymentRepo, output),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN, GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN],
  },
  {
    provide: UPSERT_MEMBERSHIP_FEE_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: IMembershipFeeRepository, output: UseCaseOutputPort<unknown>) => new UpsertMembershipFeeUseCase(membershipFeeRepo, output),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: UPDATE_MEMBER_PAYMENT_USE_CASE_TOKEN,
    useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository, output: UseCaseOutputPort<unknown>) =>
      new UpdateMemberPaymentUseCase(membershipFeeRepo, memberPaymentRepo, output),
    inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN, UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_PRIZES_USE_CASE_TOKEN,
    useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new GetPrizesUseCase(prizeRepo, output),
    inject: [PRIZE_REPOSITORY_TOKEN, GET_PRIZES_OUTPUT_PORT_TOKEN],
  },
  {
    provide: CREATE_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new CreatePrizeUseCase(prizeRepo, output),
    inject: [PRIZE_REPOSITORY_TOKEN, CREATE_PRIZE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: AWARD_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new AwardPrizeUseCase(prizeRepo, output),
    inject: [PRIZE_REPOSITORY_TOKEN, AWARD_PRIZE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: DELETE_PRIZE_USE_CASE_TOKEN,
    useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new DeletePrizeUseCase(prizeRepo, output),
    inject: [PRIZE_REPOSITORY_TOKEN, DELETE_PRIZE_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GET_WALLET_USE_CASE_TOKEN,
    useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository, output: UseCaseOutputPort<unknown>) =>
      new GetWalletUseCase(walletRepo, transactionRepo, output),
    inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN, GET_WALLET_OUTPUT_PORT_TOKEN],
  },
  {
    provide: PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
    useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository, output: UseCaseOutputPort<unknown>) =>
      new ProcessWalletTransactionUseCase(walletRepo, transactionRepo, output),
    inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN, PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN],
  },
];