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

import com.intrasoft.ermis.common.json.parsing.JsonConverter;
import com.intrasoft.ermis.common.json.parsing.JsonConverterFactory;
import com.intrasoft.ermis.common.logging.ErmisLogger;
import com.intrasoft.ermis.contracts.core.dto.declaration.common.RegimeEnum;
import com.intrasoft.ermis.contracts.core.dto.declaration.riskassessment.v2.RiskAssessmentResponseEvent;
import com.intrasoft.ermis.transit.common.config.services.GetCountryCodeService;
import com.intrasoft.ermis.transit.common.enums.DirectionEnum;
import com.intrasoft.ermis.transit.common.enums.MessageDomainTypeEnum;
import com.intrasoft.ermis.transit.common.mappers.MessageTypeMapper;
import com.intrasoft.ermis.transit.management.core.port.inbound.RiskAssessmentMessageProcessingService;
import com.intrasoft.ermis.transit.management.core.port.outbound.DossierDataService;
import com.intrasoft.ermis.transit.management.core.port.outbound.ProcessMessageCommandProducer;
import com.intrasoft.ermis.transit.management.domain.Message;
import com.intrasoft.ermis.transit.management.domain.Movement;
import com.jayway.jsonpath.JsonPath;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;


@Service
@RequiredArgsConstructor
public class RiskAssessmentMessageProcessingServiceImpl implements RiskAssessmentMessageProcessingService {

    private static final JsonConverter JSON_CONVERTER = JsonConverterFactory.getDefaultJsonConverter();

    private final ErmisLogger log;

    private final DossierDataService dossierDataService;

    private final ProcessMessageCommandProducer processMessageCommandProducer;

    private final GetCountryCodeService getCountryCodeService;

    private static final String RISK_ASSESSMENT_SOURCE = "RISK_ASSESSMENT";

    private static final String RESPONSE_ID_JSON_PATH = "$.responseId";

    @Override
    public void processMessage(String messageJson) {
        log.info("RiskAssessmentMessageProcessingServiceImpl - processMessage");

        RiskAssessmentResponseEvent receivedEvent = JSON_CONVERTER.convertStringToObject(messageJson, RiskAssessmentResponseEvent.class);

        if (RegimeEnum.TRANSIT.getCode().equals(receivedEvent.getRegime())) {
            String movementId = receivedEvent.getCorrelationKey();
            Message message = setUpMessage(messageJson);

            message = dossierDataService.persistMessage(message);
            dossierDataService.associateMessageWithMovement(message.getId(), movementId);

            Movement movement = dossierDataService.getMovementById(movementId, false);
            processMessageCommandProducer.publish(message.getId(), message.getMessageType(), movement);
        } else {
            log.info("Consumed non-Transit RiskAssessmentResponseEvent! Ignoring...");
        }
    }

    protected Message setUpMessage(String messageJson) {
        return Message.builder()
                      .messageIdentification(JsonPath.read(messageJson, RESPONSE_ID_JSON_PATH))
                      .messageType(RiskAssessmentResponseEvent.class.getSimpleName())
                      .source(RISK_ASSESSMENT_SOURCE)
                      .destination(MessageTypeMapper.NTA.concat(getCountryCodeService.getCountryCode()))
                      .payload(messageJson)
                      .domain(MessageDomainTypeEnum.ERMIS.name())
                      .direction(DirectionEnum.RECEIVED.getDirection())
                      .build();
    }
}

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

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.intrasoft.ermis.common.logging.ErmisLogger;
import com.intrasoft.ermis.contracts.core.dto.declaration.riskassessment.v2.RiskAssessmentRequestEvent;
import com.intrasoft.ermis.contracts.core.dto.declaration.riskassessment.v2.RiskAssessmentResponseEvent;
import com.intrasoft.ermis.transit.common.config.services.GetCountryCodeService;
import com.intrasoft.ermis.transit.common.enums.MessageDomainTypeEnum;
import com.intrasoft.ermis.transit.common.enums.OfficeRoleTypesEnum;
import com.intrasoft.ermis.transit.common.enums.ProcessingStatusTypeEnum;
import com.intrasoft.ermis.transit.management.core.port.outbound.DossierDataService;
import com.intrasoft.ermis.transit.management.core.port.outbound.ProcessMessageCommandProducer;
import com.intrasoft.ermis.transit.management.domain.Message;
import com.intrasoft.ermis.transit.management.domain.Movement;
import com.intrasoft.ermis.transit.shared.testing.util.FileHelpers;
import java.util.List;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)
public class RiskAssessmentMessageProcessingServiceImplUT {

