package me.qwq.doghouse.entity.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;

import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.annotation.ConfigInfo;
import me.qwq.doghouse.constants.UsefulRegex;
import me.qwq.doghouse.entity.Comment;
import me.qwq.doghouse.enums.CommentAction;
import me.qwq.doghouse.enums.CommentActionAfter;
import me.qwq.doghouse.enums.CommentStatusEnum;
import me.qwq.doghouse.interfaces.IConfig;
import me.qwq.doghouse.util.MarkDownUtils;

/**
 * 评论设置
 * @author Doghole
 *
 */
@SuppressWarnings("serial")
@Data
@Accessors(chain=true)
@ConfigInfo(field="comment", name="评论设置", initDefault = true)
@Slf4j
public class CommentConfig implements Serializable, IConfig<CommentConfig> {
    
    /**
     * 默认构造器
     */
    public CommentConfig() {
        this.markdownOn = false;
        this.ruleOn = true;
        this.maxLevel = 6;
        this.blockEmailAction = CommentAction.NONE;
        this.blockEmailActionAfter = CommentActionAfter.NONE;
        this.blockIpAction = CommentAction.NONE;
        this.blockIpActionAfter = CommentActionAfter.NONE;
        this.nonChineseAction = CommentAction.NONE;
        this.nonChineseActionAfter = CommentActionAfter.NONE;
        this.blockWordAction = CommentAction.NONE;
        this.blockWordActionAfter = CommentActionAfter.NONE;
        this.sensitiveWordAction = CommentAction.NONE;
        this.sensitiveWordActionAfter = CommentActionAfter.NONE;
        this.htmlWaitingOn = false;
    }
    
    /**
     * 是否支持 Markdown
     */
    private boolean markdownOn;
    
    /**
     * 规则是否开启
     */
    private Boolean ruleOn;
    
    /**
     * 最大回复层级，0 则不限层级
     */
    private Integer maxLevel;
    
    /**
     * 封禁 IP 列表
     */
    @JsonIgnore
    private List<String> blockIpList;
    
    /**
     * 增加 IP 到 Block IP 列表
     * @param ip
     * @return
     */
    public CommentConfig addBlockIp(String ip) {
        if (StringUtils.isBlank(ip)) {
            return this;
        }
        if (blockIpList == null) {
            blockIpList = new ArrayList<>();
        }
        ip = ip.trim().toLowerCase();
        if (!blockIpList.contains(ip)) {
            blockIpList.add(ip);
        }
        return this;
    }
    
    /**
     * 从 IP Block 列表移除指定 IP
     * @param ip
     * @return
     */
    public CommentConfig removeBlockIp(String ip) {
        if (blockIpList == null || blockIpList.size() == 0 || StringUtils.isBlank(ip)) {
            return this;
        }
        ip = ip.trim().toLowerCase();
        blockIpList.remove(ip.trim());
        return this;
    }
    
    /**
     * 封禁 IP 列表转换为换行符分隔的文本，一般用于前台显示，下同
     * @return
     */
    public String getBlockIpListText() {
        if (CollectionUtils.isEmpty(blockIpList)) {
            return "";
        }
        return String.join("\r\n", blockIpList);
    }
    
    /**
     * 设置封禁 IP 列表转换为换行符分隔的文本，一般用于接收前台数据后封装，下同
     * @return
     */
    public CommentConfig setBlockIpListText(String text) {
        blockIpList = new ArrayList<>(Arrays.asList(text.split("\r\n")));
        return this;
    }
    
    /**
     * 对封禁 IP 的动作
     */
    private CommentAction blockIpAction;
    
    /**
     * 触发封禁 IP 动作为：SPAM/FAIL 后的进一步动作
     */
    private CommentActionAfter blockIpActionAfter;
    
    @JsonIgnore
    private List<String> blockEmailList;

    public String getBlockEmailListText() {
        if (CollectionUtils.isEmpty(blockEmailList)) {
            return "";
        }
        return String.join("\r\n", blockEmailList);
    }
    
