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.function.BiConsumer;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
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.exception.BadRequestException;
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.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;
    private final int COMMENT_MAX_LENGTH = 4000;


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

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


    @Transactional
    public Map<String, List<Comment>> getComments(String fileId) {

        return commentPersistenceService.findCommentsByFileID(fileId, false).entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> toCommentList(entry.getValue())));
    }


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

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

        fileStatusPersistenceService.updateHasComments(fileId, true);

        return createdComment;
    }


    private void checkComment(String text) {

        if (!StringUtils.isEmpty(text) && text.length() > COMMENT_MAX_LENGTH) {
            throw new BadRequestException(String.format("The comment is too long (%s), max length %s", text.length(), COMMENT_MAX_LENGTH));
        }
    }


    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;
        }
        checkComment(comment);

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


    public void hardDelete(String fileId, String annotationId) {

        commentPersistenceService.hardDelete(fileId, annotationId);
    }


    public List<Comment> getComments(String fileId, String annotationId) {

        return toCommentList(commentPersistenceService.findCommentsByAnnotationIdSortByDate(fileId, annotationId, false));
    }


    private static List<Comment> toCommentList(List<CommentEntity> entity) {

        return entity.stream()
                .map(CommentService::toComment)
                .toList();
    }


    private static Comment toComment(CommentEntity entity) {

        return MagicConverter.convert(entity, Comment.class, getDeltaMapper());
    }


    private static BiConsumer<CommentEntity, Comment> getDeltaMapper() {

        return (c1, c2) -> c2.setUserId(c1.getUser());
    }


    public Map<String, Integer> getCommentCounts(String fileId) {

        return commentPersistenceService.findCommentsByFileID(fileId, false).entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().size()));
    }

}
