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

import static com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames.LAYOUT_PARSING_DLQ;

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;

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

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.model.websocket.AnalyseStatus;
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.ImageSimilarityService;
import com.iqser.red.service.persistence.management.v1.processor.service.websocket.WebsocketService;
import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.QueueMessageIdentifierService;
import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingFinishedEvent;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingRequest;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class LayoutParsingFinishedMessageReceiver {

    public static final String LAYOUT_PARSING_RESPONSE_LISTENER_ID = "layout-parsing-response-listener";

    private final FileStatusService fileStatusService;
    private final FileStatusProcessingUpdateService fileStatusProcessingUpdateService;
    private final ObjectMapper objectMapper;
    private final ImageSimilarityService imageSimilarityService;
    private final WebsocketService websocketService;


    @SneakyThrows
    @RabbitListener(id = LAYOUT_PARSING_RESPONSE_LISTENER_ID)
    public void receive(LayoutParsingFinishedEvent response) {

        var dossierId = QueueMessageIdentifierService.parseDossierId(response.identifier());
        var fileId = QueueMessageIdentifierService.parseFileId(response.identifier());
        log.info("Layout parsing has finished for {}/{} in {}", dossierId, fileId, LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_EXCHANGE);


        fileStatusService.setStatusAnalyse(QueueMessageIdentifierService.parseDossierId(response.identifier()),
                                           QueueMessageIdentifierService.parseFileId(response.identifier()),
                                           QueueMessageIdentifierService.parsePriority(response.identifier()));

        fileStatusService.updateLayoutParserVersionAndProcessedTime(QueueMessageIdentifierService.parseFileId(response.identifier()), response.layoutParserVersion());

        websocketService.sendAnalysisEvent(dossierId, fileId, AnalyseStatus.LAYOUT_UPDATE, fileStatusService.getStatus(fileId).getNumberOfAnalyses() + 1);

        try {
            imageSimilarityService.saveImages("", dossierId, fileId);
        } catch (Exception e) {
            log.error("Error occured during save images: {} ", e.getMessage(), e);
            throw e;
        }

        log.info("Received message {} from exchange {}", response, LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_EXCHANGE);
    }


    @SneakyThrows
    @RabbitListener(queues = LAYOUT_PARSING_DLQ)
    public void handleDLQMessage(Message failedMessage) {

        LayoutParsingRequest analyzeRequest = objectMapper.readValue(failedMessage.getBody(), LayoutParsingRequest.class);
        log.info("Failed to process analyze request: {}", analyzeRequest);
        String errorCause = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_HEADER);
        if (errorCause == null) {
            errorCause = "Error occured during layout parsing!";
        }

        OffsetDateTime timestamp = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_TIMESTAMP_HEADER);
        timestamp = timestamp != null ? timestamp : OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS);
        log.info("Failed to process layout parsing request, errorCause: {}, timestamp: {}", errorCause, timestamp);
        fileStatusProcessingUpdateService.analysisFailed(QueueMessageIdentifierService.parseDossierId(analyzeRequest.identifier()),
                                                         QueueMessageIdentifierService.parseFileId(analyzeRequest.identifier()),
                                                         new FileErrorInfo(errorCause, LAYOUT_PARSING_DLQ, "layoutparser-service", timestamp));

    }

}
