/**
 * Application Use Case: UpdateMemberPaymentUseCase
 *
 * Updates a member payment record.
 */

import type { IMembershipFeeRepository, IMemberPaymentRepository } from '../../domain/repositories/IMembershipFeeRepository';
import type { MemberPaymentStatus, MemberPayment } from '../../domain/entities/MemberPayment';
import type {
  IUpdateMemberPaymentPresenter,
  UpdateMemberPaymentResultDTO,
  UpdateMemberPaymentViewModel,
} from '../presenters/IUpdateMemberPaymentPresenter';
import type { UseCase } from '@core/shared/application/UseCase';

const PLATFORM_FEE_RATE = 0.10;

export interface UpdateMemberPaymentInput {
  feeId: string;
  driverId: string;
  status?: MemberPaymentStatus;
  paidAt?: Date | string;
}

export class UpdateMemberPaymentUseCase
  implements UseCase<UpdateMemberPaymentInput, UpdateMemberPaymentResultDTO, UpdateMemberPaymentViewModel, IUpdateMemberPaymentPresenter>
{
  constructor(
    private readonly membershipFeeRepository: IMembershipFeeRepository,
    private readonly memberPaymentRepository: IMemberPaymentRepository,
  ) {}

  async execute(
    input: UpdateMemberPaymentInput,
    presenter: IUpdateMemberPaymentPresenter,
  ): Promise<void> {
    presenter.reset();

    const { feeId, driverId, status, paidAt } = input;

    const fee = await this.membershipFeeRepository.findById(feeId);
    if (!fee) {
      throw new Error('Membership fee configuration not found');
    }

    let payment = await this.memberPaymentRepository.findByFeeIdAndDriverId(feeId, driverId);

    if (!payment) {
      const platformFee = fee.amount * PLATFORM_FEE_RATE;
      const netAmount = fee.amount - platformFee;

      const paymentId = `mp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      const newPayment: MemberPayment = {
        id: paymentId,
        feeId,
        driverId,
        amount: fee.amount,
        platformFee,
        netAmount,
        status: 'pending' as MemberPaymentStatus,
        dueDate: new Date(),
      };
      payment = await this.memberPaymentRepository.create(newPayment);
    }

    if (status) {
      payment.status = status;
    }
    if (paidAt || status === ('paid' as MemberPaymentStatus)) {
      payment.paidAt = paidAt ? new Date(paidAt as string) : new Date();
    }

    const updatedPayment = await this.memberPaymentRepository.update(payment);

    const dto: UpdateMemberPaymentResultDTO = {
      payment: {
        id: updatedPayment.id,
        feeId: updatedPayment.feeId,
        driverId: updatedPayment.driverId,
        amount: updatedPayment.amount,
        platformFee: updatedPayment.platformFee,
        netAmount: updatedPayment.netAmount,
        status: updatedPayment.status,
        dueDate: updatedPayment.dueDate,
        paidAt: updatedPayment.paidAt,
      },
    };

    presenter.present(dto);
  }
}