package com.intrasoft.ermis.transit.cargoofficeofdestination.core.service;

import com.intrasoft.ermis.transit.cargoofficeofdestination.domain.Movement;
import com.intrasoft.ermis.transit.common.config.timer.TimerDelayExecutor;
import com.intrasoft.ermis.transit.common.exceptions.BaseException;
import com.intrasoft.ermis.transit.common.exceptions.NotFoundException;
import com.intrasoft.ermis.transit.contracts.core.domain.TimerInfo;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class TimerSetupServiceImpl implements TimerSetupService {

    private static final String CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS = "getCargoAutomaticAcceptanceTimerDelayRS";

    private static final String CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS = "getCargoArrivalPresentationTimerDelayRS";

    private final DossierDataService dossierDataService;

    private final TimerDelayExecutor timerDelayExecutor;

    @Override
    public String getAutomaticAcceptanceTimerDelaySetupString(String movementId) throws BaseException {

        try {
            Movement movement = dossierDataService.getMovementById(movementId);
            return getTimerInfo(movement.getCreatedDateTime(), CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS).getTimerSetupString();
        } catch (NotFoundException exception) {
            throw new BaseException("Failed to retrieve Movement with ID: " + movementId);
        }
    }

    @Override
    public String getArrivalPresentationTimerDelaySetupString(String movementId) throws BaseException {

        try {
            Movement movement = dossierDataService.getMovementById(movementId);
            return getTimerInfo(movement.getCreatedDateTime(), CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS).getTimerSetupString();
        } catch (NotFoundException exception) {
            throw new BaseException("Failed to retrieve Movement with ID: " + movementId);
        }
    }

    private TimerInfo getTimerInfo(LocalDateTime date, String ruleSet) throws BaseException {

        return timerDelayExecutor.getTimerDelayConfig(date, LocalDateTime.now(ZoneOffset.UTC), ruleSet, false)
                                 .orElseThrow(() -> new BaseException("Failed to set up timer from ruleset: " + ruleSet));
    }
}

package com.intrasoft.ermis.transit.cargoofficeofdestination.test.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.intrasoft.ermis.transit.cargoofficeofdestination.core.service.DossierDataService;
import com.intrasoft.ermis.transit.cargoofficeofdestination.core.service.TimerSetupServiceImpl;
import com.intrasoft.ermis.transit.cargoofficeofdestination.test.util.TestDataUtilities;
import com.intrasoft.ermis.transit.common.config.timer.TimerDelayExecutor;
import com.intrasoft.ermis.transit.contracts.core.domain.TimerInfo;
import com.intrasoft.ermis.transit.contracts.core.enums.TimeUnitEnum;
import java.util.Optional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class TimerSetupServiceUT {

    private static final String MOVEMENT_ID = "TEST_MOVEMENT_ID";

    private static final String CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS = "getCargoAutomaticAcceptanceTimerDelayRS";

    private static final String CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS = "getCargoArrivalPresentationTimerDelayRS";

    @Mock
    private DossierDataService dossierDataService;

    @Mock
    private TimerDelayExecutor timerDelayExecutor;

    @InjectMocks
    private TimerSetupServiceImpl timerSetupService;

    @ParameterizedTest
    @DisplayName("Test - Get Automatic Acceptance Timer Delay Setup String")
    @ValueSource(strings = {"seconds", "minutes", "hours", "days"})
    void testGetAutomaticAcceptanceTimerDelaySetupString(String delayUnit) {
        TimerInfo testTimerInfo = createTimerInfo(CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS, delayUnit);
        // Stubs/mocks:
        when(dossierDataService.getMovementById(MOVEMENT_ID)).thenReturn(TestDataUtilities.createMovement(MOVEMENT_ID));
        when(timerDelayExecutor.getTimerDelayConfig(any(), any(), eq(CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS), anyBoolean())).thenReturn(Optional.of(testTimerInfo));
        // Call TimerSetupService method:
        String returnedValue = timerSetupService.getAutomaticAcceptanceTimerDelaySetupString(MOVEMENT_ID);
        // Verifications & Assertions:
        verify(dossierDataService).getMovementById(MOVEMENT_ID);
        verify(timerDelayExecutor).getTimerDelayConfig(any(), any(), eq(CARGO_AUTOMATIC_ACCEPTANCE_TIMER_DELAY_RS),  anyBoolean());
        assertEquals(testTimerInfo.getTimerSetupString(), returnedValue);
        switch (delayUnit) {
            case "seconds":
                assertEquals("PT5S", returnedValue);
                break;
            case "minutes":
                assertEquals("PT5M", returnedValue);
                break;
            case "hours":
                assertEquals("PT5H", returnedValue);
                break;
            case "days":
                assertEquals("P5D", returnedValue);
                break;
        }
    }

    @ParameterizedTest
    @DisplayName("Test - Get Arrival Presentation Timer Delay Setup String")
    @ValueSource(strings = {"seconds", "minutes", "hours", "days"})
    void testGetArrivalPresentationTimerDelaySetupString(String delayUnit) {
        TimerInfo testTimerInfo = createTimerInfo(CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS, delayUnit);
        // Stubs/mocks:
        when(dossierDataService.getMovementById(MOVEMENT_ID)).thenReturn(TestDataUtilities.createMovement(MOVEMENT_ID));
        when(timerDelayExecutor.getTimerDelayConfig(any(), any(), eq(CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS), anyBoolean())).thenReturn(Optional.of(testTimerInfo));
        // Call TimerSetupService method:
        String returnedValue = timerSetupService.getArrivalPresentationTimerDelaySetupString(MOVEMENT_ID);
        // Verifications & Assertions:
        verify(dossierDataService).getMovementById(MOVEMENT_ID);
        verify(timerDelayExecutor).getTimerDelayConfig(any(), any(), eq(CARGO_ARRIVAL_PRESENTATION_TIMER_DELAY_RS), anyBoolean());
        assertEquals(testTimerInfo.getTimerSetupString(), returnedValue);
        switch (delayUnit) {
            case "seconds":
                assertEquals("PT5S", returnedValue);
                break;
            case "minutes":
                assertEquals("PT5M", returnedValue);
                break;
            case "hours":
                assertEquals("PT5H", returnedValue);
                break;
            case "days":
                assertEquals("P5D", returnedValue);
                break;
        }
    }

    private TimerInfo createTimerInfo(String ruleSet, String delayUnit) {

        TimerInfo testTimerInfo = new TimerInfo();
        testTimerInfo.setRuleInstance(ruleSet);
        testTimerInfo.setErrorCode("TEST_CODE");
        testTimerInfo.setDelay(5);
        switch (delayUnit) {
            case "seconds":
                testTimerInfo.setUnit(TimeUnitEnum.SECONDS);
                break;
            case "minutes":
                testTimerInfo.setUnit(TimeUnitEnum.MINUTES);
                break;
            case "hours":
                testTimerInfo.setUnit(TimeUnitEnum.HOURS);
                break;
            case "days":
                testTimerInfo.setUnit(TimeUnitEnum.DAYS);
                break;
        }
        return testTimerInfo;
    }
}
