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

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;

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

    CommentPersistenceService commentPersistenceService;
    FileStatusPersistenceService fileStatusPersistenceService;
    FileStatusService fileStatusService;
    RedactionLogService redactionLogService;
    FileManagementStorageService fileManagementStorageService;


    @Transactional
    public void deleteComment(String dossierId, String fileId, List<Long> commentIds) {

        for (var commentId : commentIds) {
            commentPersistenceService.softDelete(commentId, OffsetDateTime.now());
        }
        // update indicator
        fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId));

        // This is an ugly workaround, don't even look at it!
        // Basically we should change how comments work and not merge them into the redaction log.
        // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish.
        if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) {
            reprocess(dossierId, fileId);
            return;
        }
        fileStatusService.setStatusProcessing(fileId);
        RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
        redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId())));
        fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog);
        fileStatusService.setStatusProcessed(fileId);
    }


    @Transactional
    public Comments getComments(String fileId) {

        return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false)
                .entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class))));
    }


    @Transactional
    public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) {

        CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser());

        fileStatusPersistenceService.updateHasComments(fileId, true);

        // This is an ugly workaround, don't even look at it!
        // Basically we should change how comments work and not merge them into the redaction log.
        if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) {
            reprocess(dossierId, fileId);
            return createdComment;
        }
        fileStatusService.setStatusProcessing(fileId);
        RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
        redactionLog.getRedactionLogEntry()
                .stream()
                .filter(entry -> entry.getId().equals(annotationId))
                .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class)));
        fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog);
        fileStatusService.setStatusProcessed(fileId);
        return createdComment;
    }


    public Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) {

        if (comment == null) {
            return null;
        }
        return addComment(fileId, annotationId, comment, user).getId();
    }


    private CommentEntity addComment(String fileId, String annotationId, String comment, String user) {

        if (comment == null) {
            return null;
        }

        return commentPersistenceService.insert(CommentEntity.builder()
                .text(comment)
                .fileId(fileId)
                .annotationId(annotationId)
                .user(user)
                .date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS))
                .build());
    }


    private void reprocess(String dossierId, String fileId) {

        fileStatusService.setStatusReprocessForManual(dossierId, fileId, true);
    }

}
