package com.vetti.common.utils.html;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * OkHttp第三方库读取网页HTML内容
 */
public class ReadHtmlByOkHttp {

    // 预编译空白清理正则
    private static final Pattern BLANK_LINE_PATTERN = Pattern.compile("\\n\\s*\\n");
    private static final Pattern MULTIPLE_SPACE_PATTERN = Pattern.compile("\\s+");


    // 全局OkHttpClient实例（推荐单例，避免重复创建连接池）
    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(5, TimeUnit.SECONDS) // 连接超时
            .readTimeout(5, TimeUnit.SECONDS)    // 读取超时
            .writeTimeout(5, TimeUnit.SECONDS)   // 写入超时
            .build();

    /**
     * OkHttp获取网页HTML内容
     * @param urlStr 网站链接
     * @return 网页HTML字符串
     * @throws IOException 网络IO异常
     */
    public static String getHtmlContentByOkHttp(String urlStr) throws IOException {
        // 1. 构建GET请求
        Request request = new Request.Builder()
                .url(urlStr)
                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
                .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
                .header("Referer", urlStr)
                .get() // 默认就是GET请求，可省略
                .build();

        // 2. 执行请求并获取响应（try-with-resources自动关闭Response）
        try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
            // 3. 检查响应是否成功
            if (!response.isSuccessful()) {
                throw new IOException("请求失败，响应码：" + response.code());
            }

            // 4. 读取响应体内容（string()方法默认使用UTF-8编码，避免乱码）
            return response.body() != null ? response.body().string() : "";
        }
    }

    /**
     * JSoup仅去除HTML标签及属性，保留原始文本（不修改转义字符、空白字符）
     * @param htmlContent 原始HTML字符串
     * @return 剥离标签和属性后的文本
     */
    public static String removeHtmlTagAndAttrByJsoup(String htmlContent) {
        if (htmlContent == null || htmlContent.isEmpty()) {
            return "";
        }

        // 步骤1：解析HTML为Document对象（自动修复畸形HTML标签）
        Document document = Jsoup.parse(htmlContent);
        // 可选：删除HTML注释（若需保留注释可注释此行）
//        Elements comments = document.select("comment()");
//        comments.remove();

        // 步骤2：递归遍历所有节点，仅提取文本节点的内容
        StringBuilder textBuilder = new StringBuilder();
        traverseNodes(document.body(), textBuilder);

        return textBuilder.toString();
    }

    /**
     * 递归遍历节点，提取纯文本（跳过标签和属性，仅保留文本节点内容）
     */
    private static void traverseNodes(Node node, StringBuilder textBuilder) {
        // 若是文本节点，直接追加内容（保留原始格式）
        if (node instanceof TextNode) {
            TextNode textNode = (TextNode) node;
            textBuilder.append(textNode.getWholeText()); // getWholeText()保留原始文本，不做任何处理
            return;
        }

        // 若是元素节点（标签），跳过标签本身和属性，递归遍历子节点
        if (node instanceof Element) {
            for (Node childNode : node.childNodes()) {
                traverseNodes(childNode, textBuilder);
            }
        }
    }

    /**
     * 去除空白行和多余空格，生成整洁文本
     */
    public static String removeBlankLineAndSpace(String text) {
        if (text == null || text.isEmpty()) {
            return "";
        }

        // 步骤1：清理空白行（多次替换确保所有连续空白行都被清理）
        String noBlankLine = BLANK_LINE_PATTERN.matcher(text).replaceAll("\n");
        while (BLANK_LINE_PATTERN.matcher(noBlankLine).find()) {
            noBlankLine = BLANK_LINE_PATTERN.matcher(noBlankLine).replaceAll("\n");
        }

        // 步骤2：合并多余空格为单个空格
        String noMultipleSpace = MULTIPLE_SPACE_PATTERN.matcher(noBlankLine).replaceAll(" ");

        // 步骤3：去除首尾空白
        return noMultipleSpace.trim();
    }

}
