import { Module } from '@nestjs/common';
import { TypeOrmModule, getDataSourceToken } from '@nestjs/typeorm';
import type { DataSource } from 'typeorm';

import { LoggingModule } from '../../domain/logging/LoggingModule';

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

import { PaymentsMemberPaymentOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsMemberPaymentOrmEntity';
import { PaymentsMembershipFeeOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsMembershipFeeOrmEntity';
import { PaymentsPaymentOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsPaymentOrmEntity';
import { PaymentsPrizeOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsPrizeOrmEntity';
import { PaymentsTransactionOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsTransactionOrmEntity';
import { PaymentsWalletOrmEntity } from '@adapters/payments/persistence/typeorm/entities/PaymentsWalletOrmEntity';

import { PaymentsMemberPaymentOrmMapper } from '@adapters/payments/persistence/typeorm/mappers/PaymentsMemberPaymentOrmMapper';
import { PaymentsMembershipFeeOrmMapper } from '@adapters/payments/persistence/typeorm/mappers/PaymentsMembershipFeeOrmMapper';
import { PaymentsPaymentOrmMapper } from '@adapters/payments/persistence/typeorm/mappers/PaymentsPaymentOrmMapper';
import { PaymentsPrizeOrmMapper } from '@adapters/payments/persistence/typeorm/mappers/PaymentsPrizeOrmMapper';
import { PaymentsWalletOrmMapper } from '@adapters/payments/persistence/typeorm/mappers/PaymentsWalletOrmMapper';

import { TypeOrmMemberPaymentRepository, TypeOrmMembershipFeeRepository } from '@adapters/payments/persistence/typeorm/repositories/TypeOrmMembershipFeeRepository';
import { TypeOrmPaymentRepository } from '@adapters/payments/persistence/typeorm/repositories/TypeOrmPaymentRepository';
import { TypeOrmPrizeRepository } from '@adapters/payments/persistence/typeorm/repositories/TypeOrmPrizeRepository';
import { TypeOrmTransactionRepository, TypeOrmWalletRepository } from '@adapters/payments/persistence/typeorm/repositories/TypeOrmWalletRepository';

import {
  PAYMENTS_MEMBER_PAYMENT_REPOSITORY_TOKEN,
  PAYMENTS_MEMBERSHIP_FEE_REPOSITORY_TOKEN,
  PAYMENTS_PAYMENT_REPOSITORY_TOKEN,
  PAYMENTS_PRIZE_REPOSITORY_TOKEN,
  PAYMENTS_TRANSACTION_REPOSITORY_TOKEN,
  PAYMENTS_WALLET_REPOSITORY_TOKEN,
} from '../payments/PaymentsPersistenceTokens';

const typeOrmFeatureImports = [
  TypeOrmModule.forFeature([
    PaymentsWalletOrmEntity,
    PaymentsTransactionOrmEntity,
    PaymentsPaymentOrmEntity,
    PaymentsPrizeOrmEntity,
    PaymentsMembershipFeeOrmEntity,
    PaymentsMemberPaymentOrmEntity,
  ]),
];

@Module({
  imports: [LoggingModule, ...typeOrmFeatureImports],
  providers: [
    { provide: PaymentsWalletOrmMapper, useFactory: () => new PaymentsWalletOrmMapper() },
    { provide: PaymentsPaymentOrmMapper, useFactory: () => new PaymentsPaymentOrmMapper() },
    { provide: PaymentsPrizeOrmMapper, useFactory: () => new PaymentsPrizeOrmMapper() },
    { provide: PaymentsMembershipFeeOrmMapper, useFactory: () => new PaymentsMembershipFeeOrmMapper() },
    { provide: PaymentsMemberPaymentOrmMapper, useFactory: () => new PaymentsMemberPaymentOrmMapper() },

    {
      provide: PAYMENTS_WALLET_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsWalletOrmMapper): IWalletRepository =>
        new TypeOrmWalletRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsWalletOrmMapper],
    },
    {
      provide: PAYMENTS_TRANSACTION_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsWalletOrmMapper): ITransactionRepository =>
        new TypeOrmTransactionRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsWalletOrmMapper],
    },
    {
      provide: PAYMENTS_PAYMENT_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsPaymentOrmMapper): IPaymentRepository =>
        new TypeOrmPaymentRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsPaymentOrmMapper],
    },
    {
      provide: PAYMENTS_PRIZE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsPrizeOrmMapper): IPrizeRepository =>
        new TypeOrmPrizeRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsPrizeOrmMapper],
    },
    {
      provide: PAYMENTS_MEMBERSHIP_FEE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsMembershipFeeOrmMapper): IMembershipFeeRepository =>
        new TypeOrmMembershipFeeRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsMembershipFeeOrmMapper],
    },
    {
      provide: PAYMENTS_MEMBER_PAYMENT_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsMemberPaymentOrmMapper): IMemberPaymentRepository =>
        new TypeOrmMemberPaymentRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsMemberPaymentOrmMapper],
    },
  ],
  exports: [
    PAYMENTS_WALLET_REPOSITORY_TOKEN,
    PAYMENTS_TRANSACTION_REPOSITORY_TOKEN,
    PAYMENTS_PAYMENT_REPOSITORY_TOKEN,
    PAYMENTS_PRIZE_REPOSITORY_TOKEN,
    PAYMENTS_MEMBERSHIP_FEE_REPOSITORY_TOKEN,
    PAYMENTS_MEMBER_PAYMENT_REPOSITORY_TOKEN,
  ],
})
export class PostgresPaymentsPersistenceModule {}
