package com.braintree.actions.order;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintree.constants.BraintreeConstants;
import com.braintree.enums.BrainTreePaymentMethod;
import com.braintree.model.BrainTreePaymentInfoModel;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.core.model.order.payment.PaymentInfoModel;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.servicelayer.session.SessionExecutionBody;
import de.hybris.platform.servicelayer.session.SessionService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeGoToSubmitForSettlementActionTest {

    private static final String CURRENT_SITE = "currentSite";

    @Mock
    private BrainTreeConfigService brainTreeConfigService;
    @Mock
    private SessionService sessionService;

    @Spy
    @InjectMocks
    private BrainTreeGoToSubmitForSettlementAction unit;

    @Mock
    private OrderProcessModel orderProcessModel;
    @Mock
    private OrderModel order;
    @Mock
    private PaymentInfoModel paymentInfoModel;
    @Mock
    private BrainTreePaymentInfoModel brainTreePaymentInfoModel;
    @Mock
    private BaseSiteModel baseSite;

    @Captor
    private ArgumentCaptor<SessionExecutionBody> sessionExecutionBodyCaptor;
    @Captor
    private ArgumentCaptor<Map<String, Object>> parametersCaptor;

    @Before
    public void setUp() {
        when(orderProcessModel.getOrder()).thenReturn(order);
        when(order.getSite()).thenReturn(baseSite);
        when(order.getPaymentInfo()).thenReturn(brainTreePaymentInfoModel);
        when(brainTreeConfigService.isSubmitForSettlement()).thenReturn(true);
    }

    @Test
    public void shouldExecuteActionWhenApplePayPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.APPLEPAYCARD.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        Map<String, Object> parameters = parametersCaptor.getValue();
        assertTrue(parameters.containsKey(CURRENT_SITE));
        assertEquals(baseSite, parameters.get(CURRENT_SITE));
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenGooglePayPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.ANDROIDPAYCARD.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenSrcPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.VISACHECKOUTCARD.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenCreditCardPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.CREDITCARD.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenVenmoPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.VENMOACCOUNT.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenPayPalPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.PAYPALACCOUNT.getCode());
        when(brainTreePaymentInfoModel.getPayPalIntent()).thenReturn(BraintreeConstants.PayPalIntent.PAYPAL_INTENT_SALE);

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenLPMPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.LOCALPAYMENT.getCode());
        when(brainTreePaymentInfoModel.getPayPalIntent()).thenReturn(BraintreeConstants.PayPalIntent.PAYPAL_INTENT_SALE);

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenUSBankAccountPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.USBANKACCOUNT.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenDifferentPaymentProvider() throws Exception {
        //given
        when(brainTreePaymentInfoModel.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.AMEXEXPRESSCHECKOUTCARD.getCode());

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.NOK, result);
    }

    @Test
    public void shouldExecuteActionWhenPaymentInfoNotInstanceOfBrainTreePaymentInfoModel() throws Exception {
        //given
        when(order.getPaymentInfo()).thenReturn(paymentInfoModel);

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldExecuteActionWhenPaymentInfoIsNull() throws Exception {
        //given
        when(order.getPaymentInfo()).thenReturn(null);

        //when
        unit.executeAction(orderProcessModel);

        //then
        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());
        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = (AbstractSimpleDecisionAction.Transition) sessionExecutionBody.execute();
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

}