package me.qwq.doghouse.validator;

import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import me.qwq.doghouse.entity.Comment;
import me.qwq.doghouse.entity.config.CommentConfig;
import me.qwq.doghouse.entity.config.MailConfig;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.enums.CommentAction;
import me.qwq.doghouse.enums.CommentStatusEnum;
import me.qwq.doghouse.enums.PostStatusEnum;
import me.qwq.doghouse.pojo.bo.PostPassJar;
import me.qwq.doghouse.service.CommentService;
import me.qwq.doghouse.service.IpService;
import me.qwq.doghouse.service.MailService;
import me.qwq.doghouse.service.post.PostService;
import me.qwq.doghouse.util.SessionUtils;

@Component
public class CommentValidator implements IValidator, ConstraintValidator<CommentValid, Comment> {

    public static final String AUTHOR_CANNOT_BE_EMPTY = "Author cannot be empty/名称不允许为空";
    public static final String AUTHOR_LENGTH_OVERFLOW = "Author length overflow/名称过长";
    public static final String CANNOT_BE_EDITED_MAIL_SENT = "Cannot be edited because notification mail for parent comment is sent/对父评论的通知邮件已发出，已不允许被编辑";
    public static final String CANNOT_BE_EDITED_SUBCOMMENT = "Cannot be edited because sub comments exist/包含子评论，已不允许被编辑";
    public static final String CONTENT_CANNOT_BE_EMPTY = "Content cannot be empty/评论内容不允许为空";
    public static final String CONTENT_LENGTH_MISMATCH = "Content length mismatch/评论过长或过短";
    public static final String EMAIL_CANNOT_BE_EMPTY = "Email cannot be empty/邮箱地址不允许为空";
    public static final String EMAIL_HAS_BEEN_BANNED = "Your email has been banned/您的 Email 地址已被禁言";
    public static final String EMAIL_INVALID = "Email is invaild/邮箱地址非法";
    public static final String EMAIL_LENGTH_OVERFLOW = "Email length overflow/邮箱地址过长";
    public static final String INVALID_REQUEST = "Invalid request/非法请求";
    public static final String INTERNAL_ERROR = "Internal error/内部错误";
    public static final String IP_HAS_BEEN_BANNED = "Your IP has been banned/您的 IP 地址已被禁言";
    public static final String REACH_MAX_LEVEL = "Reach max reply level, please return to the allowed level to reply/达到允许的最大回复层级, 请退回允许的层级进行回复";
    public static final String REPLY_CANNOT_BE_EMPTY = "Reply cannot be empty/评论不允许为空";
    public static final String SUB_REPLY_REACH_LIMIT = "Sub comment level reaches limit/子评论层级达到限制";
    public static final String TRIGGER_FILTER_RULE = "Filter rules triggered/触发了评论规则，评论失败";
    public static final String TRIGGER_PROHIBITED = "Contains one or more prohibited word(s), your IP has been recorded/包含违禁词, 您的 IP 已被记录";
    public static final String TRIGGER_SPAM = "Contains one or more spam word(s), your IP has been recorded/触发垃圾审核规则, 您的 IP 已被记录";
    public static final String URL_INVALID = "Url is invaild/网站地址非法";
    public static final String URL_LENGTH_OVERFLOW = "Url length overflow/网站地址过长";
    
    @Autowired
    PostService postService;

    @Autowired
    CommentService commentService;

    @Autowired
    MailService mailService;

    @Autowired
    CommentConfig commentConfig;

    @Autowired
    MailConfig mailConfig;
    
    @Autowired
    IpService ipService;
    
