package cn.xeblog.xechat.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.*;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 敏感词处理
 *
 * @author yanpanyi
 * @date 2019/4/4
 */
@Slf4j
@Configuration
public class SensitiveWordUtils {

    private final static String[] LOVE_CHINA = {"富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国",
            "敬业", "诚信", "友善"};

    /**
     * 敏感词库
     */
    private static Set<String> keyWords;
    /**
     * 敏感词根节点
     */
    private static SensitiveWordNode rootNode;

    /**
     * 读取敏感词
     */
    private static void readSensitiveWords() {
        keyWords = new HashSet<>();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(SensitiveWordUtils.class
                    .getResourceAsStream("/sensitive-word.txt"), "utf-8"));

            String line;
            while ((line = reader.readLine()) != null) {
                keyWords.add(line.trim());
            }
        } catch (Exception e) {
            log.error("读取敏感词库出现异常! error -> {}", e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
    }

    /**
     * 初始化敏感词库
     */
    private static void init() {
        if (rootNode != null) {
            return;
        }
        if (keyWords == null) {
            // 读取敏感词库
            readSensitiveWords();
            log.info("初始化敏感词库,共有{}个敏感词", keyWords.size());
        }

        // 初始化根节点
        rootNode = new SensitiveWordNode(' ');
        log.info("初始化敏感词节点");

        // 创建敏感词
        for (String keyWord : keyWords) {
            buildSensitiveWordNode(keyWord);
        }
    }

    /**
     * 构建敏感词节点
     *
     * @param keyWord
     */
    private static void buildSensitiveWordNode(String keyWord) {
        SensitiveWordNode nowNode = rootNode;

        for (Character c : keyWord.toCharArray()) {
            SensitiveWordNode nextNode = nowNode.getNextNode(c);
            if (nextNode == null) {
                nextNode = new SensitiveWordNode(c);
                nowNode.putNextNode(nextNode);
            }
            nowNode = nextNode;
        }
        nowNode.setEnd(true);
    }

    /**
     * 判断是否存在敏感词
     *
     * @param text
     * @return true:存在敏感词 false:未存在敏感词
     */
    public static boolean hasSensitiveWord(String text) {
        if (StringUtils.isEmpty(text)) {
            return false;
        }

        if (rootNode == null) {
            log.info("敏感词节点未被初始化!");
            return false;
        }

        // 清除非法字符
        text = invalidClear(text);
        StringBuilder sb = new StringBuilder();
        SensitiveWordNode nowNode;

        for (int i = 0; i < text.length(); i++) {
            nowNode = rootNode;
            for (int j = i; j < text.length(); j++) {
                nowNode = nowNode.getNextNode(text.charAt(j));
                if (nowNode == null) {
                    sb.setLength(0);
                    break;
                }

                sb.append(nowNode.getKey());

                if (nowNode.isEnd()) {
                    log.info("[{}] => 存在敏感词 -> {}", text, sb.toString());
                    return true;
                }
            }
        }

        return false;
    }

    @PostConstruct
    public void initData() {
        init();
    }

    /**
     * 热爱祖国,热爱人民
     *
     * @param text
     * @return 如果存在敏感词则返回处理后的结果,否则直接返回原内容
     */
    public static String loveChina(String text) {
        if (hasSensitiveWord(text)) {
            return LOVE_CHINA[(int) (Math.random() * LOVE_CHINA.length)];
        }

        return text;
    }

    /**
     * 清除非法字符
     *
     * @param str
     * @return 返回清除非法字符后的结果
     */
    private static String invalidClear(String str) {
        String regEx = "[`~!@#$%^&*()+=|{}':;,\\[\\].<>/?!¥…()—【】{}|/《》‘;:+——*&……%$#@!~”“’。,、?·\\s\t\r\n]";
        Matcher m = Pattern.compile(regEx).matcher(str);
        return m.replaceAll("").trim();
    }
}