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

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

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 { 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): WalletRepository =>
        new TypeOrmWalletRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsWalletOrmMapper],
    },
    {
      provide: PAYMENTS_TRANSACTION_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsWalletOrmMapper): TransactionRepository =>
        new TypeOrmTransactionRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsWalletOrmMapper],
    },
    {
      provide: PAYMENTS_PAYMENT_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsPaymentOrmMapper): PaymentRepository =>
        new TypeOrmPaymentRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsPaymentOrmMapper],
    },
    {
      provide: PAYMENTS_PRIZE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsPrizeOrmMapper): PrizeRepository =>
        new TypeOrmPrizeRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsPrizeOrmMapper],
    },
    {
      provide: PAYMENTS_MEMBERSHIP_FEE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsMembershipFeeOrmMapper): MembershipFeeRepository =>
        new TypeOrmMembershipFeeRepository(dataSource, mapper),
      inject: [getDataSourceToken(), PaymentsMembershipFeeOrmMapper],
    },
    {
      provide: PAYMENTS_MEMBER_PAYMENT_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: PaymentsMemberPaymentOrmMapper): MemberPaymentRepository =>
        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 {}
