package com.liuyanzhao.sens.web.controller.admin;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.liuyanzhao.sens.config.annotation.SystemLog;
import com.liuyanzhao.sens.entity.Comment;
import com.liuyanzhao.sens.entity.Post;
import com.liuyanzhao.sens.entity.User;
import com.liuyanzhao.sens.exception.SensBusinessException;
import com.liuyanzhao.sens.model.dto.JsonResult;
import com.liuyanzhao.sens.model.dto.QueryCondition;
import com.liuyanzhao.sens.model.dto.SensConst;
import com.liuyanzhao.sens.model.enums.*;
import com.liuyanzhao.sens.service.CommentService;
import com.liuyanzhao.sens.service.MailService;
import com.liuyanzhao.sens.service.PostService;
import com.liuyanzhao.sens.utils.LocaleMessageUtil;
import com.liuyanzhao.sens.utils.OwoUtil;
import com.liuyanzhao.sens.utils.PageUtil;
import com.liuyanzhao.sens.web.controller.common.BaseController;
import cn.hutool.core.lang.Validator;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <pre>
 *     后台评论管理控制器
 * </pre>
 *
 * @author : saysky
 * @date : 2017/12/10
 */
@Slf4j
@Controller
@RequestMapping(value = "/admin/comment")
public class CommentController extends BaseController {

    @Autowired
    private CommentService commentService;

    @Autowired
    private MailService mailService;

    @Autowired
    private PostService postService;

    @Autowired
    private LocaleMessageUtil localeMessageUtil;

    /**
     * 评论人相关信息
     */
    public static final String COMMENT_AUTHOR_IP = "ip";
    public static final String COMMENT_AUTHOR = "author";
    public static final String COMMENT_EMAIL = "email";
    public static final String COMMENT_URL = "url";
    public static final String COMMENT_CONTENT = "content";


    /**
     * 渲染评论管理页面
     *
     * @param model      model
     * @param status     status 评论状态
     * @param pageNumber page 当前页码
     * @param pageSize   size 每页显示条数
     * @return 模板路径admin/admin_comment
     */
    @GetMapping
    public String comments(Model model,
                           @RequestParam(value = "status", defaultValue = "0") Integer status,
                           @RequestParam(value = "keywords", defaultValue = "") String keywords,
                           @RequestParam(value = "searchType", defaultValue = "") String searchType,
                           @RequestParam(value = "commentType", defaultValue = "-1") Integer commentType,
                           @RequestParam(value = "page", defaultValue = "1") Integer pageNumber,
                           @RequestParam(value = "size", defaultValue = "15") Integer pageSize,
                           @RequestParam(value = "sort", defaultValue = "createTime") String sort,
                           @RequestParam(value = "order", defaultValue = "desc") String order) {
        Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
        Long loginUserId = getLoginUserId();
        Comment condition = new Comment();
        condition.setAcceptUserId(loginUserId);
        condition.setCommentStatus(status);
        condition.setCommentType(commentType);
        if (!StringUtils.isBlank(keywords)) {
            if (COMMENT_CONTENT.equals(searchType)) {
                condition.setCommentContent(keywords);
            } else if (COMMENT_AUTHOR.equals(searchType)) {
                condition.setCommentAuthor(keywords);
            } else if (COMMENT_EMAIL.equals(searchType)) {
                condition.setCommentAuthorEmail(keywords);
            } else if (COMMENT_URL.equals(searchType)) {
                condition.setCommentAuthorUrl(keywords);
            } else if (COMMENT_AUTHOR_IP.equals(searchType)) {
                condition.setCommentAuthorIp(keywords);
            }
        }
        Page<Comment> comments = commentService.findAll(page, new QueryCondition<>(condition));

        List<Comment> commentList = comments.getRecords();
        commentList.forEach(comment -> comment.setPost(postService.get(comment.getPostId())));
        model.addAttribute("comments", commentList);
        model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
        model.addAttribute("publicCount", commentService.countByAcceptUserAndStatus(loginUserId, CommentStatusEnum.PUBLISHED.getCode()));
        model.addAttribute("checkCount", commentService.countByAcceptUserAndStatus(loginUserId, CommentStatusEnum.CHECKING.getCode()));
        model.addAttribute("trashCount", commentService.countByAcceptUserAndStatus(loginUserId, CommentStatusEnum.RECYCLE.getCode()));
        model.addAttribute("status", status);
        model.addAttribute("keywords", keywords);
        model.addAttribute("searchType", searchType);
        model.addAttribute("commentType", commentType);
        model.addAttribute("sort", sort);
        model.addAttribute("order", order);
        return "admin/admin_comment";
    }

