package com.braintree.actions.replenishment;

import com.braintree.customfield.service.BraintreeCustomFieldsService;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.braintree.transaction.service.BrainTreeTransactionService;
import de.hybris.platform.b2bacceleratoraddon.actions.replenishment.AuthorizePaymentAction;
import de.hybris.platform.b2bacceleratorservices.model.process.ReplenishmentProcessModel;
import de.hybris.platform.commerceservices.impersonation.ImpersonationContext;
import de.hybris.platform.commerceservices.impersonation.ImpersonationService;
import de.hybris.platform.commerceservices.service.data.CommerceOrderParameter;
import de.hybris.platform.commerceservices.util.GuidKeyGenerator;
import de.hybris.platform.core.enums.OrderStatus;
import de.hybris.platform.core.model.order.CartModel;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.payment.model.PaymentTransactionEntryModel;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.processengine.model.BusinessProcessParameterModel;

import static com.braintree.hybris.data.BraintreePaymentInitiator.RECURRING;


public class BrainTreeAuthorizePaymentAction extends AuthorizePaymentAction {

    private BrainTreeTransactionService brainTreeTransactionService;
    private BraintreeCustomFieldsService customFieldsService;
    private GuidKeyGenerator guidKeyGenerator;

    @Override
    public de.hybris.platform.processengine.action.AbstractSimpleDecisionAction.Transition executeAction(
        final ReplenishmentProcessModel process) throws Exception {
        final BusinessProcessParameterModel clonedCartParameter = processParameterHelper
            .getProcessParameterByName(process, "cart");
        final CartModel clonedCart = (CartModel) clonedCartParameter.getValue();
        getModelService().refresh(clonedCart);

        final ImpersonationContext context = new ImpersonationContext();
        context.setOrder(clonedCart);
        return getImpersonationService().executeInContext(context,
            new ImpersonationService.Executor<AbstractSimpleDecisionAction.Transition, ImpersonationService.Nothing>() {
                @Override
                public AbstractSimpleDecisionAction.Transition execute() {
                    if (clonedCart.getPaymentInfo() instanceof BrainTreePaymentInfoModel) {
                        final BrainTreePaymentInfoModel paymentInfo = (BrainTreePaymentInfoModel) clonedCart
                            .getPaymentInfo();
                        // disable 3ds for replenishment order
                        modelService.refresh(clonedCart);

                        clonedCart.setBrainTreeOrderId(guidKeyGenerator.generate().toString());
                        modelService.save(clonedCart);

                        final CommerceOrderParameter parameter = new CommerceOrderParameter();
                        parameter.setOrder(clonedCart);
                        parameter.setCustomFields(customFieldsService.getDefaultCustomFieldsMap());
                        parameter.setPaymentInitiator(RECURRING);

                        final PaymentTransactionEntryModel paymentTransactionEntryModel = brainTreeTransactionService.createAuthorizationTransaction(parameter);

                        if (paymentTransactionEntryModel == null || !TransactionStatus.ACCEPTED.name().equals(paymentTransactionEntryModel.getTransactionStatus())) {
                            clonedCart.setStatus(OrderStatus.B2B_PROCESSING_ERROR);
                            modelService.save(clonedCart);
                            return AbstractSimpleDecisionAction.Transition.NOK;
                        }
                    }
                    return AbstractSimpleDecisionAction.Transition.OK;
                }
            });
    }

    /**
     * @return the brainTreeTransactionService
     */
    public BrainTreeTransactionService getBrainTreeTransactionService() {
        return brainTreeTransactionService;
    }

    public void setBrainTreeTransactionService(final BrainTreeTransactionService brainTreeTransactionService) {
        this.brainTreeTransactionService = brainTreeTransactionService;
    }

    public BraintreeCustomFieldsService getCustomFieldsService() {
        return customFieldsService;
    }

    public void setCustomFieldsService(BraintreeCustomFieldsService customFieldsService) {
        this.customFieldsService = customFieldsService;
    }

    public void setGuidKeyGenerator(GuidKeyGenerator guidKeyGenerator) {
        this.guidKeyGenerator = guidKeyGenerator;
    }

}
