package dev.cheerfun.pixivic.biz.web.comment.service;

import dev.cheerfun.pixivic.biz.web.comment.dto.Like;
import dev.cheerfun.pixivic.biz.web.comment.exception.CommentException;
import dev.cheerfun.pixivic.biz.web.comment.mapper.CommentMapper;
import dev.cheerfun.pixivic.biz.web.comment.po.Comment;
import dev.cheerfun.pixivic.common.constant.AuthConstant;
import dev.cheerfun.pixivic.common.constant.RedisKeyConstant;
import dev.cheerfun.pixivic.common.context.AppContext;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author OysterQAQ
 * @version 1.0
 * @date 2019/12/09 20:38
 * @description CommentService
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CommentService {
    private final StringRedisTemplate stringRedisTemplate;
    private final CommentMapper commentMapper;

    @CacheEvict(value = "comments", key = "#comment.appType+#comment.appId")
    public void pushComment(Comment comment) {
        commentMapper.pushComment(comment);
        //
    }

    @Transactional(rollbackFor = Exception.class)
    public void likeComment(Like like, int userId) {
        Long add = stringRedisTemplate.opsForSet().add(RedisKeyConstant.LIKE_REDIS_PRE + userId, like.toString());
        if (add != null && add != 0L) {
            stringRedisTemplate.opsForHash().increment(RedisKeyConstant.LIKE_COUNT_MAP_REDIS_PRE, like.toString(), 1);
        } else {
            throw new CommentException(HttpStatus.BAD_REQUEST, "用户评论点赞关系请求错误");
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void cancelLikeComment(int userId, Like like) {
        Long remove = stringRedisTemplate.opsForSet().remove(RedisKeyConstant.LIKE_REDIS_PRE + userId, like.toString());
        if (remove != null && remove != 0L) {
            stringRedisTemplate.opsForHash().increment(RedisKeyConstant.LIKE_COUNT_MAP_REDIS_PRE, like.toString(), -1);
        } else {
            throw new CommentException(HttpStatus.BAD_REQUEST, "用户评论点赞关系请求错误");
        }
    }

    public List<Comment> pullComment(String appType, Integer appId, Integer page, Integer pageSize) {
        List<Comment> comments = pullComment(appType, appId);
        return comments.stream().skip(pageSize * (page - 1))
                .limit(pageSize).collect(Collectors.toList());
    }

    @Cacheable(value = "comments", key = "#appType+#appId")
    public List<Comment> pullComment(String appType, Integer appId) {
        List<Comment> comments = queryCommentList(appType, appId);
        if (comments.size() == 0) {
            return comments;
        }
        List<Comment> result = new ArrayList<>();
        Map<Integer, List<Comment>>[] mayByParentId = new Map[]{null};
        //拼接是否点赞
        List<Object> isLikedList;
        if (AppContext.get() != null && AppContext.get().get(AuthConstant.USER_ID) != null) {
            isLikedList = stringRedisTemplate.executePipelined((RedisCallback<String>) redisConnection -> {
                comments.forEach(e -> {
                    StringRedisConnection stringRedisConnection = (StringRedisConnection) redisConnection;
                    stringRedisConnection.sIsMember(RedisKeyConstant.LIKE_REDIS_PRE + AppContext.get().get(AuthConstant.USER_ID), String.valueOf(e.toStringForQueryLike()));
                });
                return null;
            });
        } else {
            isLikedList = comments.stream().map(e -> false).collect(Collectors.toList());
        }
        //顶级评论
        mayByParentId[0] = comments.stream().collect(Collectors.groupingBy(e -> {
            //顶级评论引用列表
            if (e.getParentId() == 0) {
                result.add(e);
            }
            return e.getParentId();
        }));

        int index = comments.size();
        for (int i = 0; i < index; i++) {
            Comment comment = comments.get(i);
            comment.setIsLike((Boolean) isLikedList.get(i));
            //拼成树形
            if (comment.getParentId() == 0) {
                comment.setSubCommentList(mayByParentId[0] != null ? mayByParentId[0].get(comment.getId()) : null);
            }
        }
        //最新消息逆序
        result.sort(Comparator.comparingInt(Comment::getId));
        return result;
    }

    public List<Comment> queryCommentList(String appType, Integer appId) {
        return commentMapper.pullComment(appType, appId);
    }
}