package com.izouma.jmrh.service;

import com.izouma.jmrh.domain.*;
import com.izouma.jmrh.dto.CommentDTO;
import com.izouma.jmrh.dto.PageQuery;
import com.izouma.jmrh.enums.OrgStatus;
import com.izouma.jmrh.enums.PostType;
import com.izouma.jmrh.exception.BusinessException;
import com.izouma.jmrh.repo.CommentRepo;
import com.izouma.jmrh.repo.LikeRecordRepo;
import com.izouma.jmrh.repo.PostRepo;
import com.izouma.jmrh.repo.UserRepo;
import com.izouma.jmrh.security.Authority;
import com.izouma.jmrh.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.izouma.jmrh.web.BaseController.toPageRequest;
import static com.izouma.jmrh.web.BaseController.toSpecification;

@Service
@AllArgsConstructor
public class CommentService {

    private CommentRepo    commentRepo;
    private PostRepo       postRepo;
    private LikeRecordRepo likeRecordRepo;
    private UserRepo       userRepo;
    private MessageService messageService;

    public Comment create(Comment record) {
        Post post = postRepo.findById(record.getPostId()).orElseThrow(new BusinessException("帖子不存在"));
        if (post.getType() == PostType.OFFICIAL) {
            if (!(
                    SecurityUtils.hasRole(Authority.NAMES.ROLE_ADMIN)
                            || SecurityUtils.hasRole(Authority.NAMES.ROLE_INTERACT)
            )) {
                throw new BusinessException("无权回复");
            }
            record.setStatus(OrgStatus.PASS);
        } else {
            record.setStatus(OrgStatus.PENDING);
        }
        if (SecurityUtils.hasRole(Authority.NAMES.ROLE_ADMIN)) {
            record.setStatus(OrgStatus.PASS);
        }
        post.setCommentNum(post.getCommentNum() + 1);
        postRepo.save(post);
        record.setUserId(SecurityUtils.getAuthenticatedUser().getId());
        record = commentRepo.save(record);

        if (!post.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
            messageService.sendCommentMsg(SecurityUtils.getAuthenticatedUser().getId(), post.getUserId(), record, post);
        }

        return record;
    }

    public void del(Long id) {
        Comment comment = commentRepo.findById(id).orElseThrow(new BusinessException("无记录"));
        if (SecurityUtils.hasRole(Authority.NAMES.ROLE_ADMIN)
                || SecurityUtils.hasRole(Authority.NAMES.ROLE_INTERACT)
                || comment.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
            commentRepo.deleteById(id);
            postRepo.findById(comment.getPostId()).ifPresent(post -> {
                post.setCommentNum(Math.max(0, post.getCommentNum()));
                postRepo.save(post);
            });
        }
        throw new BusinessException("无权限");
    }

    public void like(Long commentId, boolean dislike) {
        Comment comment = commentRepo.findById(commentId).orElseThrow(new BusinessException("无记录"));
        Post post = postRepo.findById(comment.getPostId()).orElseThrow(new BusinessException("无记录"));
        LikeRecord likeRecord = likeRecordRepo
                .findByCommentIdAndUserId(commentId, SecurityUtils.getAuthenticatedUser().getId());
        if (likeRecord == null) {
            likeRecordRepo.save(LikeRecord.builder()
//                    .postId(comment.getPostId())
                                          .commentId(comment.getId())
                                          .userId(SecurityUtils.getAuthenticatedUser().getId())
                                          .dislike(dislike)
                                          .build());
            if (dislike) {
                comment.setDislikeNum(comment.getDislikeNum() + 1);
            } else {
                comment.setLikeNum(comment.getLikeNum() + 1);
                messageService.sendLikeMsg(SecurityUtils.getAuthenticatedUser().getId(), comment.getUserId(),
                        "comment", post, comment);
            }
        } else {
            if (dislike == likeRecord.isDislike()) {
                likeRecordRepo.delete(likeRecord);
                if (dislike) {
                    comment.setDislikeNum(Math.max(comment.getDislikeNum() - 1, 0));
                } else {
                    comment.setLikeNum(Math.max(comment.getLikeNum() - 1, 0));
                }
            } else {
                if (dislike) {
                    comment.setLikeNum(Math.max(comment.getLikeNum() - 1, 0));
                    comment.setDislikeNum(comment.getDislikeNum() + 1);
                } else {
                    comment.setDislikeNum(Math.max(comment.getDislikeNum() - 1, 0));
                    comment.setLikeNum(comment.getLikeNum() + 1);
                }
                likeRecord.setDislike(dislike);
                likeRecordRepo.save(likeRecord);
            }
        }
        commentRepo.save(comment);
    }

    public Page<CommentDTO> allDTO(PageQuery pageQuery) {
        Page<Comment> page = commentRepo.findAll(toSpecification(pageQuery, Comment.class), toPageRequest(pageQuery));
        Set<Long> userIds = page.stream().map(Comment::getUserId).collect(Collectors.toSet());
        List<User> userList = userIds.isEmpty() ? new ArrayList<>() : userRepo.findAllById(userIds);
        Set<Long> commentIds = page.stream().map(BaseEntity::getId).collect(Collectors.toSet());
        List<LikeRecord> likeRecords = new ArrayList<>();
        if (SecurityUtils.getAuthenticatedUser() != null) {
            if (!commentIds.isEmpty()) {
                likeRecords = likeRecordRepo
                        .findByUserIdAndCommentIdIn(SecurityUtils.getAuthenticatedUser().getId(), commentIds);
            }
        }

        List<LikeRecord> finalLikeRecords = likeRecords;
        return page.map(comment -> {
            CommentDTO commentDTO = new CommentDTO();
            BeanUtils.copyProperties(comment, commentDTO);
            userList.stream().filter(user -> user.getId().equals(comment.getUserId())).findAny().ifPresent(user -> {
                commentDTO.setAvatar(user.getAvatar());
                commentDTO.setNickname(user.getNickname());
            });
            finalLikeRecords.stream()
                            .filter(likeRecord -> comment.getId().equals(likeRecord.getCommentId()))
                            .findAny()
                            .ifPresent(likeRecord -> {
                                commentDTO.setLiked(!likeRecord.isDislike());
                                commentDTO.setDisliked(likeRecord.isDislike());
                            });
            return commentDTO;
        });
    }
}
