package com.luojia_channel.modules.post.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luojia_channel.common.domain.page.PageResponse;
import com.luojia_channel.common.exception.PostException;
import com.luojia_channel.common.utils.PageUtil;
import com.luojia_channel.common.utils.UserContext;
import com.luojia_channel.modules.post.dto.req.CommentPageQueryDTO;
import com.luojia_channel.modules.post.dto.req.CommentSaveDTO;
import com.luojia_channel.modules.post.dto.resp.CommentInfoDTO;
import com.luojia_channel.modules.post.dto.resp.PostBasicInfoDTO;
import com.luojia_channel.modules.post.entity.Comment;
import com.luojia_channel.modules.post.entity.Post;
import com.luojia_channel.modules.post.mapper.CommentMapper;
import com.luojia_channel.modules.post.service.CommentService;
import com.luojia_channel.modules.post.utils.ValidatePostUtil;
import com.luojia_channel.modules.user.entity.User;
import com.luojia_channel.modules.user.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    private final ValidatePostUtil validatePostUtil;
    private final CommentMapper commentMapper;
    private final UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveComment(CommentSaveDTO commentSaveDTO) {
        validatePostUtil.validateComment(commentSaveDTO);
        Comment comment = BeanUtil.copyProperties(commentSaveDTO, Comment.class);
        if(!save(comment)){
            throw new PostException("创建评论失败");
        }
        Long parentCommentId = commentSaveDTO.getParentCommentId();
        if(parentCommentId != null){
            LambdaUpdateWrapper<Comment> updateWrapper = Wrappers.lambdaUpdate(Comment.class)
                    .eq(Comment::getId, parentCommentId)
                    .setSql("reply_count = reply_count + 1");
            int update = commentMapper.update(null, updateWrapper);
            if(update  <= 0) {
                throw new PostException("回复评论失败");
            }
            Long topId = commentSaveDTO.getTopId();
            // 更新顶级评论回复数
            if(!parentCommentId.equals(topId)){
                updateWrapper = Wrappers.lambdaUpdate(Comment.class)
                        .eq(Comment::getId, topId)
                        .setSql("reply_count = reply_count + 1");
                update = commentMapper.update(null, updateWrapper);
                if(update  <= 0) {
                    throw new PostException("回复顶级评论失败");
                }
            }

            // TODO 消息通知

        }

    }

    @Override
    public void updateComment(CommentSaveDTO commentSaveDTO) {
        validatePostUtil.validateComment(commentSaveDTO);
        validatePostUtil.validateCommentOwnership(commentSaveDTO.getId());
        Comment comment = BeanUtil.copyProperties(commentSaveDTO, Comment.class);
        comment.setUpdateTime(LocalDateTime.now());
        if(!updateById(comment)){
            throw new PostException("更新评论失败");
        }
    }

    @Override
    public void deleteComment(Long id) {
        validatePostUtil.validateCommentOwnership(id);
        LambdaQueryWrapper<Comment> queryWrapper = Wrappers.lambdaQuery(Comment.class)
                .eq(Comment::getTopId, id);
        int delete = commentMapper.delete(queryWrapper);
        if(delete <= 0) {
            throw new PostException("删除评论失败");
        }
        // TODO 如果根评论删除，那么其他评论怎么办，目前做法是删除其下所有的子评论
    }

    // 分页查询一系列根评论
    @Override
    public PageResponse<CommentInfoDTO> getCommentsByPostId(CommentPageQueryDTO commentPageQueryDTO) {
        if(commentPageQueryDTO.getPostId() == null || commentPageQueryDTO.getPostId() < 0){
            throw new PostException("帖子id不合法");
        }
        LambdaQueryWrapper<Comment> queryWrapper = Wrappers.lambdaQuery(Comment.class)
                .eq(Comment::getPostId, commentPageQueryDTO.getPostId())
                .eq(Comment::getParentCommentId, 0L)
                .orderByDesc(Comment::getCreateTime);
        return getCommentInfoDTOPageResponse(commentPageQueryDTO, queryWrapper);
    }

    @Override
    public PageResponse<CommentInfoDTO> getReplyById(CommentPageQueryDTO commentPageQueryDTO) {
        if(commentPageQueryDTO.getCommentId() == null || commentPageQueryDTO.getCommentId() < 0){
            throw new PostException("评论id不合法");
        }
        LambdaQueryWrapper<Comment> queryWrapper = Wrappers.lambdaQuery(Comment.class)
                .eq(Comment::getTopId, commentPageQueryDTO.getCommentId())
                .orderByDesc(Comment::getCreateTime);
        return getCommentInfoDTOPageResponse(commentPageQueryDTO, queryWrapper);
    }

    private PageResponse<CommentInfoDTO> getCommentInfoDTOPageResponse(CommentPageQueryDTO commentPageQueryDTO, LambdaQueryWrapper<Comment> queryWrapper) {
        IPage<Comment> commentPage = commentMapper.selectPage(PageUtil.convert(commentPageQueryDTO), queryWrapper);
        List<Long> userIds = new ArrayList<>();
        commentPage.getRecords().forEach(comment -> {
            userIds.add(comment.getUserId());
        });
        List<User> users = userMapper.selectBatchIds(userIds);
        Map<Long, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, user -> user));
        return PageUtil.convert(commentPage, (comment) -> {
            CommentInfoDTO commentInfoDTO = BeanUtil.copyProperties(comment, CommentInfoDTO.class);
            User user = userMap.getOrDefault(comment.getUserId(), new User());
            commentInfoDTO.setUserAvatar(user.getAvatar());
            commentInfoDTO.setUserName(user.getUsername());
            return commentInfoDTO;
        });
    }

    private List<CommentInfoDTO> convertToDTO(List<Comment> commentList) {
        List<CommentInfoDTO> dtos = new ArrayList<>();
        for (Comment comment : commentList) {
            CommentInfoDTO dto = new CommentInfoDTO();
            BeanUtils.copyProperties(comment, dto);
            dtos.add(dto);
        }
        return dtos;
    }

    // 根据评论创建嵌套评论,目前没用到
    private List<CommentInfoDTO> buildNestedCommentList(List<Comment> comments) {
        Map<Long, CommentInfoDTO> map = new HashMap<>();
        List<CommentInfoDTO> rootComments = new ArrayList<>();
        for (Comment comment : comments) {
            CommentInfoDTO dto = new CommentInfoDTO();
            BeanUtils.copyProperties(comment, dto);
            map.put(comment.getId(), dto);
            if (comment.getParentCommentId() == null) {
                rootComments.add(dto);
            } else {
                CommentInfoDTO parentDto = map.get(comment.getParentCommentId());
                if (parentDto != null && parentDto.getCommentInfoDTOList() == null) {
                    parentDto.setCommentInfoDTOList(new ArrayList<>());
                }
                if (parentDto != null) {
                    parentDto.getCommentInfoDTOList().add(dto);
                }
            }
        }
        return rootComments;
    }
}
