package com.braintree.customersupportbackoffice.actions.order.adjustauthorization;

import com.braintree.facade.backoffice.BraintreeBackofficeAdjustAuthorizationFacade;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.hybris.cockpitng.actions.ActionContext;
import com.hybris.cockpitng.actions.ActionResult;
import com.hybris.cockpitng.engine.impl.ComponentWidgetAdapter;
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.CreditCardPaymentInfoModel;
import de.hybris.platform.servicelayer.session.SessionExecutionBody;
import de.hybris.platform.servicelayer.session.SessionService;
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.runners.MockitoJUnitRunner;

import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeAdjustAuthorizationActionTest {
    private static final String CURRENT_SITE = "currentSite";

    @Mock
    private BraintreeBackofficeAdjustAuthorizationFacade braintreeBackofficeAdjustAuthorizationFacade;
    @Mock
    private SessionService sessionService;
    @Mock
    private ComponentWidgetAdapter componentWidgetAdapter;

    @InjectMocks
    private BrainTreeAdjustAuthorizationAction unit;

    @Mock
    private ActionContext<OrderModel> actionContext;
    @Mock
    private OrderModel order;
    @Mock
    private BrainTreePaymentInfoModel braintreePaymentInfo;
    @Mock
    private CreditCardPaymentInfoModel creditCardPaymentInfo;
    @Mock
    private BaseSiteModel baseSite;

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

    @Test
    public void shouldReturnTrueIfAdjustedAuthorizationPossible() {
        when(actionContext.getData()).thenReturn(order);
        when(order.getPaymentInfo()).thenReturn(braintreePaymentInfo);
        when(order.getSite()).thenReturn(baseSite);
        when(braintreeBackofficeAdjustAuthorizationFacade.isAdjustAuthorizationPossible(order)).thenReturn(true);
        when(sessionService.executeInLocalViewWithParams(any(), any())).thenReturn(true);

        unit.canPerform(actionContext);

        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();
        boolean result = (Boolean) sessionExecutionBody.execute();
        assertTrue(result);
    }

    @Test
    public void shouldSetHiddenViewModeForNonBraintreePaymentInfo() {
        when(actionContext.getData()).thenReturn(order);
        when(order.getPaymentInfo()).thenReturn(creditCardPaymentInfo);
        when(order.getSite()).thenReturn(baseSite);
        when(braintreeBackofficeAdjustAuthorizationFacade.isAdjustAuthorizationPossible(order)).thenReturn(true);
        when(sessionService.executeInLocalViewWithParams(any(), any())).thenReturn(true);

        unit.canPerform(actionContext);

        verify(sessionService).executeInLocalViewWithParams(parametersCaptor.capture(), sessionExecutionBodyCaptor.capture());

        SessionExecutionBody sessionExecutionBody = sessionExecutionBodyCaptor.getValue();
        sessionExecutionBody.execute();
        verify(actionContext).setParameter(ActionContext.VIEW_MODE_PARAM, ActionContext.VIEWMODE_HIDDEN);
    }

    @Test
    public void shouldReturnFalseIfActionContextDoesNotHaveOrder() {
        boolean result = unit.canPerform(actionContext);

        assertFalse(result);
        verify(sessionService, never()).executeInLocalViewWithParams(any(), any());
    }

    @Test
    public void shouldSuccessfullyPerform() {
        ActionResult<OrderModel> result = unit.perform(actionContext);

        assertEquals(ActionResult.SUCCESS, result.getResultCode());
    }

}