    @Mock
    private ErmisLogger ermisLogger;

    @Mock
    private DossierDataService dossierDataService;

    @Mock
    private ProcessMessageCommandProducer processMessageCommandProducer;

    @Mock
    private GetCountryCodeService getCountryCodeService;

    @InjectMocks
    private RiskAssessmentMessageProcessingServiceImpl riskAssessmentMessageProcessingService;

    @Captor
    ArgumentCaptor<Message> messageArgumentCaptor;

    @Captor
    private ArgumentCaptor<String> messageIdCaptor;

    @Captor
    private ArgumentCaptor<String> movementIdCaptor;

    @Captor
    private ArgumentCaptor<String> messageTypeCaptor;

    @Captor
    ArgumentCaptor<Movement> movementArgumentCaptor;

    private static final String MOVEMENT_ID = "TEST_MOVEMENT_ID";

    private static final String REQUEST_ID = "TEST_REQUEST_ID";

    private static final String RESPONSE_ID = "TEST_RESPONSE_ID";

    private static final String DESTINATION = "NTA.DE";

    private static final String RISK_ASSESSMENT = "RISK_ASSESSMENT";

    private static final String OFFICE_ID = "AA000001";

    @Test
    @SneakyThrows
    void testProcessMessage_success() {
        // given
        String responseMessageJson = FileHelpers.readClasspathFile("data/RiskAssessmentResponseEvent.json");
        String requestMessageJson = FileHelpers.readClasspathFile("data/RiskAssessmentRequestEvent.json");

        // when
        Message requestMessage = mockRequestMessage(requestMessageJson);
        Movement movement = Movement.builder()
                                    .id(MOVEMENT_ID)
                                    .officeRoleType(OfficeRoleTypesEnum.DESTINATION.getValue())
                                    .officeId("AA000001")
                                    .processingStatus(ProcessingStatusTypeEnum.OODEST_AAR_CREATED.getItemCode())
                                    .build();
        when(getCountryCodeService.getCountryCode()).thenReturn("DK");
        when(dossierDataService.getMovementById(MOVEMENT_ID, false)).thenReturn(movement);
        when(dossierDataService.persistMessage(any())).thenAnswer(argument -> {
            Message message = argument.getArgument(0);
            message.setId(RESPONSE_ID);
            return message;
        });
        riskAssessmentMessageProcessingService.processMessage(responseMessageJson);

        // then
        verify(dossierDataService, times(1)).persistMessage(messageArgumentCaptor.capture());
        verify(dossierDataService, times(1)).associateMessageWithMovement(messageIdCaptor.capture(), movementIdCaptor.capture());
        verify(processMessageCommandProducer, times(1)).publish(messageIdCaptor.capture(), messageTypeCaptor.capture(),
                movementArgumentCaptor.capture());

        assertThat(messageIdCaptor.getValue()).isEqualTo(RESPONSE_ID);
        assertThat(movementIdCaptor.getValue()).isEqualTo(MOVEMENT_ID);
        assertThat(messageTypeCaptor.getValue()).isEqualTo(RiskAssessmentResponseEvent.class.getSimpleName());
        List<Movement> publishedMovements = movementArgumentCaptor.getAllValues();
        assertThat(publishedMovements.size()).isEqualTo(1);
        assertTrue(publishedMovements.stream()
                                     .filter(m -> m.getOfficeRoleType().equals(OfficeRoleTypesEnum.DESTINATION.getValue()))
                                     .allMatch(m -> m.getOfficeId().equals(OFFICE_ID)));
    }

    private Message mockRequestMessage(String requestMessageJson) {
        return Message.builder()
                      .messageIdentification("TEST_REQUEST_ID")
                      .messageType(RiskAssessmentRequestEvent.class.getSimpleName())
                      .source(DESTINATION)
                      .destination(RISK_ASSESSMENT)
                      .domain(MessageDomainTypeEnum.ERMIS.name())
                      .payload(requestMessageJson)
                      .build();
    }
}