    @Autowired
    HttpServletRequest request;
    
    
    @Override
    public boolean isValid(Comment value, ConstraintValidatorContext context) {
        
        if (value == null) return false;
        HttpSession session = request.getSession(false);
        if (Objects.isNull(session)) return invalid(context, "Error occured, please refresh the page and retry.");
        if (!(value instanceof Comment comment)) return false;
        
        Boolean logined = SessionUtils.isLogin(session);
        Long postId = comment.getPostId();
        String postPageName = comment.getPostPageName();
        
        if (Objects.isNull(postId) && StringUtils.isBlank(postPageName)) {
            return invalid(context, INVALID_REQUEST);
        }
        
        Post post = postService.getOne(
                new LambdaQueryWrapper<Post>()
                .eq(!logined, Post::getPostStatus,
                        PostStatusEnum.RELEASED)
                // 是哪种页面，如何定位
                .and(!Objects.isNull(postId), i -> i.eq(Post::getPostId, postId))
                .and(!StringUtils.isBlank(postPageName), i -> i.eq(Post::getPostPageName, postPageName))
                .last("LIMIT 1")
                );
        
        if (post == null || !post.getEnableComment() && !logined) {
            // Post 不存在或不允许评论
            return invalid(context, INVALID_REQUEST);
        }
        if (!PostPassJar.validFromSession(session, post)) {
            // 未登录且文章密码校验不通过（在有密码的情况下）
            return invalid(context, INVALID_REQUEST);
        }
        
        comment.setPostId(post.getPostId());
        
        if (Objects.isNull(comment.getId())) {
            // 新增评论
            if (Objects.isNull(comment.getReplyTo())) {
                comment.setReplyTo(-1L);
            }
            else {
                Comment replyToComment = commentService.getById(comment.getReplyTo());
                if (!replyToComment.getPostId().equals(post.getPostId())) {
                    // 回复的评论所属 PostId 与当前提交的 PostId 不一致
                    return invalid(context, INVALID_REQUEST);
                }
                Integer parentLevel = replyToComment.getLevel();
                if (commentConfig.getMaxLevel() >= 0 && parentLevel >= commentConfig.getMaxLevel()) {
                    // 评论达到最大层级
                    return invalid(context, REACH_MAX_LEVEL);
                }
            }
        }
        else {
            // 编辑评论
            Comment existComment = commentService.getById(comment.getId());
            if (!logined) {
                // 未登录则收到严格审查
                if (mailConfig.isMailOn() && !mailService.clearTaskDelay(existComment) && existComment.isMailSent()) {
                    return invalid(context, CANNOT_BE_EDITED_MAIL_SENT);
                }
                String msg = null;
                if (!SessionUtils.containsCommentId(request, comment.getId())) {
                    // 没权限编辑
                    msg = INVALID_REQUEST;
                }
                commentService.getFullRelativeComment(existComment, 1);
                if (!CollectionUtils.isEmpty(existComment.getSubComments())) {
                    // 有子评论了
                    msg = CANNOT_BE_EDITED_SUBCOMMENT;
                }
                if (msg != null) {
                    // 重新设置 Delay
                    mailService.addOrUpdateSendQueue(existComment);
                    return invalid(context, msg);
                }
            }
            // 被编辑的评论需要从存在评论内加入不允许为空的项
            comment.setReplyTo(existComment.getReplyTo());
            comment.setCreateTime(existComment.getCreateTime());
            comment.setLevel(existComment.getLevel());
            comment.setReplyTo(existComment.getReplyTo());
        }
        
        String ip = ipService.getClientIp(request);
        comment.setIp(ip);
        
        if (StringUtils.isNotBlank(comment.getUrl())) {
            String url = comment.getUrl().trim().toLowerCase();
            if(!(url.startsWith("http:") || url.startsWith("https:"))) {
                comment.setUrl("http://" + comment.getUrl());
            }
        }
        
        comment.setAgent(request.getHeader("User-Agent"));
        comment.setCommentStatus(CommentStatusEnum.RELEASED);
        comment.setMarkdown(commentConfig.isMarkdownOn() && comment.isMarkdown());
        comment.setSubscribeReply(mailConfig.isMailOn() && comment.isSubscribeReply());
        comment.setMailSent(false);
        
        CommentAction action = commentConfig.filter(comment);
        
        if (action == CommentAction.FAIL) {
            return invalid(context, TRIGGER_FILTER_RULE);
        }
        if (action != CommentAction.NONE) {
            commentConfig.saveOrUpdate();
        }
        return true;
    }

}
