using Grand.Business.Core.Commands.Checkout.Orders;
using Grand.Business.Core.Interfaces.Checkout.Orders;
using Grand.Business.Core.Interfaces.Checkout.Payments;
using Grand.Business.Core.Queries.Checkout.Orders;
using Grand.Domain.Orders;
using Grand.Domain.Payments;
using Grand.SharedKernel;
using MediatR;

namespace Grand.Business.Checkout.Commands.Handlers.Orders;

public class MarkAsPaidCommandHandler : IRequestHandler<MarkAsPaidCommand, bool>
{
    private readonly IMediator _mediator;
    private readonly IOrderService _orderService;
    private readonly IPaymentTransactionService _paymentTransactionService;

    public MarkAsPaidCommandHandler(
        IMediator mediator,
        IOrderService orderService,
        IPaymentTransactionService paymentTransactionService)
    {
        _mediator = mediator;
        _orderService = orderService;
        _paymentTransactionService = paymentTransactionService;
    }

    public async Task<bool> Handle(MarkAsPaidCommand request, CancellationToken cancellationToken)
    {
        var paymentTransaction = request.PaymentTransaction;
        if (paymentTransaction == null)
            throw new ArgumentNullException(nameof(request.PaymentTransaction));

        var canMarkOrderAsPaid =
            await _mediator.Send(new CanMarkPaymentTransactionAsPaidQuery { PaymentTransaction = paymentTransaction },
                cancellationToken);
        if (!canMarkOrderAsPaid)
            throw new GrandException("You can't mark this Payment Transaction as paid");

        paymentTransaction.TransactionStatus = TransactionStatus.Paid;
        paymentTransaction.PaidAmount = paymentTransaction.TransactionAmount;

        await _paymentTransactionService.UpdatePaymentTransaction(paymentTransaction);
        var order = await _orderService.GetOrderByGuid(paymentTransaction.OrderGuid);
        if (order == null)
            throw new ArgumentNullException(nameof(order));

        order.PaidAmount = paymentTransaction.PaidAmount;
        order.PaymentStatusId = PaymentStatus.Paid;
        order.PaidDateUtc = DateTime.UtcNow;
        await _orderService.UpdateOrder(order);

        //add a note
        await _orderService.InsertOrderNote(new OrderNote {
            Note = "Order has been marked as paid",
            DisplayToCustomer = false,
            OrderId = order.Id
        });

        await _mediator.Send(new CheckOrderStatusCommand { Order = order }, cancellationToken);
        if (order.PaymentStatusId == PaymentStatus.Paid)
            await _mediator.Send(new ProcessOrderPaidCommand { Order = order }, cancellationToken);
        return true;
    }
}