    public CommentConfig setBlockEmailListText(String text) {
        blockEmailList = new ArrayList<>(Arrays.asList(text.split("\r\n")));
        return this;
    }
    /**
     * 增加 email 到 Block Email 列表
     * @param email
     * @return
     */
    public CommentConfig addBlockEmail(String email) {
        if (StringUtils.isBlank(email)) {
            return this;
        }
        if (blockEmailList == null) {
            blockEmailList = new ArrayList<>();
        }
        email = "^" + email.trim().toLowerCase().replace(".", "\\.").replace("-", "\\-") + "$";
        if (!blockEmailList.contains(email)) {
            blockEmailList.add(email);
        }
        return this;
    }
    
    /**
     * 从 IP Block 列表移除指定 IP
     * @param ip
     * @return
     */
    public CommentConfig removeBlockEmail(String email) {
        if (blockEmailList == null || blockEmailList.size() == 0 || StringUtils.isBlank(email)) {
            return this;
        }
        email = "^" + email.trim().toLowerCase().replace(".", "\\.").replace("-", "\\-") + "$";
        blockEmailList.remove(email);
        return this;
    }
    
    private CommentAction blockEmailAction;
    
    private CommentActionAfter blockEmailActionAfter;
    

    
    private CommentAction nonChineseAction;
    
    private CommentActionAfter nonChineseActionAfter;
    
    @JsonIgnore
    private List<String> blockWordList;

    public String getBlockWordListText() {
        if (CollectionUtils.isEmpty(blockWordList)) {
            return "";
        }
        return String.join("\r\n", blockWordList);
    }
    
    public CommentConfig setBlockWordListText(String text) {
        blockWordList = new ArrayList<>(Arrays.asList(text.split("\r\n")));
        return this;
    }
    
    private CommentAction blockWordAction;
    
    private CommentActionAfter blockWordActionAfter;

    @JsonIgnore
    private List<String> sensitiveWordList;
    
    public String getSensitiveWordListText() {
        if (CollectionUtils.isEmpty(sensitiveWordList)) {
            return "";
        }
        return String.join("\r\n", sensitiveWordList);
    }
    
    public CommentConfig setSensitiveWordListText(String text) {
        sensitiveWordList = new ArrayList<>(Arrays.asList(text.split("\r\n")));
        return this;
    }
    
    private CommentAction sensitiveWordAction;
    
    private CommentActionAfter sensitiveWordActionAfter;
    
    private Boolean htmlWaitingOn;
    