    /**
     * 将评论改变为发布状态
     * 评论状态有两种:待审核1,回收站2
     * 对待审核转发布的,发邮件
     *
     * @param commentId 评论编号
     * @return 重定向到/admin/comment
     */
    @PostMapping(value = "/revert")
    @ResponseBody
    @SystemLog(description = "回滚评论", type = LogTypeEnum.OPERATION)
    public JsonResult moveToPublish(@RequestParam("id") Long commentId) {
        User loginUser = getLoginUser();
        //评论
        Comment comment = commentService.get(commentId);
        //检查权限
        basicCheck(comment);

        Post post = postService.get(comment.getPostId());
        Comment result = commentService.updateCommentStatus(commentId, CommentStatusEnum.PUBLISHED.getCode());
        //判断是否启用邮件服务
        new NoticeToAuthor(result, post, loginUser, comment.getCommentStatus()).start();

        return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), localeMessageUtil.getMessage("code.admin.common.operation-success"));
    }

    /**
     * 删除评论
     *
     * @param commentId commentId
     * @return string 重定向到/admin/comment
     */
    @PostMapping(value = "/delete")
    @ResponseBody
    @SystemLog(description = "删除评论", type = LogTypeEnum.OPERATION)
    public JsonResult moveToAway(@RequestParam("id") Long commentId) {
        //评论
        Comment comment = commentService.get(commentId);
        //检查权限
        basicCheck(comment);

        if (Objects.equals(comment.getCommentStatus(), CommentStatusEnum.RECYCLE.getCode())) {
            commentService.delete(commentId);
        } else {
            commentService.updateCommentStatus(commentId, CommentStatusEnum.RECYCLE.getCode());
        }
        return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-success"));
    }


    /**
     * 管理员回复评论,并通过评论
     *
     * @param commentId      被回复的评论
     * @param commentContent 回复的内容
     * @return 重定向到/admin/comment
     */
    @PostMapping(value = "/reply")
    @ResponseBody
    @SystemLog(description = "回复评论", type = LogTypeEnum.OPERATION)
    public JsonResult replyComment(@RequestParam("id") Long commentId,
                                   @RequestParam("commentContent") String commentContent,
                                   @RequestParam("userAgent") String userAgent,
                                   HttpServletRequest request) {
        //博主信息
        User loginUser = getLoginUser();
        //被回复的评论
        Comment lastComment = commentService.get(commentId);
        if (lastComment == null) {
            return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.comment-not-exist"));
        }

        Post post = postService.get(lastComment.getPostId());
        if (post == null) {
            return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.post-not-exist"));
        }
        //修改被回复的评论的状态
        if (Objects.equals(lastComment.getCommentStatus(), CommentStatusEnum.CHECKING.getCode())) {
            lastComment.setCommentStatus(CommentStatusEnum.PUBLISHED.getCode());
            commentService.insertOrUpdate(lastComment);
        }

        //保存评论
        Comment comment = new Comment();
        comment.setUserId(loginUser.getId());
        comment.setPostId(lastComment.getPostId());
        comment.setCommentAuthor(loginUser.getUserDisplayName());
        comment.setCommentAuthorEmail(loginUser.getUserEmail());
        comment.setCommentAuthorUrl(SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()));
        comment.setCommentAuthorIp(ServletUtil.getClientIP(request));
        comment.setCommentAuthorAvatar(loginUser.getUserAvatar());
        String lastContent = "<a href='#comment-id-" + lastComment.getId() + "'>@" + lastComment.getCommentAuthor() + "</a> ";
        comment.setCommentContent(lastContent + OwoUtil.markToImg(HtmlUtil.escape(commentContent)));
        comment.setCommentAgent(userAgent);
        comment.setCommentParent(commentId);
        comment.setCommentStatus(CommentStatusEnum.PUBLISHED.getCode());
        //判断是否是博主
        if (Objects.equals(loginUser.getId(), post.getUserId())) {
            comment.setIsAdmin(1);
        } else {
            comment.setIsAdmin(0);
        }
        comment.setAcceptUserId(lastComment.getUserId());
        comment.setPathTrace(lastComment.getPathTrace() + lastComment.getId() + "/");
        commentService.insertOrUpdate(comment);
        //邮件通知
        new EmailToAuthor(comment, lastComment, post, loginUser, commentContent).start();
        return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), localeMessageUtil.getMessage("code.admin.common.reply-success"));

    }

    /**
     * 批量删除
     *
     * @param ids 评论ID列表
     * @return
     */
    @DeleteMapping(value = "/batchDelete")
    @ResponseBody
    @SystemLog(description = "批量删除评论", type = LogTypeEnum.OPERATION)
    public JsonResult batchDelete(@RequestParam("ids") List<Long> ids) {
        Long loginUserId = getLoginUserId();
        //批量操作
        //1、防止恶意操作
        if (ids == null || ids.size() == 0 || ids.size() >= 100) {
            return new JsonResult(ResultCodeEnum.FAIL.getCode(), "参数不合法!");
        }
        //2、检查用户权限
        //文章作者才可以删除
        List<Comment> commentList = commentService.findByBatchIds(ids);
        for (Comment comment : commentList) {
            if (!Objects.equals(comment.getUserId(), loginUserId) && !Objects.equals(comment.getAcceptUserId(), loginUserId)) {
                return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.permission-denied"));
            }
        }
        //3、如果当前状态为回收站,则删除;否则,移到回收站
        for (Comment comment : commentList) {
            if (Objects.equals(comment.getCommentStatus(), PostStatusEnum.RECYCLE.getCode())) {
                commentService.delete(comment.getId());
            } else {
                comment.setCommentStatus(PostStatusEnum.RECYCLE.getCode());
                commentService.update(comment);
            }
        }
        return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-success"));
    }

    /**
     * 检查文章是否存在和用户是否有权限控制
     *
     * @param comment
     */
    private void basicCheck(Comment comment) {
        Long loginUserId = getLoginUserId();
        if (comment == null) {
            throw new SensBusinessException(localeMessageUtil.getMessage("code.admin.common.comment-not-exist"));
        }
        //文章
        Post post = postService.get(comment.getPostId());
        if (post == null) {
            throw new SensBusinessException(localeMessageUtil.getMessage("code.admin.common.post-not-exist"));
        }
        //检查权限,文章的作者和收到评论的可以删除
        if (!Objects.equals(post.getUserId(), loginUserId) && !Objects.equals(comment.getAcceptUserId(), loginUserId)) {
            throw new SensBusinessException(localeMessageUtil.getMessage("code.admin.common.permission-denied"));
        }
    }

    /**
     * 异步发送邮件回复给评论者
     */
    class EmailToAuthor extends Thread {

        private Comment comment;
        private Comment lastComment;
        private Post post;
        private User user;
        private String commentContent;

        private EmailToAuthor(Comment comment, Comment lastComment, Post post, User user, String commentContent) {
            this.comment = comment;
            this.lastComment = lastComment;
            this.post = post;
            this.user = user;
            this.commentContent = commentContent;
        }

        @Override
        public void run() {
            if (StringUtils.equals(SensConst.OPTIONS.get(BlogPropertiesEnum.SMTP_EMAIL_ENABLE.getProp()), TrueFalseEnum.TRUE.getValue()) && StringUtils.equals(SensConst.OPTIONS.get(BlogPropertiesEnum.COMMENT_REPLY_NOTICE.getProp()), TrueFalseEnum.TRUE.getValue())) {
                if (Validator.isEmail(lastComment.getCommentAuthorEmail())) {
                    Map<String, Object> map = new HashMap<>(8);
                    map.put("blogTitle", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()));
                    map.put("commentAuthor", lastComment.getCommentAuthor());
                    map.put("pageName", post.getPostTitle());
                    if (StringUtils.equals(post.getPostType(), PostTypeEnum.POST_TYPE_POST.getValue())) {
                        map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/article/" + post.getId() + "#comment-id-" + comment.getId());
                    } else if (StringUtils.equals(post.getPostType(), PostTypeEnum.POST_TYPE_NOTICE.getValue())) {
                        map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/notice/" + post.getId() + "#comment-id-" + comment.getId());
                    } else {
                        map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/p/" + post.getPostUrl() + "#comment-id-" + comment.getId());
                    }
                    map.put("commentContent", lastComment.getCommentContent());
                    map.put("replyAuthor", user.getUserDisplayName());
                    map.put("replyContent", commentContent);
                    map.put("blogUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()));
                    mailService.sendTemplateMail(
                            lastComment.getCommentAuthorEmail(), "您在" + SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()) + "的评论有了新回复", map, "common/mail_template/mail_reply.ftl");
                }
            }
        }
    }

    /**
     * 异步通知评论者审核通过
     */
    class NoticeToAuthor extends Thread {

        private Comment comment;
        private Post post;
        private User user;
        private Integer status;

        private NoticeToAuthor(Comment comment, Post post, User user, Integer status) {
            this.comment = comment;
            this.post = post;
            this.user = user;
            this.status = status;
        }

        @Override
        public void run() {
            if (StringUtils.equals(SensConst.OPTIONS.get(BlogPropertiesEnum.SMTP_EMAIL_ENABLE.getProp()), TrueFalseEnum.TRUE.getValue()) && StringUtils.equals(SensConst.OPTIONS.get(BlogPropertiesEnum.COMMENT_REPLY_NOTICE.getProp()), TrueFalseEnum.TRUE.getValue())) {
                try {
                    //待审核的评论变成已通过,发邮件
                    if (status == 1 && Validator.isEmail(comment.getCommentAuthorEmail())) {
                        Map<String, Object> map = new HashMap<>(6);
                        if (StringUtils.equals(post.getPostType(), PostTypeEnum.POST_TYPE_POST.getValue())) {
                            map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/article/" + post.getId() + "#comment-id-" + comment.getId());
                        } else if (StringUtils.equals(post.getPostType(), PostTypeEnum.POST_TYPE_NOTICE.getValue())) {
                            map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/notice/" + post.getId() + "#comment-id-" + comment.getId());
                        } else {
                            map.put("pageUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/p/" + post.getPostUrl() + "#comment-id-" + comment.getId());
                        }
                        map.put("pageName", post.getPostTitle());
                        map.put("commentContent", comment.getCommentContent());
                        map.put("blogUrl", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()));
                        map.put("blogTitle", SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()));
                        map.put("author", user.getUserDisplayName());
                        mailService.sendTemplateMail(
                                comment.getCommentAuthorEmail(),
                                "您在" + SensConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()) + "的评论已审核通过!", map, "common/mail_template/mail_passed.ftl");
                    }
                } catch (Exception e) {
                    log.error("邮件服务器未配置:{}", e.getMessage());
                }
            }
        }
    }
}