package com.braintree.job;

import com.braintree.model.BraintreeUpdatePaymentTransactionStatusCronJobModel;
import com.braintree.transaction.service.BrainTreeTransactionService;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.core.servicelayer.data.PaginationData;
import de.hybris.platform.core.servicelayer.data.SearchPageData;
import de.hybris.platform.cronjob.enums.CronJobResult;
import de.hybris.platform.cronjob.enums.CronJobStatus;
import de.hybris.platform.payment.model.PaymentTransactionModel;
import de.hybris.platform.servicelayer.cronjob.PerformResult;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.List;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

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

    @Mock
    private BrainTreeTransactionService brainTreeTransactionService;
    @Mock
    private List<PaymentTransactionModel> paymentTransactionModels;
    @Mock
    private SearchPageData<PaymentTransactionModel> searchPageData;
    @Mock
    private BraintreeUpdatePaymentTransactionStatusCronJobModel cronJobModel;
    @Mock
    private PaginationData paginationData;

    @InjectMocks
    private BraintreeUpdatePaymentTransactionStatusJob unit;

    @Test
    public void performBraintreeUpdatePaymentTransactionStatusJobTest() {
        when(brainTreeTransactionService.getPaymentTransactionsByStatuses(any(), any())).thenReturn(searchPageData);
        when(cronJobModel.getPageSize()).thenReturn(100);
        when(searchPageData.getResults()).thenReturn(paymentTransactionModels);
        when(searchPageData.getPagination()).thenReturn(paginationData);
        when(paginationData.getCurrentPage()).thenReturn(0);
        when(paginationData.getHasNext()).thenReturn(Boolean.FALSE);

        PerformResult performResult = unit.perform(cronJobModel);

        Assert.assertEquals(CronJobStatus.FINISHED, performResult.getStatus());
        Assert.assertEquals(CronJobResult.SUCCESS, performResult.getResult());
        verify(brainTreeTransactionService).getPaymentTransactionsByStatuses(any(), any());
        verify(brainTreeTransactionService).updateBraintreePaymentTransactionStatuses(paymentTransactionModels);
    }

    @Test
    public void performBraintreeUpdatePaymentTransactionStatusJobWhenPaginationDataHasNextTest() {
        when(brainTreeTransactionService.getPaymentTransactionsByStatuses(any(), any())).thenReturn(searchPageData);
        when(cronJobModel.getPageSize()).thenReturn(100);
        when(searchPageData.getResults()).thenReturn(paymentTransactionModels);
        when(searchPageData.getPagination()).thenReturn(paginationData);
        when(paginationData.getCurrentPage()).thenReturn(0);
        when(paginationData.getHasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);

        PerformResult performResult = unit.perform(cronJobModel);

        Assert.assertEquals(CronJobStatus.FINISHED, performResult.getStatus());
        Assert.assertEquals(CronJobResult.SUCCESS, performResult.getResult());
        verify(brainTreeTransactionService, times(2)).getPaymentTransactionsByStatuses(any(), any());
        verify(brainTreeTransactionService, times(2)).updateBraintreePaymentTransactionStatuses(paymentTransactionModels);
    }

    @Test
    public void performBraintreeUpdatePaymentTransactionStatusJobWhenNoSearchResult() {
        when(brainTreeTransactionService.getPaymentTransactionsByStatuses(any(), any())).thenReturn(searchPageData);
        when(cronJobModel.getPageSize()).thenReturn(100);
        when(searchPageData.getResults()).thenReturn(paymentTransactionModels);
        when(paymentTransactionModels.isEmpty()).thenReturn(true);

        PerformResult performResult = unit.perform(cronJobModel);

        Assert.assertEquals(CronJobStatus.FINISHED, performResult.getStatus());
        Assert.assertEquals(CronJobResult.SUCCESS, performResult.getResult());
        verify(paginationData, never()).getHasNext();
        verify(brainTreeTransactionService).getPaymentTransactionsByStatuses(any(), any());
        verify(brainTreeTransactionService, never()).updateBraintreePaymentTransactionStatuses(paymentTransactionModels);
    }

    @Test
    public void performBraintreeUpdatePaymentTransactionStatusJobWhenSearchResultIsNull() {
        when(brainTreeTransactionService.getPaymentTransactionsByStatuses(any(), any())).thenReturn(searchPageData);
        when(cronJobModel.getPageSize()).thenReturn(100);
        when(searchPageData.getResults()).thenReturn(null);

        PerformResult performResult = unit.perform(cronJobModel);

        Assert.assertEquals(CronJobStatus.FINISHED, performResult.getStatus());
        Assert.assertEquals(CronJobResult.SUCCESS, performResult.getResult());
        verify(paginationData, never()).getHasNext();
        verify(brainTreeTransactionService).getPaymentTransactionsByStatuses(any(), any());
        verify(brainTreeTransactionService, never()).updateBraintreePaymentTransactionStatuses(paymentTransactionModels);
    }

}
