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

import java.util.Map;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration;
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.DossierTemplateExportService;
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.FileExchangeExportService;
import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AddNotificationRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue;
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class ExportDownloadMessageReceiver {

    public static final String EXPORT_DOWNLOAD_LISTENER_ID = "export-download-listener";
    static long MB = 1024 * 1024;
    DossierTemplateExportService dossierTemplateService;
    FileExchangeExportService fileExchangeExportService;
    DownloadStatusPersistenceService downloadStatusPersistenceService;
    NotificationPersistenceService notificationPersistenceService;


    @RabbitHandler
    @RabbitListener(id = EXPORT_DOWNLOAD_LISTENER_ID)
    public void receive(ExportDownloadMessage downloadJob) throws JsonProcessingException {

        var download = downloadStatusPersistenceService.getStatus(downloadJob.getStorageId());
        try {
            long start = System.currentTimeMillis();

            long contentLength = switch (downloadJob.getType()) {
                case DOSSIER_TEMPLATE -> {
                    log.info("Preparing dossier template export download for userId: {} and storageId: {}", downloadJob.getUserId(), downloadJob.getStorageId());
                    yield dossierTemplateService.createDownloadArchive(downloadJob);
                }
                case FILE_EXCHANGE -> {
                    log.info("Preparing file exchange export download for userId: {} and storageId: {}", downloadJob.getUserId(), downloadJob.getStorageId());
                    yield fileExchangeExportService.createDownloadArchive(downloadJob);
                }
            };

            log.info("Finished export of template {} with size {} MB for userId: {} in {} ms",
                     downloadJob.getDossierTemplateId(),
                     contentLength / MB,
                     downloadJob.getUserId(),
                     System.currentTimeMillis() - start);

            downloadStatusPersistenceService.updateStatus(download, DownloadStatusValue.READY, contentLength);

            notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
                                                                      .userId(download.getUserId())
                                                                      .issuerId(download.getUserId())
                                                                      .notificationType(NotificationType.DOWNLOAD_READY.name())
                                                                      .target(Map.of("userId", download.getUserId(), //
                                                                                     "dossierTemplateId", downloadJob.getDossierTemplateId(), //
                                                                                     "downloadId", download.getStatus()))
                                                                      .build());
        } catch (Exception e) {
            log.error("Export preparation failed with error: ", e);
            downloadStatusPersistenceService.updateStatus(downloadJob.getStorageId(), DownloadStatusValue.FAILED);
            notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
                                                                      .userId(download.getUserId())
                                                                      .issuerId(download.getUserId())
                                                                      .notificationType("DOWNLOAD_FAILED")
                                                                      .target(Map.of("userId", download.getUserId(), //
                                                                                     "dossierTemplateId", downloadJob.getDossierTemplateId(), //
                                                                                     "downloadId", download.getStatus()))
                                                                      .build());
            throw new RuntimeException(e);
        }

    }


    @RabbitHandler
    @RabbitListener(queues = MessagingConfiguration.EXPORT_DOWNLOAD_DLQ)
    public void receiveDLQ(DownloadJob downloadJob) {

        log.error("Creation of download package for user {} with id {} failed!", downloadJob.getUserId(), downloadJob.getStorageId());
        downloadStatusPersistenceService.updateStatus(downloadJob.getStorageId(), DownloadStatusValue.FAILED);
    }

}
