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 org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
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.OCRStatusUpdateResponse;
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.websocket.WebsocketService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo;
import com.knecon.fforesight.service.ocr.v1.api.model.DocumentRequest;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class OCRProcessingMessageReceiver {

    public static final String OCR_RESPONSE_LISTENER_ID = "ocr-response-listener";
    public static final String OCR_STATUS_UPDATE_LISTENER_ID = "ocr-status-update-listener";

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


    @SneakyThrows
    @RabbitHandler
    @RabbitListener(id = OCR_STATUS_UPDATE_LISTENER_ID)
    public void handleOCRStatusUpdateMessage(OCRStatusUpdateResponse response) {

        var fileModel = fileStatusService.getStatus(response.getFileId());

        if (response.isOcrStarted()) {
            fileStatusProcessingUpdateService.ocrProcessingUpdateOnly(response.getFileId());
        } else {
            fileStatusService.updateOCRStatus(response);
            websocketService.sendOcrUpdateAnalysisEvent(fileModel.getDossierId(),
                                                        fileModel.getId(),
                                                        AnalyseStatus.OCR_PROCESSING,
                                                        fileModel.getNumberOfAnalyses() + 1,
                                                        response.getNumberOfPagesToOCR(),
                                                        response.getNumberOfOCRedPages());
        }

        log.debug("Received message {} in {}", response, MessagingConfiguration.OCR_STATUS_UPDATE_RESPONSE_EXCHANGE);
    }


    @SneakyThrows
    @RabbitHandler
    @RabbitListener(queues = MessagingConfiguration.OCR_STATUS_UPDATE_DLQ)
    public void handleOCRStatusUpdateDLQMessage(Message failedMessage) {

        var response = objectMapper.readValue(failedMessage.getBody(), OCRStatusUpdateResponse.class);

        log.debug("Received message {} in {}", response, MessagingConfiguration.OCR_STATUS_UPDATE_DLQ);
    }


    @RabbitHandler
    @RabbitListener(id = OCR_RESPONSE_LISTENER_ID)
    public void handleOCRResponseMessage(Message successMessage) throws IOException {

        DocumentRequest ocrResponseMessage = objectMapper.readValue(successMessage.getBody(), DocumentRequest.class);

        log.info("OCR Response received: {}", ocrResponseMessage);
        fileStatusProcessingUpdateService.ocrSuccessful(ocrResponseMessage.getDossierId(), ocrResponseMessage.getFileId());
    }


    @RabbitHandler
    @RabbitListener(queues = MessagingConfiguration.OCR_DLQ)
    public void handleOCRDLQMessage(Message failedMessage) throws IOException {

        DocumentRequest ocrRequestMessage = objectMapper.readValue(failedMessage.getBody(), DocumentRequest.class);

        log.info("OCR DQL received: {}", ocrRequestMessage);
        String errorMessage = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_HEADER);
        OffsetDateTime timestamp = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_TIMESTAMP_HEADER);
        timestamp = timestamp != null ? timestamp : OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS);
        fileStatusProcessingUpdateService.requeueOCROrMarkFailed(ocrRequestMessage.getDossierId(),
                                                                 ocrRequestMessage.getFileId(),
                                                                 new FileErrorInfo(errorMessage, MessagingConfiguration.OCR_DLQ, "ocr-service", timestamp));
    }

}
