package com.braintree.actions.order;

import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.basecommerce.enums.FraudStatus;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.fraud.model.FraudReportModel;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.servicelayer.time.TimeService;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;

import static junit.framework.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


@UnitTest
public class BrainTreeScheduleForCleanUpActionTest {

    private BrainTreeScheduleForCleanUpAction action = null;
    private OrderProcessModel orderProcess = null;
    private final Integer minPeriodWaitingForCleanUp = Integer.valueOf(10);

    @Before
    public void setup() {
        prepareAction();
        prepareOrderProcess();
    }

    protected void prepareAction() {
        action = new BrainTreeScheduleForCleanUpAction();
        action.setTimeService(mockTimeService());
        action.setMinPeriodWaitingForCleanUpInSeconds(minPeriodWaitingForCleanUp);
    }

    protected void prepareOrderProcess() {
        final OrderModel order = new OrderModel();
        order.setFraudReports(new HashSet<FraudReportModel>());
        orderProcess = new OrderProcessModel();
        orderProcess.setOrder(order);
    }

    protected TimeService mockTimeService() {
        final TimeService mockedTimeService = mock(TimeService.class);
        when(mockedTimeService.getCurrentTime()).thenReturn(new Date());
        return mockedTimeService;
    }

    @Test
    public void testOrderShouldBeCleaned() {
        //given
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, -minPeriodWaitingForCleanUp.intValue() * 5);
        final Date timestamp = calendar.getTime();
        final FraudReportModel fraudReport = new FraudReportModel();
        fraudReport.setTimestamp(timestamp);
        fraudReport.setStatus(FraudStatus.FRAUD);
        orderProcess.getOrder().getFraudReports().add(fraudReport);
        //when
        final AbstractSimpleDecisionAction.Transition result = action.executeAction(orderProcess);
        //then
        assertEquals(AbstractSimpleDecisionAction.Transition.OK, result);
    }

    @Test
    public void testOrderShouldNotBeCleaned() {
        //given
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, (int) (minPeriodWaitingForCleanUp.intValue() * 0.5));
        final Date timestamp = calendar.getTime();
        final FraudReportModel fraudReport = new FraudReportModel();
        fraudReport.setTimestamp(timestamp);
        fraudReport.setStatus(FraudStatus.FRAUD);
        orderProcess.getOrder().getFraudReports().add(fraudReport);
        //when
        final AbstractSimpleDecisionAction.Transition result = action.executeAction(orderProcess);
        //then
        assertEquals(AbstractSimpleDecisionAction.Transition.NOK, result);
    }

    @Test
    public void shouldReturnTransitionNokIfFraudulentIsTrue() {
        //given
        orderProcess.getOrder().setFraudulent(true);

        //when
        AbstractSimpleDecisionAction.Transition result = action.executeAction(orderProcess);

        //then
        assertEquals(AbstractSimpleDecisionAction.Transition.NOK, result);
    }

    @Test
    public void shouldReturnTransitionNokIfLastReportIsNull() {
        //given
        orderProcess.getOrder().setFraudReports(null);

        //when
        AbstractSimpleDecisionAction.Transition result = action.executeAction(orderProcess);

        //then
        assertEquals(AbstractSimpleDecisionAction.Transition.NOK, result);
    }

    @Test
    public void testOrderShouldBeCleanedIfFraudStatusCheck() {
        //given
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, -minPeriodWaitingForCleanUp.intValue() * 5);
        final Date timestamp = calendar.getTime();
        final FraudReportModel fraudReport = new FraudReportModel();
        fraudReport.setTimestamp(timestamp);
        fraudReport.setStatus(FraudStatus.CHECK);
        orderProcess.getOrder().getFraudReports().add(fraudReport);

        //when
        final AbstractSimpleDecisionAction.Transition result = action.executeAction(orderProcess);

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

}
