package com.braintree.customersupportbackoffice.widgets;

import com.braintree.customersupportbackoffice.data.BrainTreeTransactionInfo;
import com.braintree.customersupportbackoffice.facade.BrainTreeCustomerSupportFacade;
import com.braintree.customfield.service.BraintreeCustomFieldsService;
import com.braintree.hybris.data.BrainTreeResponseResultData;
import com.hybris.backoffice.widgets.notificationarea.NotificationService;
import com.hybris.backoffice.widgets.notificationarea.event.NotificationEvent;
import com.hybris.backoffice.widgets.notificationarea.event.NotificationEventTypes;
import com.hybris.cockpitng.config.jaxb.wizard.CustomType;
import com.hybris.cockpitng.core.impl.NotificationStack;
import com.hybris.cockpitng.core.model.WidgetModel;
import com.hybris.cockpitng.engine.WidgetInstanceManager;
import com.hybris.cockpitng.widgets.configurableflow.FlowActionHandlerAdapter;
import de.hybris.bootstrap.annotations.UnitTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.math.BigDecimal;
import java.util.Map;

import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeNewTransactionByVaultHandlerTest {
    private static Map<String, String> testParameters;
    private static CustomType testCustomType;
    private static final BigDecimal TEST_AMOUNT = BigDecimal.valueOf(5);
    private static final BigDecimal TEST_TAX_AMOUNT = BigDecimal.valueOf(10);
    private static final String TEST_PAYMENT_TOKEN = "TEST_TOKEN";
    private static final String TEST_TRANSACTION_ID = "TEST_TRANSACTION_ID";
    private static final String TEST_ERROR_MSG = "TEST_ERROR_MSG";
    private static final String TRANSACTION_SUCCESSFULLY_CREATED_MSG = "Transaction successfully created";
    private static final String TRANSACTION_FAILURE_CREATED_MSG = "Error occurs";
    private static final String FORM_SUCCESSFULLY_STATUS = "Transaction was successfully created with id: ";
    private static final String TRANSACTION_FAILURE_STATUS = TRANSACTION_FAILURE_CREATED_MSG + ": ";
    private static final String TEST_KEY = "TEST_KEY";
    private static final String TEST_KEY_2 = "TEST_KEY_2";
    private static final String TEST_VALUE = "TEST_VALUE";
    private static final String TEST_VALUE_2 = "TEST_VALUE_2";
    private static final String TEST_CUSTOM_PARAM = TEST_KEY_2 + ":" + TEST_VALUE_2;
    private static final String FORM = "newTransactionByVaultForm";
    @Mock
    private BraintreeCustomFieldsService customFieldsService;
    @Mock
    private BrainTreeCustomerSupportFacade brainTreeCustomerSupportFacade;
    @Mock
    private NotificationStack notificationStack;
    @Mock
    private NotificationService notificationService;
    @Mock
    private FlowActionHandlerAdapter flowActionHandlerAdapter;
    @Mock
    private WidgetInstanceManager widgetInstanceManager;
    @Mock
    private BrainTreeResponseResultData brainTreeResponseResultData;
    @Mock
    private WidgetModel widgetModel;
    @InjectMocks
    private BrainTreeNewTransactionByVaultHandler brainTreeNewTransactionByVaultHandler;

    @Test
    public void shouldPerformWhenFormEqualsNull() {
        when(flowActionHandlerAdapter.getWidgetInstanceManager()).thenReturn(widgetInstanceManager);
        when(widgetInstanceManager.getModel()).thenReturn(widgetModel);
        brainTreeNewTransactionByVaultHandler.perform(testCustomType, flowActionHandlerAdapter, testParameters);
        verify(flowActionHandlerAdapter).next();
    }

    @Test
    public void shouldPerformWhenFormNotNullAndCustomFieldsIsNotBlankAndTransactionIsSuccess() {
        final BrainTreeNewTransactionByVaultForm brainTreeNewTransactionByVaultForm = new BrainTreeNewTransactionByVaultForm();
        brainTreeNewTransactionByVaultForm.setAmount(TEST_AMOUNT);
        brainTreeNewTransactionByVaultForm.setTaxAmount(TEST_TAX_AMOUNT);
        brainTreeNewTransactionByVaultForm.setPaymentMethodToken(TEST_PAYMENT_TOKEN);
        brainTreeNewTransactionByVaultForm.setCustomFields(TEST_CUSTOM_PARAM);
        when(customFieldsService.getDefaultCustomFieldsMap()).thenReturn(Map.of(TEST_KEY, TEST_VALUE));
        when(flowActionHandlerAdapter.getWidgetInstanceManager()).thenReturn(widgetInstanceManager);
        when(widgetInstanceManager.getModel()).thenReturn(widgetModel);
        when(widgetModel.getValue(FORM, BrainTreeNewTransactionByVaultForm.class)).thenReturn(brainTreeNewTransactionByVaultForm);
        when(brainTreeCustomerSupportFacade.createTransaction(argThat(getBrainTreeTransactionInfoMatcherWithCustomFieldsMap()))).thenReturn(brainTreeResponseResultData);
        when(brainTreeResponseResultData.isSuccess()).thenReturn(true);
        when(brainTreeResponseResultData.getTransactionId()).thenReturn(TEST_TRANSACTION_ID);
        brainTreeNewTransactionByVaultHandler.perform(testCustomType, flowActionHandlerAdapter, testParameters);
        verify(brainTreeCustomerSupportFacade).createTransaction(argThat(getBrainTreeTransactionInfoMatcher()));
        verify(notificationService).notifyUser(TRANSACTION_SUCCESSFULLY_CREATED_MSG, NotificationEventTypes.EVENT_TYPE_OBJECT_CREATION, NotificationEvent.Level.SUCCESS);
        Assert.assertEquals(brainTreeNewTransactionByVaultForm.getStatus(), FORM_SUCCESSFULLY_STATUS + TEST_TRANSACTION_ID);
        verify(flowActionHandlerAdapter).next();
    }

    @Test
    public void shouldPerformWhenFormNotNullAndCustomFieldsIsBlankAndTransactionIsNotSuccess() {
        final BrainTreeNewTransactionByVaultForm brainTreeNewTransactionByVaultForm = new BrainTreeNewTransactionByVaultForm();
        brainTreeNewTransactionByVaultForm.setAmount(TEST_AMOUNT);
        brainTreeNewTransactionByVaultForm.setTaxAmount(TEST_TAX_AMOUNT);
        brainTreeNewTransactionByVaultForm.setPaymentMethodToken(TEST_PAYMENT_TOKEN);
        when(flowActionHandlerAdapter.getWidgetInstanceManager()).thenReturn(widgetInstanceManager);
        when(widgetInstanceManager.getModel()).thenReturn(widgetModel);
        when(widgetModel.getValue(FORM, BrainTreeNewTransactionByVaultForm.class)).thenReturn(brainTreeNewTransactionByVaultForm);
        when(brainTreeCustomerSupportFacade.createTransaction(argThat(getBrainTreeTransactionInfoMatcher()))).thenReturn(brainTreeResponseResultData);
        when(brainTreeResponseResultData.isSuccess()).thenReturn(false);
        when(brainTreeResponseResultData.getErrorMessage()).thenReturn(TEST_ERROR_MSG);
        brainTreeNewTransactionByVaultHandler.perform(testCustomType, flowActionHandlerAdapter, testParameters);
        verify(brainTreeCustomerSupportFacade).createTransaction(argThat(getBrainTreeTransactionInfoMatcher()));
        verify(notificationService).notifyUser(TRANSACTION_FAILURE_CREATED_MSG, NotificationEventTypes.EVENT_TYPE_OBJECT_CREATION, NotificationEvent.Level.FAILURE);
        Assert.assertEquals(brainTreeNewTransactionByVaultForm.getStatus(), TRANSACTION_FAILURE_STATUS + TEST_ERROR_MSG);
        verify(flowActionHandlerAdapter).next();
    }

    private ArgumentMatcher<BrainTreeTransactionInfo> getBrainTreeTransactionInfoMatcher() {
        return paymentInfo -> TEST_PAYMENT_TOKEN.equals(paymentInfo.getPaymentMethodToken())
                && paymentInfo.getAmount().compareTo(TEST_AMOUNT) == 0 && paymentInfo.getTax().compareTo(TEST_TAX_AMOUNT) == 0;
    }

    private ArgumentMatcher<BrainTreeTransactionInfo> getBrainTreeTransactionInfoMatcherWithCustomFieldsMap() {
        return paymentInfo -> TEST_PAYMENT_TOKEN.equals(paymentInfo.getPaymentMethodToken())
                && paymentInfo.getAmount().compareTo(TEST_AMOUNT) == 0 && paymentInfo.getTax().compareTo(TEST_TAX_AMOUNT) == 0
                && TEST_VALUE.equals(paymentInfo.getCustom().get(TEST_KEY))
                && TEST_VALUE_2.equals(paymentInfo.getCustom().get(TEST_KEY_2));
    }

}
