package com.braintree.facade.impl;

import com.braintree.enums.BraintreePaymentTransactionStatus;
import com.braintree.model.PaymentTransactionLogEntryModel;
import com.braintree.transaction.service.BrainTreeTransactionService;
import com.braintreegateway.StatusEvent;
import com.braintreegateway.Transaction;
import com.braintreegateway.WebhookNotification;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.core.model.order.AbstractOrderModel;
import de.hybris.platform.payment.model.PaymentTransactionModel;
import de.hybris.platform.servicelayer.model.ModelService;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.List;
import java.util.Calendar;
import java.util.GregorianCalendar;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.mock;

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

    @Mock
    private BrainTreeTransactionService brainTreeTransactionService;

    @Mock
    private ModelService modelService;

    @Mock
    private List<StatusEvent> statusHistory;

    private WebhookNotification webhookNotification;
    private PaymentTransactionLogEntryModel logEntryModel;
    private PaymentTransactionModel paymentTransactionModel;

    @InjectMocks
    private DefaultBrainTreeOrderFacade unit;

    @Test
    public void shouldSetSettlementDeclinedStatusUpdateOrderStatusWithUsBankAccountPaymentMethod() {
        defaultPreparingBeforeUpdateOrderStatusWithUsBankAccountPaymentMethod();
        when(webhookNotification.getKind()).thenReturn(WebhookNotification.Kind.TRANSACTION_SETTLEMENT_DECLINED);

        unit.updateOrderStatusWithUsBankAccountPaymentMethod(webhookNotification);

        verify(modelService).save(logEntryModel);
        verify(brainTreeTransactionService).saveBraintreeTransactionStatus(
                BraintreePaymentTransactionStatus.SETTLEMENT_DECLINED.toString(), paymentTransactionModel);
    }

    @Test
    public void shouldSetSettledStatusUpdateOrderStatusWithUsBankAccountPaymentMethod() {
        defaultPreparingBeforeUpdateOrderStatusWithUsBankAccountPaymentMethod();
        when(webhookNotification.getKind()).thenReturn(WebhookNotification.Kind.TRANSACTION_SETTLED);

        unit.updateOrderStatusWithUsBankAccountPaymentMethod(webhookNotification);

        verify(modelService).save(logEntryModel);
        verify(brainTreeTransactionService).saveBraintreeTransactionStatus(
                BraintreePaymentTransactionStatus.SETTLED.toString(), paymentTransactionModel);
    }

    private void defaultPreparingBeforeUpdateOrderStatusWithUsBankAccountPaymentMethod() {
        webhookNotification = mock(WebhookNotification.class);
        Transaction transaction = mock(Transaction.class);
        StatusEvent statusEvent = mock(StatusEvent.class);
        Calendar calendar = new GregorianCalendar();
        paymentTransactionModel = mock(PaymentTransactionModel.class);
        AbstractOrderModel abstractOrderModel = mock(AbstractOrderModel.class);
        logEntryModel = mock(PaymentTransactionLogEntryModel.class);

        when(webhookNotification.getTransaction()).thenReturn(transaction);

        //get time for log entry
        when(transaction.getStatusHistory()).thenReturn(statusHistory);
        when(statusHistory.size()).thenReturn(1);
        when(statusHistory.get(0)).thenReturn(statusEvent);
        when(statusEvent.getTimestamp()).thenReturn(calendar);

        when(brainTreeTransactionService.findTransactionByTransactionId(any())).thenReturn(paymentTransactionModel);
        when(paymentTransactionModel.getOrder()).thenReturn(abstractOrderModel);
        when(brainTreeTransactionService.createTransactionLogEntry(any(), any(), any(), any(), any())).thenReturn(logEntryModel);
    }
}
