package com.iqser.red.service.persistence.management.v1.processor.service.queue;

import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusProcessingUpdateService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.QueueMessageIdentifierService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo;
import com.knecon.fforesight.llm.service.LlmNerMessage;
import com.knecon.fforesight.llm.service.LlmNerResponseMessage;

import io.micrometer.observation.ObservationRegistry;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class NerMessageReceiver {

    public static final String ENTITY_RESPONSE_LISTENER_ID = "entity-response-listener";
    public static final String LLM_ENTITY_RESPONSE_LISTENER_ID = "llm-entity-response-listener";

    private final FileStatusService fileStatusService;
    private final ObjectMapper objectMapper;
    private final FileStatusProcessingUpdateService fileStatusProcessingUpdateService;
    private final FileStatusPersistenceService fileStatusPersistenceService;
    private final ObservationRegistry observationRegistry;


    @SneakyThrows
    @RabbitListener(id = ENTITY_RESPONSE_LISTENER_ID)
    public void receive(Message message) {

        HashMap<String, Object> entityResponse = objectMapper.readValue(message.getBody(), new TypeReference<>() {
        });

        String dossierId = (String) entityResponse.get("dossierId");
        String fileId = (String) entityResponse.get("fileId");
        addFileIdToTrace(fileId);

        log.info("Received message from exchange {} for dossierId {} and fileId  {}", MessagingConfiguration.ENTITY_RESPONSE_EXCHANGE, dossierId, fileId);
        fileStatusService.setStatusAnalyse(dossierId, fileId, false);
    }


    @SneakyThrows
    @RabbitListener(id = LLM_ENTITY_RESPONSE_LISTENER_ID)
    public void receiveLLM(LlmNerResponseMessage message) {

        String dossierId = QueueMessageIdentifierService.parseDossierId(message.getIdentifier());
        String fileId = QueueMessageIdentifierService.parseFileId(message.getIdentifier());
        addFileIdToTrace(fileId);

        log.info("Received message from {} for dossierId {} and fileId  {}", LLM_ENTITY_RESPONSE_LISTENER_ID, dossierId, fileId);
        fileStatusPersistenceService.setAiCreationVersion(fileId, message.getAiCreationVersion());
        fileStatusService.setStatusForceAnalyse(dossierId, fileId, false);
    }


    @RabbitListener(queues = MessagingConfiguration.ENTITY_DLQ)
    public void handleDLQMessage(Message failedMessage) throws IOException {

        HashMap<String, Object> entityResponse = objectMapper.readValue(failedMessage.getBody(), new TypeReference<>() {
        });
        String dossierId = (String) entityResponse.get("dossierId");
        String fileId = (String) entityResponse.get("fileId");
        addFileIdToTrace(fileId);

        log.warn("Received message {} for dossierId {} and fileId {}", MessagingConfiguration.ENTITY_DLQ, dossierId, fileId);
        fileStatusProcessingUpdateService.analysisFailed(dossierId,
                                                         fileId,
                                                         new FileErrorInfo("ner service failed",
                                                                           MessagingConfiguration.ENTITY_DLQ,
                                                                           "entity-recognition-service-v3",
                                                                           OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)));
    }


    @RabbitListener(queues = MessagingConfiguration.LLM_NER_DLQ)
    public void handleLLMDLQMessage(Message failedMessage) throws IOException {

        LlmNerMessage entityResponse = objectMapper.readValue(failedMessage.getBody(), LlmNerMessage.class);

        String dossierId = QueueMessageIdentifierService.parseDossierId(entityResponse.getIdentifier());
        String fileId = QueueMessageIdentifierService.parseFileId(entityResponse.getIdentifier());

        addFileIdToTrace(fileId);

        log.warn("Received message {} for dossierId {} and fileId {}", MessagingConfiguration.LLM_NER_DLQ, dossierId, fileId);
        fileStatusProcessingUpdateService.analysisFailed(dossierId,
                                                         fileId,
                                                         new FileErrorInfo("llm ner service failed",
                                                                           MessagingConfiguration.LLM_NER_DLQ,
                                                                           "llm-service",
                                                                           OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)));
    }


    // This can be removed if tracing is implemented in python services.
    private void addFileIdToTrace(String fileId) {

        if (observationRegistry.getCurrentObservation() != null) {
            observationRegistry.getCurrentObservation().highCardinalityKeyValue("fileId", fileId);
        }
    }

}
