package com.braintree.warehouse;

import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.basecommerce.enums.ConsignmentStatus;
import de.hybris.platform.commerceservices.model.PickUpDeliveryModeModel;
import de.hybris.platform.core.model.order.AbstractOrderEntryModel;
import de.hybris.platform.ordersplitting.model.ConsignmentEntryModel;
import de.hybris.platform.ordersplitting.model.ConsignmentModel;
import de.hybris.platform.servicelayer.model.ModelService;
import de.hybris.platform.servicelayer.time.TimeService;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Date;
import java.util.Set;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


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

    private static final long CONSIGNMENT_ENTRY_QUANTITY = 12L;
    private static final String TENANT_ID = "tenantId";
    private static final long PK_LONG_VALUE = 111L;

    @Mock
    private ModelService modelService;
    @Mock
    private TimeService timeService;

    @Spy
    @InjectMocks
    private BrainTreeMockProcess2WarehouseAdapter unit;

    @Mock
    private ConsignmentModel consignment;
    @Mock
    private ConsignmentEntryModel consignmentEntry;
    @Mock
    private AbstractOrderEntryModel orderEntry;
    @Mock
    private Date date;
    @Mock
    private PickUpDeliveryModeModel pickUpDeliveryModeModel;

    @Before
    public void setUp() {
        doReturn(PK_LONG_VALUE).when(unit).getConsignmentPkLongValue(consignment);
        when(timeService.getCurrentTime()).thenReturn(date);
    }

    @Test
    public void shouldShipConsignment() {
        //given
        when(consignment.getConsignmentEntries()).thenReturn(Set.of(consignmentEntry));
        when(consignmentEntry.getOrderEntry()).thenReturn(orderEntry);
        when(orderEntry.getQuantity()).thenReturn(CONSIGNMENT_ENTRY_QUANTITY);

        //when
        unit.shipConsignment(consignment);

        //then
        verify(consignment).setStatus(ConsignmentStatus.SHIPPED);
        verify(consignment).setShippingDate(date);
        verify(consignmentEntry).setShippedQuantity(CONSIGNMENT_ENTRY_QUANTITY);
        verify(modelService).save(consignmentEntry);
        verify(modelService).save(consignment);
    }

    @Test
    public void shouldSetReadyForPickUpStatusWhenShipConsignment() {
        //given
        when(consignment.getDeliveryMode()).thenReturn(pickUpDeliveryModeModel);

        //when
        unit.shipConsignment(consignment);

        //then
        verify(consignment).setStatus(ConsignmentStatus.READY_FOR_PICKUP);
        verify(modelService).save(consignment);
    }

    @Test
    public void shouldNotDoAnythingIfConsignmentIsNullWhenShipConsignment() {
        //when
        unit.shipConsignment(null);

        //then
        verify(consignment, never()).setStatus(any(ConsignmentStatus.class));
        verify(consignment, never()).setShippingDate(any(Date.class));
        verify(consignmentEntry, never()).setShippedQuantity(anyLong());
        verify(modelService, never()).save(any(ConsignmentEntryModel.class));
        verify(modelService, never()).save(any(ConsignmentModel.class));
    }

    @Test
    public void shouldPrepareConsignment() {
        //given
        doReturn(TENANT_ID).when(unit).getTenantID();
        when(consignment.getConsignmentEntries()).thenReturn(Set.of(consignmentEntry));
        when(consignmentEntry.getQuantity()).thenReturn(CONSIGNMENT_ENTRY_QUANTITY);

        //when
        unit.prepareConsignment(consignment);

        //then
        verify(consignmentEntry).setShippedQuantity(CONSIGNMENT_ENTRY_QUANTITY);
        verify(consignment).setStatus(ConsignmentStatus.READY);
        verify(modelService).save(consignment);
    }

}
