package org.dromara.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.domain.communityNews.CommentIndex;
import org.dromara.domain.communityNews.CommentLikes;
import org.dromara.domain.communityNews.CommunityNews;
import org.dromara.domain.communityNews.bo.CommentLikesBo;
import org.dromara.domain.communityNews.vo.CommentInteractionVo;
import org.dromara.domain.communityNews.vo.CommentLikesVo;
import org.dromara.mapper.CommentIndexMapper;
import org.dromara.mapper.CommentLikesMapper;
import org.dromara.mapper.CommunityNewsMapper;
import org.dromara.service.ICommentLikesService;
import org.dromara.service.ICommunityNewsService;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static org.dromara.common.core.constant.Constants.*;

/**
 * 社区资讯点赞Service业务层处理
 *
 * @author boman
 * @date 2025-04-11
 */
@RequiredArgsConstructor
@Service
public class CommentLikesServiceImpl implements ICommentLikesService {

    private final CommentLikesMapper baseMapper;
    private final CommunityNewsMapper communityNewsMapper;
    private final ICommunityNewsService communityNewsService;
    private final CommentIndexMapper commentIndexMapper;
    /**
     * 查询社区资讯点赞
     *
     * @param likesId 主键
     * @return 社区资讯点赞
     */
    @Override
    public CommentLikesVo queryById(Long likesId){
        return baseMapper.selectVoById(likesId);
    }

