import type { DataSource } from 'typeorm';

import type { MemberPayment } from '@core/payments/domain/entities/MemberPayment';
import type { MembershipFee } from '@core/payments/domain/entities/MembershipFee';
import type { MembershipFeeRepository, MemberPaymentRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';

import { PaymentsMemberPaymentOrmEntity } from '../entities/PaymentsMemberPaymentOrmEntity';
import { PaymentsMembershipFeeOrmEntity } from '../entities/PaymentsMembershipFeeOrmEntity';
import { PaymentsMemberPaymentOrmMapper } from '../mappers/PaymentsMemberPaymentOrmMapper';
import { PaymentsMembershipFeeOrmMapper } from '../mappers/PaymentsMembershipFeeOrmMapper';

export class TypeOrmMembershipFeeRepository implements MembershipFeeRepository {
  constructor(
    private readonly dataSource: DataSource,
    private readonly mapper: PaymentsMembershipFeeOrmMapper,
  ) {}

  async findById(id: string): Promise<MembershipFee | null> {
    const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
    const entity = await repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByLeagueId(leagueId: string): Promise<MembershipFee | null> {
    const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
    const entity = await repo.findOne({ where: { leagueId } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async create(fee: MembershipFee): Promise<MembershipFee> {
    const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
    await repo.save(this.mapper.toOrmEntity(fee));
    return fee;
  }

  async update(fee: MembershipFee): Promise<MembershipFee> {
    const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
    await repo.save(this.mapper.toOrmEntity(fee));
    return fee;
  }
}

export class TypeOrmMemberPaymentRepository implements MemberPaymentRepository {
  constructor(
    private readonly dataSource: DataSource,
    private readonly mapper: PaymentsMemberPaymentOrmMapper,
  ) {}

  async findById(id: string): Promise<MemberPayment | null> {
    const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
    const entity = await repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByFeeIdAndDriverId(feeId: string, driverId: string): Promise<MemberPayment | null> {
    const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
    const entity = await repo.findOne({ where: { feeId, driverId } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByLeagueIdAndDriverId(
    leagueId: string,
    driverId: string,
    membershipFeeRepo: MembershipFeeRepository,
  ): Promise<MemberPayment[]> {
    const fee = await membershipFeeRepo.findByLeagueId(leagueId);
    if (!fee) {
      return [];
    }

    const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
    const entities = await repo.find({ where: { feeId: fee.id, driverId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async create(payment: MemberPayment): Promise<MemberPayment> {
    const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
    await repo.save(this.mapper.toOrmEntity(payment));
    return payment;
  }

  async update(payment: MemberPayment): Promise<MemberPayment> {
    const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
    await repo.save(this.mapper.toOrmEntity(payment));
    return payment;
  }
}
