package com.braintree.facade.backoffice.impl;

import com.braintree.exceptions.BraintreeErrorException;
import com.braintree.facade.backoffice.BraintreeBackofficePartialRefundFacade;
import com.braintree.order.refund.partial.services.BraintreePartialRefundService;
import com.braintree.order.service.BraintreeOrderBackofficeUtilService;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.ordermanagementfacades.payment.data.PaymentTransactionEntryData;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.payment.dto.TransactionStatusDetails;
import de.hybris.platform.payment.enums.PaymentTransactionType;
import de.hybris.platform.payment.model.PaymentTransactionEntryModel;
import de.hybris.platform.payment.model.PaymentTransactionModel;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import de.hybris.platform.servicelayer.model.ModelService;
import org.apache.log4j.Logger;

import java.math.BigDecimal;

public class DefaultBraintreeBackofficePartialRefundFacade implements BraintreeBackofficePartialRefundFacade {

    private static final Logger LOG = Logger.getLogger(DefaultBraintreeBackofficePartialRefundFacade.class);

    private BraintreePartialRefundService braintreePartialRefundService;
    private BraintreeOrderBackofficeUtilService braintreeOrderBackofficeUtilService;
    private Converter<PaymentTransactionEntryModel, PaymentTransactionEntryData> ordermanagementPaymentTransactionEntryConverter;
    private ModelService modelService;

    @Override
    public boolean isPartialRefundPossible(final OrderModel order) {
        if (order == null) {
            return false;
        }
        LOG.info("isPartialRefundPossible, order.getTotalPrice: " + order.getTotalPrice());

        modelService.refresh(order);
        if (braintreeOrderBackofficeUtilService.isOrderVoided(order)) {
            return false;
        }

        BigDecimal capturedAmount = BigDecimal.ZERO;
        for (final PaymentTransactionModel paymentTransaction : order.getPaymentTransactions()) {
            for (final PaymentTransactionEntryModel transactionEntry : paymentTransaction.getEntries()) {
                if (TransactionStatusDetails.SUCCESFULL.name().equals(transactionEntry.getTransactionStatusDetails()) &&
                        TransactionStatus.ACCEPTED.name().equals(transactionEntry.getTransactionStatus())) {
                    capturedAmount = checkTransactionTypeAndAddCapturedAmount(transactionEntry, capturedAmount);
                }
            }
        }
        return capturedAmount.compareTo(BigDecimal.ZERO) > 0;
    }

    private BigDecimal checkTransactionTypeAndAddCapturedAmount(PaymentTransactionEntryModel transactionEntry,
                                                                BigDecimal capturedAmount) {
        final PaymentTransactionType transactionType = transactionEntry.getType();
        if (PaymentTransactionType.CAPTURE.equals(transactionType) || PaymentTransactionType.PARTIAL_CAPTURE
                .equals(transactionType)) {
            capturedAmount = capturedAmount.add(transactionEntry.getAmount());
        } else if (PaymentTransactionType.REFUND_PARTIAL.equals(transactionType)) {
            capturedAmount = capturedAmount.subtract(transactionEntry.getAmount());
        }
        return capturedAmount;
    }

    @Override
    public PaymentTransactionEntryData partialRefundTransaction(final OrderModel order,
                                                                final PaymentTransactionEntryModel paymentTransactionEntry, final BigDecimal amount)
            throws BraintreeErrorException {
        final PaymentTransactionEntryModel response = braintreePartialRefundService.partialRefundTransaction(order,
                paymentTransactionEntry, amount);
        return ordermanagementPaymentTransactionEntryConverter.convert(response);
    }

    public void setBraintreePartialRefundService(BraintreePartialRefundService braintreePartialRefundService) {
        this.braintreePartialRefundService = braintreePartialRefundService;
    }

    public void setBraintreeOrderBackofficeUtilService(BraintreeOrderBackofficeUtilService braintreeOrderBackofficeUtilService) {
        this.braintreeOrderBackofficeUtilService = braintreeOrderBackofficeUtilService;
    }

    public void setOrdermanagementPaymentTransactionEntryConverter(Converter<PaymentTransactionEntryModel, PaymentTransactionEntryData> ordermanagementPaymentTransactionEntryConverter) {
        this.ordermanagementPaymentTransactionEntryConverter = ordermanagementPaymentTransactionEntryConverter;
    }

    public void setModelService(ModelService modelService) {
        this.modelService = modelService;
    }
}
