/**
 * Application Use Case: UpdatePaymentStatusUseCase
 *
 * Updates the status of a payment.
 */

import type { IPaymentRepository } from '../../domain/repositories/IPaymentRepository';
import type { Payment } from '../../domain/entities/Payment';
import { PaymentStatus } from '../../domain/entities/Payment';
import type { UseCase } from '@core/shared/application/UseCase';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';

export type UpdatePaymentStatusErrorCode = 'PAYMENT_NOT_FOUND';

export interface UpdatePaymentStatusInput {
  paymentId: string;
  status: PaymentStatus;
}

export interface UpdatePaymentStatusResult {
  payment: Payment;
}

export class UpdatePaymentStatusUseCase
  implements UseCase<UpdatePaymentStatusInput, void, UpdatePaymentStatusErrorCode>
{
  constructor(
    private readonly paymentRepository: IPaymentRepository,
    private readonly output: UseCaseOutputPort<UpdatePaymentStatusResult>,
  ) {}

  async execute(input: UpdatePaymentStatusInput): Promise<Result<void, ApplicationErrorCode<UpdatePaymentStatusErrorCode>>> {
    const { paymentId, status } = input;

    const existingPayment = await this.paymentRepository.findById(paymentId);
    if (!existingPayment) {
      return Result.err({ code: 'PAYMENT_NOT_FOUND' as const });
    }

    const updatedPayment = {
      ...existingPayment,
      status,
      completedAt: status === PaymentStatus.COMPLETED ? new Date() : existingPayment.completedAt,
    };

    const savedPayment = await this.paymentRepository.update(updatedPayment as Payment);

    this.output.present({ payment: savedPayment });

    return Result.ok(undefined);
  }
}