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

import com.intrasoft.ermis.cargov1.messages.MessageTypes;
import com.intrasoft.ermis.common.logging.ErmisLogger;
import com.intrasoft.ermis.transit.cargoofficeofdestination.core.outbound.ValidationRequestEventProducer;
import com.intrasoft.ermis.transit.cargoofficeofdestination.domain.Message;
import com.intrasoft.ermis.transit.cargoofficeofdestination.domain.events.ValidationRequestedDomainEvent;
import com.intrasoft.ermis.transit.contracts.validation.enums.ValidationTypeEnum;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ValidationRequestServiceImpl implements ValidationRequestService {

    private final ValidationRequestEventProducer validationRequestedEventProducer;

    private final DossierDataService dossierDataService;

    private final ErmisLogger logger;

    @Override
    public void publishValidationRequest(String messageId, String movementId) {

        logger.error("ENTER publishValidationRequest() " + messageId);

        List<String> validationTypes = new ArrayList<>();

        Message message = dossierDataService.getMessageById(messageId);

        if (MessageTypes.TB_015_C.value().equals(message.getMessageType())) {
            validationTypes.addAll(List.of(
                    ValidationTypeEnum.SEMANTIC_VALIDATION.getType(),
                    ValidationTypeEnum.XSD_VALIDATION.getType()));
        } else if (MessageTypes.TB_007_C.value().equals(message.getMessageType())) {
            // TODO: Refine validation types for TB007.
            validationTypes.addAll(List.of(
                    ValidationTypeEnum.SEMANTIC_VALIDATION.getType(),
                    ValidationTypeEnum.XSD_VALIDATION.getType()));
        }

        validationRequestedEventProducer.publish(createValidationRequestedDomainEvent(messageId, movementId, validationTypes));

        logger.info("EXIT publishValidationRequest() " + messageId);
    }

    private ValidationRequestedDomainEvent createValidationRequestedDomainEvent(String messageId, String movementId, List<String> validationTypes) {
        return  ValidationRequestedDomainEvent.builder()
                                              .messageId(messageId)
                                              .movementId(movementId)
                                              .requestedValidationTypeList(validationTypes)
                                              .build();
    }
}

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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.intrasoft.ermis.cargov1.messages.MessageTypes;
import com.intrasoft.ermis.common.logging.ErmisLogger;
import com.intrasoft.ermis.transit.cargoofficeofdestination.core.outbound.ValidationRequestEventProducer;
import com.intrasoft.ermis.transit.cargoofficeofdestination.core.service.DossierDataService;
import com.intrasoft.ermis.transit.cargoofficeofdestination.core.service.ValidationRequestServiceImpl;
import com.intrasoft.ermis.transit.cargoofficeofdestination.domain.Message;
import com.intrasoft.ermis.transit.cargoofficeofdestination.domain.events.ValidationRequestedDomainEvent;
import com.intrasoft.ermis.transit.contracts.validation.enums.ValidationTypeEnum;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;
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.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ExtendWith(MockitoExtension.class)
class ValidationRequestServiceImplUT {

    private static final String MESSAGE_ID = UUID.randomUUID().toString();

    private static final String MOVEMENT_ID = UUID.randomUUID().toString();

    private static final List<String> MESSAGE_TYPES = List.of(
            MessageTypes.TB_015_C.value(),
            MessageTypes.TB_007_C.value()
    );

    @Captor
    private ArgumentCaptor<ValidationRequestedDomainEvent> validationRequestedDomainEventArgumentCaptor;

    @Mock
    private ValidationRequestEventProducer validationRequestedEventProducer;

    @Mock
    private DossierDataService dossierDataService;

    @Mock
    private ErmisLogger ermisLogger;

    @InjectMocks
    private ValidationRequestServiceImpl validationRequestService;

    @ParameterizedTest
    @MethodSource("arguments")
    @DisplayName("Test that a ValidationRequestedDomainEvent is created and passed to the producer")
    void test_creationAndPublishOfValidationRequestedEvent(String messageType) {
        when(dossierDataService.getMessageById(MESSAGE_ID)).thenReturn(createMessage(messageType));
        doNothing().when(validationRequestedEventProducer).publish(any(ValidationRequestedDomainEvent.class));

        validationRequestService.publishValidationRequest(MESSAGE_ID, MOVEMENT_ID);

        verify(validationRequestedEventProducer, times(1)).publish(validationRequestedDomainEventArgumentCaptor.capture());

        assertEquals(MESSAGE_ID, validationRequestedDomainEventArgumentCaptor.getValue().getMessageId());
        assertEquals(MOVEMENT_ID, validationRequestedDomainEventArgumentCaptor.getValue().getMovementId());
        assertNotNull(validationRequestedDomainEventArgumentCaptor.getValue().getRequestedValidationTypeList());
        List<String> requestedValidationTypeList = validationRequestedDomainEventArgumentCaptor.getValue().getRequestedValidationTypeList();

        if (MessageTypes.TB_015_C.value().equals(messageType)) {
            assertEquals(2, requestedValidationTypeList.size());
            assertTrue(requestedValidationTypeList.contains(ValidationTypeEnum.XSD_VALIDATION.getType()));
            assertTrue(requestedValidationTypeList.contains(ValidationTypeEnum.SEMANTIC_VALIDATION.getType()));
        } else if (MessageTypes.TB_007_C.value().equals(messageType)) {
            // TODO: Refine validation types for TB007.
            assertEquals(2, requestedValidationTypeList.size());
            assertTrue(requestedValidationTypeList.contains(ValidationTypeEnum.XSD_VALIDATION.getType()));
            assertTrue(requestedValidationTypeList.contains(ValidationTypeEnum.SEMANTIC_VALIDATION.getType()));
        }
    }

    private static Stream<Arguments> arguments() {
        List<Arguments> argumentsList = new ArrayList<>();

        for (String expectedMessageType : MESSAGE_TYPES) {
            argumentsList.add(Arguments.of(expectedMessageType));
        }

        return argumentsList.stream();
    }

    private Message createMessage(String messageType) {
        return Message.builder()
                      .id(MESSAGE_ID)
                      .messageType(messageType)
                      .build();
    }
}