    public CommentAction filter(Comment comment) {
        if (!ruleOn) {
            return CommentAction.NONE;
        }
        // IP Filter, support IPv6
        if (!CollectionUtils.isEmpty(blockIpList) && StringUtils.isNotBlank(comment.getIp())) {
            String ip = comment.getIp().trim().toLowerCase();
            for(String ipBlockRule : blockIpList) {
                Boolean fullMatched = !ipBlockRule.contains("?") && !ipBlockRule.contains("*");
                String regexForIP = ipBlockRule
                        .replace(".", "\\.");
                if (!fullMatched) {
                    regexForIP = regexForIP.replace("?", ".").replace("*", ".*?");
                }
                String prompt = fullMatched ? "完全" : "模糊";
                if (ip.matches(regexForIP)) {
                    log.info("评论触发了 IP 地址黑名单过滤（{}匹配）", prompt);
                    if (!processComment(comment, blockIpAction, blockIpActionAfter)) {
                        log.info("评论触发了 IP 地址黑名单过滤（{}匹配）的 {} 操作", prompt, blockIpAction.getNote());
                        return blockIpAction;
                    }
                    break;
                }
            }
        }
        
        // Email Filter
        if (!CollectionUtils.isEmpty(blockEmailList)) {
            for(String blockEmailRule : blockEmailList) {
                if (StringUtils.isBlank(blockEmailRule)) {
                    continue;
                }
                Pattern pattern = Pattern.compile(blockEmailRule, Pattern.CASE_INSENSITIVE);
                if (pattern.matcher(comment.getEmail()).find()) {
                    log.info("评论触发了邮箱地址黑名单过滤");
                    if (!processComment(comment, blockEmailAction, blockEmailActionAfter)) {
                        log.info("评论触发了邮箱地址黑名单过滤的 {} 操作", blockEmailAction.getNote());
                        return blockEmailAction;
                    }
                    break;
                }
            }
        }
        
        // Non-Chinese filter
        if (!UsefulRegex.ANY_CHINESE_PATTERN.matcher(comment.getContent()).find()) {
            log.info("评论触发了非中文过滤");
            if (!processComment(comment, nonChineseAction, nonChineseActionAfter)) {
                log.info("评论触发了非中文过滤的 {} 操作", nonChineseAction.getNote());
                return nonChineseAction;
            }
        }

        // Block Word Filter
        if (!CollectionUtils.isEmpty(blockWordList)) {
            for(String blockWordRule : blockWordList) {
                if (StringUtils.isBlank(blockWordRule)) {
                    continue;
                }
                Pattern pattern = Pattern.compile(blockWordRule, Pattern.CASE_INSENSITIVE);
                if (pattern.matcher(comment.getAuthor()).find() || pattern.matcher(comment.getContent()).find()) {
                    log.info("评论触发了违禁词过滤");
                    if (!processComment(comment, blockWordAction, blockWordActionAfter)) {
                        log.info("评论触发了违禁词过滤的 {} 操作", blockWordAction.getNote());
                        return blockWordAction;
                    }
                    break;
                }
            }
        }
        

        // Sensitive Word Filter
        if (!CollectionUtils.isEmpty(sensitiveWordList)) {
            for(String sensitiveWordRule : sensitiveWordList) {
                if (StringUtils.isBlank(sensitiveWordRule)) {
                    continue;
                }
                Pattern pattern = Pattern.compile(sensitiveWordRule, Pattern.CASE_INSENSITIVE);
                if (pattern.matcher(comment.getAuthor()).find() || pattern.matcher(comment.getContent()).find()) {
                    log.info("评论触发了敏感词过滤");
                    if (!processComment(comment, sensitiveWordAction, sensitiveWordActionAfter)) {
                        log.info("评论触发了敏感词过滤的 {} 操作", sensitiveWordAction.getNote());
                        return sensitiveWordAction;
                    }
                    break;
                }
            }
        }
        
        // HTML a tag & img tag
        if (markdownOn == true && htmlWaitingOn == true) {
            String html = MarkDownUtils.commentToHtml(comment.getContent());
            Document jsoupDoc = Jsoup.parseBodyFragment(html);
            if (jsoupDoc.select("a,img").size() > 0) {
                processComment(comment, CommentAction.WAITING, null);
                return CommentAction.WAITING;
            }
        }
        
        return CommentAction.NONE;
    }
    
    /**
     * 是否进行下一步
     * @param comment
     * @param action
     * @param actionAfter
     * @return
     */
    private boolean processComment(Comment comment, CommentAction action, CommentActionAfter actionAfter) {
        if (action == CommentAction.NONE) {
            return true;
        }
        if (action == CommentAction.WAITING) {
            comment.setCommentStatus(CommentStatusEnum.WAITING);
            return false;
        }
        else {
            if (actionAfter == CommentActionAfter.BLOCK_EMAIL || actionAfter == CommentActionAfter.BOTH) {
                addBlockEmail(comment.getEmail());
            }
            if (actionAfter == CommentActionAfter.BLOCK_IP || actionAfter == CommentActionAfter.BOTH) {
                addBlockIp(comment.getIp());
            }
            comment.setCommentStatus(CommentStatusEnum.SPAM);
            if (action == CommentAction.FAIL) {
                comment.setIsDeleted(true);
            }
        }
        return false;
    }
}
