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.bootstrap.annotations.UnitTest;
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.helpers.ProcessParameterHelper;
import de.hybris.platform.processengine.model.BusinessProcessParameterModel;
import de.hybris.platform.servicelayer.model.ModelService;
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 static com.braintree.hybris.data.BraintreePaymentInitiator.RECURRING;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeAuthorizePaymentActionTest {
    private static final String GUID = "guid";
    private static final String CART = "cart";

    @Mock
    private BrainTreeTransactionService brainTreeTransactionService;
    @Mock
    private BraintreeCustomFieldsService customFieldsService;
    @Mock
    private GuidKeyGenerator guidKeyGenerator;
    @Mock
    private ProcessParameterHelper processParameterHelper;
    @Mock
    private ModelService modelService;
    @Mock
    private ImpersonationService impersonationService;

    @InjectMocks
    private BrainTreeAuthorizePaymentAction unit;

    @Mock
    private ReplenishmentProcessModel process;
    @Mock
    private BusinessProcessParameterModel processParameter;
    @Mock
    private CartModel cart;
    @Mock
    private BrainTreePaymentInfoModel paymentInfo;
    @Mock
    private PaymentTransactionEntryModel transactionEntry;

    @Captor
    private ArgumentCaptor<ImpersonationService.Executor<AbstractSimpleDecisionAction.Transition, ImpersonationService.Nothing>> executorArgumentCaptor;
    @Captor
    private ArgumentCaptor<CommerceOrderParameter> parameterArgumentCaptor;

    @Test
    public void shouldCreateAuthorizationAndCompleteActionWithOkStatus() throws Exception {
        when(guidKeyGenerator.generate()).thenReturn(GUID);
        when(brainTreeTransactionService.createAuthorizationTransaction(any(CommerceOrderParameter.class))).thenReturn(transactionEntry);
        when(processParameterHelper.getProcessParameterByName(process, CART)).thenReturn(processParameter);
        when(processParameter.getValue()).thenReturn(cart);
        when(cart.getPaymentInfo()).thenReturn(paymentInfo);
        when(transactionEntry.getTransactionStatus()).thenReturn(TransactionStatus.ACCEPTED.name());

        unit.executeAction(process);

        verify(impersonationService).executeInContext(any(ImpersonationContext.class), executorArgumentCaptor.capture());
        ImpersonationService.Executor<AbstractSimpleDecisionAction.Transition, ImpersonationService.Nothing> executor = executorArgumentCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = executor.execute();

        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void shouldCreateAuthorizationAndCompleteActionWithNokStatus() throws Exception {
        when(guidKeyGenerator.generate()).thenReturn(GUID);
        when(brainTreeTransactionService.createAuthorizationTransaction(any(CommerceOrderParameter.class))).thenReturn(transactionEntry);
        when(processParameterHelper.getProcessParameterByName(process, CART)).thenReturn(processParameter);
        when(processParameter.getValue()).thenReturn(cart);
        when(cart.getPaymentInfo()).thenReturn(paymentInfo);
        when(transactionEntry.getTransactionStatus()).thenReturn(TransactionStatus.REJECTED.name());

        unit.executeAction(process);

        verify(impersonationService).executeInContext(any(ImpersonationContext.class), executorArgumentCaptor.capture());
        ImpersonationService.Executor<AbstractSimpleDecisionAction.Transition, ImpersonationService.Nothing> executor = executorArgumentCaptor.getValue();

        AbstractSimpleDecisionAction.Transition result = executor.execute();

        assertEquals(AbstractSimpleDecisionAction.Transition.NOK, result);
        verify(cart).setStatus(OrderStatus.B2B_PROCESSING_ERROR);
    }

}