    /**
     * 分页查询社区资讯点赞列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 社区资讯点赞分页列表
     */
    @Override
    public TableDataInfo<CommentLikesVo> queryPageList(CommentLikesBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<CommentLikes> lqw = buildQueryWrapper(bo);
        Page<CommentLikesVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的社区资讯点赞列表
     *
     * @param bo 查询条件
     * @return 社区资讯点赞列表
     */
    @Override
    public List<CommentLikesVo> queryList(CommentLikesBo bo) {
        LambdaQueryWrapper<CommentLikes> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<CommentLikes> buildQueryWrapper(CommentLikesBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<CommentLikes> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(CommentLikes::getLikesId);
        lqw.eq(bo.getTargetId() != null, CommentLikes::getTargetId, bo.getTargetId());
        lqw.eq(StringUtils.isNotBlank(bo.getTargetType()), CommentLikes::getTargetType, bo.getTargetType());
        lqw.eq(StringUtils.isNotBlank(bo.getTargetTitle()), CommentLikes::getTargetTitle, bo.getTargetTitle());
        lqw.eq(bo.getUserId() != null, CommentLikes::getUserId, bo.getUserId());
        lqw.like(StringUtils.isNotBlank(bo.getNickName()), CommentLikes::getNickName, bo.getNickName());
        lqw.eq(StringUtils.isNotBlank(bo.getAvatar()), CommentLikes::getAvatar, bo.getAvatar());
        return lqw;
    }

    /**
     * 新增社区资讯点赞
     *
     * @param bo 社区资讯点赞
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(CommentLikesBo bo) {
        CommentLikes add = MapstructUtils.convert(bo, CommentLikes.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setLikesId(add.getLikesId());
        }
        return flag;
    }

    /**
     * 修改社区资讯点赞
     *
     * @param bo 社区资讯点赞
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(CommentLikesBo bo) {
        CommentLikes update = MapstructUtils.convert(bo, CommentLikes.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(CommentLikes entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除社区资讯点赞信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 进行点赞操作
     * //点赞数据存储到redis,设置redis过期key监听，继承onMessage类把数据更新到数据库中
     * //点赞目标id + 目标类型 + 用户信息组装成CommentLikes写入数据库
     * //文章需要统计点赞的数量和当前登录用户是否已经点赞
     * //点赞之前应该去查一遍该文章或者回复的点赞key,value应该是点赞的人员id判断用户是否已经点赞过了，点赞过了就取消，没点赞过就加入
     * //还需要同步到数据库，需要一个完整的点赞key 一个设置过期时间的监听key
     */
    @Override
    public R<Void> giveTheThumbs(CommentLikes commentLikes) {
        String targetType = commentLikes.getTargetType();
        Long targetId = commentLikes.getTargetId();
        Long userId = commentLikes.getUserId();
        //保存点赞信息
        //根据点赞目标id' 点赞目标类型（1：资讯 2：回复） 用户id查询是否已经点赞过
        CommentLikes commentLikesOld = baseMapper.selectCommentLikes(commentLikes);
        if (commentLikesOld != null) {
            commentLikesOld.setDelFlag("Y");
            baseMapper.updateById(commentLikesOld);
        } else {
            baseMapper.insert(commentLikes);
        }
        if (StringUtils.isNotBlank(targetType)) {
            //设置未读点赞互动的方法
            setCommentInteractionVo(commentLikes);
            if (ONE.equals(targetType)) {
                // 社区资讯文章点赞的人员集合的key key = LIKE_ONE:{targetId} value = [userId,userId];
                String likeOneKey = ONE_LIKE + targetId;
                //社区资讯文章点赞的数量数据库同步的key
                String likeOneCountTimeKey = ONE_LIKE_COUNT_TIME + targetId;
                //文章永久点赞的数量key
                String likeOneCountKey = ONE_LIKE_COUNT + targetId;
                //先去查看key对应的value集合 value = 点赞人员的id集合
                List<Long> userIdListValue = RedisUtils.getCacheList(likeOneKey);
                //该用户点赞文章的key
                String myLikeOneKey = ONE_MY_LIKE + userId;
                List<Long> communityIdList = RedisUtils.getCacheList(myLikeOneKey);
                if (userIdListValue != null && userIdListValue.size() > 0) {
                    //说明该文章被点过赞
                    //判断该用户是否点过赞
                    if (userIdListValue.contains(userId)) {
                        //进行取消点赞
                        return unLike(commentLikes);
                    } else {
                        //新增点赞信息
                        return isLike(commentLikes);
                    }
                } else {
                    //该文章没有被点过赞直接新增
                    userIdListValue = new ArrayList<>();
                    userIdListValue.add(userId);
                    RedisUtils.setCacheList(likeOneKey, userIdListValue);
                    //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间  key=like_one_count_time:{文章id}#{数量}
                    RedisUtils.setCacheObject(likeOneCountTimeKey + "#" + 1, 1,  Duration.ofMinutes(1));
                    //给该用户点赞文章的key添加值
                    communityIdList.add(targetId);
                    RedisUtils.setCacheList(myLikeOneKey, communityIdList);
                    //给该文章永久点赞数量的key添加值
                    RedisUtils.setCacheObject(likeOneCountKey, 1);
                    return R.ok();
                }
            } else {
                //对回复进行点赞
                // 社区资讯回复点赞的人员集合的key key = LIKE_ONE:{targetId} value = [userId,userId];
                String likeTwoKey = TWO_LIKE + targetId;
                //社区资讯回复点赞的数量数据库同步的key
                String likeTwoCountTimeKey = TWO_LIKE_COUNT_TIME + targetId;
                //回复永久点赞的数量key
                String likeTwoCountKey = TWO_LIKE_COUNT + targetId;
                //先去查看key对应的value集合 value = 点赞人员的id集合
                List<Long> userIdListValue = RedisUtils.getCacheList(likeTwoKey);
                //该用户点赞回复的key
                String myLikeTwoKey = TWO_MY_LIKE + userId;
                List<Long> communityIdList = RedisUtils.getCacheList(myLikeTwoKey);
                if (userIdListValue != null && userIdListValue.size() > 0) {
                    //说明该回复被点过赞
                    //判断该用户是否点过赞
                    if (userIdListValue.contains(userId)) {
                        //进行取消点赞
                        return unLike(commentLikes);
                    } else {
                        //新增点赞信息
                        return isLike(commentLikes);
                    }
                } else {
                    //该回复没有被点过赞直接新增
                    userIdListValue = new ArrayList<>();
                    userIdListValue.add(userId);
                    RedisUtils.setCacheList(likeTwoKey, userIdListValue);
                    //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
                    RedisUtils.setCacheObject(likeTwoCountTimeKey + "#" + 1, 1, Duration.ofMinutes(1));
                    //给该用户点赞回复的key添加值
                    communityIdList.add(targetId);
                    RedisUtils.setCacheList(myLikeTwoKey, communityIdList);
                    //给该回复永久点赞数量的key添加值
                    RedisUtils.setCacheObject(likeTwoCountKey, 1);
                    return R.ok();
                }
            }
        }
        return R.fail("点赞失败");
    }

    /**
     * 用户点赞，但不是第一次点赞的方法
     *
     * @param commentLikes
     * @return
     */
    public R<Void> isLike(CommentLikes commentLikes) {
        String targetType = commentLikes.getTargetType();
        Long targetId = commentLikes.getTargetId();
        Long userId = commentLikes.getUserId();
        if (ONE.equals(targetType)) {
            // 社区资讯文章点赞的人员集合的key key = ONE_LIKE:{targetId} value = [userId,userId];
            String likeOneKey = ONE_LIKE + targetId;
            //社区资讯文章点赞的数量数据库同步的key
            String likeOneCountTimeKey = ONE_LIKE_COUNT + targetId;
            //文章永久点赞的数量key
            String likeOneCountKey = ONE_LIKE_COUNT + targetId;
            //先去查看key对应的value集合 value = 点赞人员的id集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeOneKey);
            //该用户点赞文章的key
            String myLikeOneKey = ONE_MY_LIKE + userId;
            List<Long> communityIdList = RedisUtils.getCacheList(myLikeOneKey);
            //新增点赞信息
            // 新增社区资讯文章点赞的人员集合
            userIdListValue.add(userId);
            RedisUtils.setCacheList(likeOneKey, userIdListValue);
            //新增该用户点赞文章
            communityIdList.add(targetId);
            RedisUtils.setCacheList(myLikeOneKey, communityIdList);
            //新增文章永久点赞数量的key更新值
            Integer likeOneCount = RedisUtils.getCacheObject(likeOneCountKey);
            likeOneCount = likeOneCount + 1;
            RedisUtils.setCacheObject(likeOneCountKey, likeOneCount);
            //新增数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
            RedisUtils.setCacheObject(likeOneCountTimeKey + "#" + likeOneCount, likeOneCount, Duration.ofMinutes(1));
            return R.ok();
        } else {
            // 社区资讯文章回复的人员集合的key key = TWO_LIKE:{targetId} value = [userId,userId];
            String likeTwoKey = TWO_LIKE + targetId;
            //社区资讯文章回复的数量数据库同步的key
            String likeTwoCountTimeKey = TWO_LIKE_COUNT_TIME + targetId;
            //文章永久回复的数量key
            String likeTwoCountKey = TWO_LIKE_COUNT + targetId;
            //先去查看key对应的value集合 value = 点赞人员的id集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeTwoKey);
            //该用户点赞回复的key
            String myLikeTwoKey = TWO_MY_LIKE + userId;
            List<Long> communityIdList = RedisUtils.getCacheList(myLikeTwoKey);
            //新增点赞信息
            // 新增社区资讯回复点赞的人员集合
            userIdListValue.add(userId);
            RedisUtils.setCacheList(likeTwoKey, userIdListValue);
            //新增该用户点赞回复
            communityIdList.add(targetId);
            RedisUtils.setCacheList(myLikeTwoKey, communityIdList);
            //新增回复永久点赞数量的key更新值
            Integer likeTwoCount = RedisUtils.getCacheObject(likeTwoCountKey);
            likeTwoCount = likeTwoCount + 1;
            RedisUtils.setCacheObject(likeTwoCountKey, likeTwoCount);
            //新增数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
            RedisUtils.setCacheObject(likeTwoCountTimeKey + "#" + likeTwoCount, likeTwoCount, Duration.ofMinutes(1));
            return R.ok();
        }
    }
    /**
     * 用户取消点赞
     *
     * @param commentLikes
     * @return
     */
    public R<Void> unLike(CommentLikes commentLikes) {
        //用户点过赞 进行取消点赞
        String targetType = commentLikes.getTargetType();
        Long targetId = commentLikes.getTargetId();
        Long userId = commentLikes.getUserId();
        if (ONE.equals(targetType)) {
            //文章永久点赞的数量key
            String likeOneCountKey = ONE_LIKE_COUNT + targetId;
            //社区资讯文章点赞的数量数据库同步的key
            String likeOneCountTimeKey = ONE_LIKE_COUNT_TIME + targetId;
            //-------------------------删除 社区资讯文章点赞的人员集合value中的userId
            //  key = ONE_LIKE:{targetId} value = [userId,userId];
            String likeOneKey = ONE_LIKE + targetId;
            //先去查看key对应的value集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeOneKey);
            userIdListValue.remove(userId);
            if (userIdListValue.size() == 0) {
                RedisUtils.deleteObject(likeOneKey);
            } else {
                RedisUtils.deleteObject(likeOneKey);
                // 社区资讯文章点赞的人员集合中删除该用户
                RedisUtils.setCacheList(likeOneKey, userIdListValue);
            }

            //-------------------------删除 该用户点赞文章value中的文章id
            String myLikeOneKey = ONE_MY_LIKE + userId;
            List<Long> communityIdListValue = RedisUtils.getCacheList(myLikeOneKey);
            communityIdListValue.remove(targetId);
            if (communityIdListValue.size() == 0) {
                RedisUtils.deleteObject(myLikeOneKey);
            } else {
                RedisUtils.deleteObject(myLikeOneKey);
                RedisUtils.setCacheList(myLikeOneKey, communityIdListValue);
            }
            // ---------点赞数量操作------------------
            //先获取永久点赞数量的值
            Integer likeCount = RedisUtils.getCacheObject(likeOneCountKey);
            //更新永久点赞数量
            RedisUtils.setCacheObject(likeOneCountKey, Math.max(likeCount - 1,0));
            //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
            RedisUtils.setCacheObject(likeOneCountTimeKey + "#" + likeCount, likeCount, Duration.ofMinutes(1));
            return R.ok();
        } else {
            //评论的删除
            //评论永久点赞的数量key
            String likeTwoCountKey = TWO_LIKE_COUNT + targetId;
            //社区资讯评论点赞的数量数据库同步的key
            String likeTwoCountTimeKey = TWO_LIKE_COUNT_TIME + targetId;
            //-------------------------删除 社区资讯文章评论的人员集合value中的userId
            //  key = LIKE_ONE:{targetId} value = [userId,userId];
            String likeTwoKey = TWO_LIKE + targetId;
            //先去查看key对应的value集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeTwoKey);
            userIdListValue.remove(userId);
            if (userIdListValue.size() == 0) {
                RedisUtils.deleteObject(likeTwoKey);
            } else {
                RedisUtils.deleteObject(likeTwoKey);
                // 社区资讯文章评论的人员集合中删除该用户
                RedisUtils.setCacheList(likeTwoKey, userIdListValue);
            }
            //-------------------------删除 该用户点赞评论value中的文章id
            String myLikeTwoKey = TWO_MY_LIKE + userId;
            List<Long> communityIdListValue = RedisUtils.getCacheList(myLikeTwoKey);
            communityIdListValue.remove(targetId);
            if (communityIdListValue.size() == 0) {
                RedisUtils.deleteObject(myLikeTwoKey);
            } else {
                RedisUtils.deleteObject(myLikeTwoKey);
                RedisUtils.setCacheList(myLikeTwoKey, communityIdListValue);
            }
            // ---------点赞数量操作------------------
            //先获取永久点赞数量的值
            Integer likeCount = RedisUtils.getCacheObject(likeTwoCountKey);
            //更新永久点赞数量
            RedisUtils.setCacheObject(likeTwoCountKey, Math.max(likeCount - 1,0));
            //给数据库同步数据在 redis中增加一个有过期时间的key 1分钟过期时间
            RedisUtils.setCacheObject(likeTwoCountTimeKey + "#" + likeCount, likeCount, Duration.ofMinutes(1));
            return R.ok();
        }
    }

    /**
     * 设置未读点赞互动的方法
     *
     * @param commentLikes
     */
    public void setCommentInteractionVo(CommentLikes commentLikes) {
        Long userId = commentLikes.getUserId();
        Long targetId = commentLikes.getTargetId();
        //------设置未读收藏，在redis中新增一条未读的互动--------
        CommentInteractionVo commentInteractionVo = new CommentInteractionVo();
        //先判断是资讯点赞还是回复点赞
        String targetType = commentLikes.getTargetType();
        commentInteractionVo.setTargetType(TWO);
        commentInteractionVo.setType(ONE);
        if (ONE.equals(targetType)) {
            //说明是资讯点赞
            //根据targetId获取该资讯的内容
            CommunityNews communityNews = communityNewsMapper.selectById(targetId);
            commentInteractionVo.setTargetUserId(communityNews.getUserId());
            //-------------判断是点赞还是取消点赞-------------------
            // 社区资讯文章点赞的人员集合的key key = LIKE_ONE:{targetId} value = [userId,userId];
            String likeOneKey = ONE_LIKE + targetId;
            //先去查看key对应的value集合 value = 点赞人员的id集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeOneKey);
            if (userIdListValue != null && userIdListValue.size() > 0) {
                //说明该文章被点过赞
                //判断该用户是否点过赞
                if (userIdListValue.contains(userId)) {
                    //设置取消点赞
                    commentInteractionVo.setType(TWO);
                }
            }
            //-------------判断是点赞还是取消点赞结束-------------------
        } else if (TWO.equals(targetType)) {
            //说明是回复点赞
            commentInteractionVo.setTargetType(FIV);
            //根据targetId获取该评论的内容
            CommentIndex commentIndex = commentIndexMapper.selectById(targetId);
            commentInteractionVo.setTargetUserId(commentIndex.getUserId());
            commentInteractionVo.setCommunityId(commentLikes.getCommunityId());

            //-------------判断是点赞还是取消点赞-------------------
            // 社区资讯回复点赞的人员集合的key key = LIKE_ONE:{targetId} value = [userId,userId];
            String likeTwoKey = TWO_LIKE + targetId;
            //先去查看key对应的value集合 value = 点赞人员的id集合
            List<Long> userIdListValue = RedisUtils.getCacheList(likeTwoKey);
            if (userIdListValue != null && userIdListValue.size() > 0) {
                //说明该回复被点过赞
                //判断该用户是否点过赞
                if (userIdListValue.contains(userId)) {
                    //设置取消点赞
                    commentInteractionVo.setType(TWO);
                }
            }
            //-------------判断是点赞还是取消点赞-------------------
        }
        commentInteractionVo.setTargetTitle(commentLikes.getTargetTitle());
        commentInteractionVo.setUserId(commentLikes.getUserId());
        commentInteractionVo.setAvatar(commentLikes.getAvatar());
        commentInteractionVo.setNickName(commentLikes.getNickName());
        commentInteractionVo.setCreateTime(DateUtils.getNowDate());
        commentInteractionVo.setTargetId(commentLikes.getTargetId());
        communityNewsService.setCommentInteraction(commentInteractionVo);
        //----------------------设置未读互动完成--------
    }
}
