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

import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ViewedPagesPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RecategorizationPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.ComponentLogMongoService;
import com.iqser.red.service.search.v1.model.IndexMessageType;

import jakarta.transaction.Transactional;
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 FileDeletionService {

    CommentPersistenceService commentPersistenceService;
    ViewedPagesPersistenceService viewedPagesPersistenceService;
    AddRedactionPersistenceService addRedactionPersistenceService;
    ForceRedactionPersistenceService forceRedactionPersistenceService;
    RemoveRedactionPersistenceService removeRedactionPersistenceService;
    RecategorizationPersistenceService recategorizationPersistenceService;
    LegalBasisChangePersistenceService legalBasisChangePersistenceService;
    ResizeRedactionPersistenceService resizeRedactionPersistenceService;
    FileStatusPersistenceService fileStatusPersistenceService;
    FileManagementStorageService fileManagementStorageService;
    IndexingService indexingService;
    ComponentLogMongoService componentLogMongoService;


    @Transactional
    public void undeleteFile(String fileId, OffsetDateTime softDeletedTime) {

        // revert comment deletion
        commentPersistenceService.undeleteByFileId(fileId, softDeletedTime);

        // revert annotation deletion
        addRedactionPersistenceService.undeleteByFileId(fileId, softDeletedTime);
        forceRedactionPersistenceService.undeleteByFileId(fileId, softDeletedTime);
        removeRedactionPersistenceService.undeleteByFileId(fileId, softDeletedTime);
        recategorizationPersistenceService.undeleteByFileId(fileId, softDeletedTime);
        legalBasisChangePersistenceService.undeleteByFileId(fileId, softDeletedTime);
        resizeRedactionPersistenceService.undeleteByFileId(fileId, softDeletedTime);

        fileStatusPersistenceService.undelete(fileId);
    }


    @Transactional
    public void softDeleteFiles(List<String> fileIds, OffsetDateTime softDeleteTime) {

        // delete all annotations
        addRedactionPersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);
        forceRedactionPersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);
        removeRedactionPersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);
        recategorizationPersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);
        legalBasisChangePersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);
        resizeRedactionPersistenceService.softDeleteByFileIds(fileIds, softDeleteTime);

        // delete all comments for all deleted annotations and files
        commentPersistenceService.softDeleteCommentsForFiles(fileIds, softDeleteTime);

        // delete all viewed pages for all files
        viewedPagesPersistenceService.deleteForFiles(fileIds);

        fileStatusPersistenceService.softDeleteFiles(fileIds, softDeleteTime);

    }


    private void hardDeleteFileData(String dossierId, List<String> fileIds) {

        fileIds.forEach(fileId -> {
            Arrays.stream(FileType.values())
                    .forEach(fileType -> {
                        try {
                            fileManagementStorageService.deleteObject(dossierId, fileId, fileType);
                        } catch (Exception e) {
                            log.warn("Failed to physically delete file: {} with type {}", fileId, fileType);
                        }
                    });
        });
    }


    public void hardDeleteFileDataAndIndexUpdates(String dossierId, String fileId) {

        this.hardDeleteFileDataAndIndexUpdates(dossierId, List.of(fileId));

    }


    public void hardDeleteFileDataAndIndexUpdates(String dossierId, List<String> fileIds) {

        hardDeleteFileData(dossierId, fileIds);

        fileIds.forEach(fileId -> {
            indexingService.addToDeleteFromIndexQueue(dossierId, fileId, 2);
        });

    }


    @Transactional
    public void hardDeleteFile(String dossierId, String fileId) {

        this.hardDeleteFiles(dossierId, List.of(fileId));
    }


    @Transactional
    public void hardDeleteFiles(String dossierId, List<String> fileIds) {

        deleteAllRelatedEntries(dossierId, fileIds);

        fileStatusPersistenceService.hardDeleteFiles(fileIds);

    }


    @Transactional
    public void hardDeleteFiles(String dossierId, List<String> fileIds, OffsetDateTime hardDeleteTime) {

        deleteAllRelatedEntries(dossierId, fileIds);

        fileStatusPersistenceService.hardDeleteFiles(fileIds, hardDeleteTime);

    }


    private void deleteAllRelatedEntries(String dossierId, List<String> fileIds) {

        // delete all annotations
        addRedactionPersistenceService.deleteByFileIds(fileIds);
        forceRedactionPersistenceService.deleteByFileIds(fileIds);
        removeRedactionPersistenceService.deleteByFileIds(fileIds);
        recategorizationPersistenceService.deleteByFileIds(fileIds);
        legalBasisChangePersistenceService.deleteByFileIds(fileIds);
        resizeRedactionPersistenceService.deleteByFileIds(fileIds);

        // delete all comments for all deleted annotations and files
        commentPersistenceService.deleteByFileIds(fileIds);

        // delete all viewed pages for all files
        viewedPagesPersistenceService.deleteForFiles(fileIds);

        fileIds.forEach(fileId -> componentLogMongoService.deleteComponentLog(dossierId, fileId));

    }


    public void reindexDeletedFiles(String dossierId, Collection<String> relevantFileIds) {

        relevantFileIds.forEach(fileId -> {
            indexingService.addToIndexingQueue(IndexMessageType.UPDATE, null, dossierId, fileId, 2);
        });
    }


    public void reindexUndeletedFiles(String dossierTemplateId, String dossierId, Collection<String> relevantFileIds) {

        relevantFileIds.forEach(fileId -> {
            indexingService.addToIndexingQueue(IndexMessageType.UPDATE, dossierTemplateId, dossierId, fileId, 2);
        });
    }

}
