package com.test.common.utils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.test.common.core.domain.model.JmeterRequest;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.samplers.SampleSaveConfiguration;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.ObjectProperty;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.threads.gui.ThreadGroupGui;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liangdaliang
 * @Description：JMeterter工具类
 * @date 2025-02-12 9:12
 */
public class JMeterUtil {

    /**
     * 生成jmeter测试执行计划并获取执行结果
     * @param jmeterRequest
     * @return
     */
    public static Map<String, String> getJmeterResult(JmeterRequest jmeterRequest) {
        Long id = jmeterRequest.getId();
        String url = jmeterRequest.getUrl();
        int port = jmeterRequest.getPort();
        String method = jmeterRequest.getMethod().toUpperCase();
        String requestBody = jmeterRequest.getRequestBody();
        String requestParams = jmeterRequest.getRequestParams();
        String requestHeaderJson = "";
        Map<String, String> requestParamsMap = convertJsonStringToMap(requestParams);
        String requestHeader = jmeterRequest.getRequestHeader();
        String jmeterHomePath = jmeterRequest.getJmeterHomePath();
        Map<String, String> result = null;
        try {
            // 1. 初始化 JMeter
            JMeterUtils.loadJMeterProperties(jmeterHomePath + "/bin/jmeter.properties");
            JMeterUtils.setJMeterHome(jmeterHomePath);
            JMeterUtils.initLocale();

            // 2. 创建测试计划
            TestPlan testPlan = createTestPlan("Dynamic Test Plan");

            // 3. 创建线程组
            ThreadGroup threadGroup = createThreadGroup(1, 1);

            // 4. 创建 HTTP 请求
            HTTPSamplerProxy httpSampler = null;
            if ("POST".equals(method)) {
                httpSampler = createPostHttpSampler(
                        url, // 请求地址
                        port,
                        requestBody, // 请求体
                        requestParamsMap // 查询参数
                );
            } else {
                httpSampler = createGetHttpSampler(
                        url, // 请求地址
                        port,
                        requestParamsMap // 查询参数
                );
            }
            // 5. 创建请求头管理器
            Map<String, String> headerMap = new HashMap<>();
            if (!StringUtils.isEmpty(requestHeader) && !requestHeader.equals("[]")) {
                Gson gson = new Gson();
                // 定义类型
                Type type = new TypeToken<List<Map<String, String>>>() {}.getType();
                // 解析 JSON 数组
                List<Map<String, String>> headerList = gson.fromJson(requestHeader, type);
                // 将 List<Map<String, String>> 转换为 Map<String, String>
                for (Map<String, String> entry : headerList) {
                    String key = entry.get("key");
                    String value = entry.get("value");
                    headerMap.put(key, value);
                }
                requestHeaderJson = gson.toJson(headerMap);
            }
            HeaderManager headerManager = createHeaderManager(headerMap);

            // 6. 获取结果：如汇总报告、查看结果树
            String replayLogPath = jmeterHomePath + "/replay_result"+ id +".log";
            List<ResultCollector> resultCollector = getResultCollector(replayLogPath);

            // 7. 构建测试树
            HashTree testPlanTree = new HashTree();
            HashTree threadGroupTree = testPlanTree.add(testPlan);
            threadGroupTree.add(threadGroup);
            threadGroupTree.add(httpSampler);
            threadGroupTree.add(headerManager);
            threadGroupTree.add(resultCollector);

            // 8. 保存测试计划为 JMX 文件
            File jmxFile = new File(jmeterHomePath + "/dynamic_test_plan"+ id +".jmx");
            SaveService.saveTree(testPlanTree, new FileOutputStream(jmxFile));

            // 9. 运行 JMeter 测试
            File resultFile = new File(jmeterHomePath + "/replay_result"+ id +".log");
            if (resultFile.exists()) {
                resultFile.delete();
            }
            StandardJMeterEngine jmeter = new StandardJMeterEngine();
            jmeter.configure(testPlanTree);
            jmeter.run();
            while (jmeter.isActive()) {
                System.out.println("JMeter isActive！");
                Thread.sleep(1000); // 每隔 1 秒检查一次
            }
            // 10. 获取响应结果
            result = getResultMessageFromFile(jmeterHomePath + "/replay_result"+ id +".log");
            if (result != null) {
                result.put("requestHeader", requestHeaderJson);
                result.put("requestBody", requestBody);
            }

            System.out.println("JMeter 测试执行完成！");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 创建测试计划
     * @param name
     * @return
     */
    private static TestPlan createTestPlan(String name) {
        TestPlan testPlan = new TestPlan(name);
        testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
        testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
        testPlan.setUserDefinedVariables((Arguments) new ArgumentsPanel().createTestElement());
        return testPlan;
    }

    /**
     * 创建线程组
     * @param numThreads
     * @param loops
     * @return
     */
    private static ThreadGroup createThreadGroup(int numThreads, int loops) {
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Thread Group");
        threadGroup.setNumThreads(numThreads);
        threadGroup.setRampUp(1);
        threadGroup.setSamplerController(createLoopController(loops));
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
        threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
        return threadGroup;
    }

    /**
     * 创建轮询控制器
     * @param loops
     * @return
     */
    private static LoopController createLoopController(int loops) {
        LoopController loopController = new LoopController();
        loopController.setLoops(loops);
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
        loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
        loopController.initialize();
        return loopController;
    }

    /**
     * 创建get请求方式
     * @param urlString
     * @param port
     * @param requestParams
     * @return
     * @throws MalformedURLException
     */
    private static HTTPSamplerProxy createGetHttpSampler(String urlString, int port, Map<String, String> requestParams) throws MalformedURLException {
        URL url = new URL(urlString);
        // 提取域名（不包括端口号）
        String domain = url.getHost();
        // 提取路径（不包括查询参数和片段标识符）
        String path = url.getPath();
        HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
        httpSampler.setName("HTTP Request Test");
        httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
        httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
        httpSampler.setDomain(domain); // 提取域名
        if (requestParams != null) {
            path += "?";
            path += mapToQueryString(requestParams);
        }
        httpSampler.setPath(path); // 提取路径
        httpSampler.setPort(port);
        httpSampler.setMethod("GET");
        httpSampler.setConnectTimeout("5000");
        httpSampler.setUseKeepAlive(true);

        return httpSampler;
    }

    /**
     * 构建get请求查询参数
     * @param params
     * @return
     */
    public static String mapToQueryString(Map<String, String> params) {
        StringBuilder queryString = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (!queryString.isEmpty()) {
                queryString.append("&");
            }
            // 对键和值进行 URL 编码
            String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
            String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
            queryString.append(encodedKey).append("=").append(encodedValue);
        }
        return queryString.toString();
    }

    /**
     * 转换[{"key":"authorization","value":"tttt"},{"key":"name","value":"123"}]为Map结构
     * @param jsonString
     * @return
     */
    private static Map<String, String> convertJsonStringToMap(String jsonString) {
        if (StringUtils.isEmpty(jsonString) || jsonString.equals("[]")) {
            return null;
        }
        Gson gson = new Gson();
        // 定义类型，用于告诉Gson我们期望的结果类型是一个包含键值对的对象列表
        Type listType = new TypeToken<List<Map<String, String>>>(){}.getType();

        // 将JSON字符串转换为List<Map<String, String>>
        List<Map<String, String>> keyValuePairs = gson.fromJson(jsonString, listType);

        // 创建一个新的Map<String, String>用于存储结果
        Map<String, String> resultMap = new HashMap<>();
        for (Map<String, String> pair : keyValuePairs) {
            // 确保每个map都有"key"和"value"两个字段
            if (pair.containsKey("key") && pair.containsKey("value")) {
                resultMap.put(pair.get("key"), pair.get("value"));
            }
        }

        return resultMap;
    }

    /**
     * 创建post请求方式
     * @param urlString
     * @param port
     * @param requestBody
     * @param requestParams
     * @return
     * @throws MalformedURLException
     */
    private static HTTPSamplerProxy createPostHttpSampler(String urlString, int port, String requestBody, Map<String, String> requestParams) throws MalformedURLException {
        URL url = new URL(urlString);
        // 提取域名（不包括端口号）
        String domain = url.getHost();
        // 提取路径（不包括查询参数和片段标识符）
        String path = url.getPath();
//        int portTest = url.getPort();
        HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
        httpSampler.setName("POST JSON Request");
        httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
        httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
        httpSampler.setDomain(domain);
        if (requestParams != null) {
            path += "?";
            path += mapToQueryString(requestParams);
        }
        httpSampler.setPath(path);
        httpSampler.setPort(port);
        httpSampler.setMethod("POST");
        httpSampler.setConnectTimeout("5000");
        httpSampler.setUseKeepAlive(true);

        // 设置请求体
        httpSampler.setPostBodyRaw(true); // 使用原始请求体
        httpSampler.addNonEncodedArgument("", requestBody, "");

        return httpSampler;
    }

    /**
     * 创建http请求头管理器
     * @param headerMap
     * @return
     */
    private static HeaderManager createHeaderManager(Map<String, String> headerMap) {
        HeaderManager headerManager = new HeaderManager();
        headerManager.setName("HTTP Header Manager");
        headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
        headerManager.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());

        // 添加默认 Content-Type 请求头
        if (!headerMap.containsKey("Content-Type")) {
            Header contentTypeHeader = new Header();
            contentTypeHeader.setName("Content-Type");
            contentTypeHeader.setValue("application/json; charset=UTF-8");
            headerManager.add(contentTypeHeader);
        }

        // 遍历 headerMap，动态添加请求头
        for (Map.Entry<String, String> entry : headerMap.entrySet()) {
            Header header = new Header();
            header.setName(entry.getKey()); // 请求头名称
            header.setValue(entry.getValue()); // 请求头值
            headerManager.add(header);
        }

        return headerManager;
    }

    /***
     * 监听结果树
     * @param replayLogPath  将结果保存到文件中，这个是文件的路径
     * @return
     */
    private static List<ResultCollector> getResultCollector(String replayLogPath) {
        // 察看结果数
        List<ResultCollector> resultCollectors = new ArrayList<>();
        Summariser summariser = new Summariser("速度");
        ResultCollector resultCollector = new ResultCollector(summariser);
        resultCollector.setProperty(new BooleanProperty("ResultCollector.error_logging", false));
        resultCollector.setProperty(new ObjectProperty("saveConfig", getSampleSaveConfig()));
        resultCollector.setProperty(new StringProperty("TestElement.gui_class", "org.apache.jmeter.visualizers.ViewResultsFullVisualizer"));
        resultCollector.setProperty(new StringProperty("TestElement.name", "察看结果树"));
        resultCollector.setProperty(new StringProperty("TestElement.enabled", "true"));
        resultCollector.setProperty(new StringProperty("filename", replayLogPath));
        resultCollectors.add(resultCollector);

        // 结果汇总
//        ResultCollector resultTotalCollector = new ResultCollector();
//        resultTotalCollector.setProperty(new BooleanProperty("ResultCollector.error_logging", false));
//        resultTotalCollector.setProperty(new ObjectProperty("saveConfig", getSampleSaveConfig()));
//        resultTotalCollector.setProperty(new StringProperty("TestElement.gui_class", "org.apache.jmeter.visualizers.SummaryReport"));
//        resultTotalCollector.setProperty(new StringProperty("TestElement.name", "汇总报告"));
//        resultTotalCollector.setProperty(new StringProperty("TestElement.enabled", "true"));
//        resultTotalCollector.setProperty(new StringProperty("filename", ""));
//        resultCollectors.add(resultTotalCollector);

        return resultCollectors;
    }

    /**
     * 配置采样结果信息
     * @return
     */
    private static SampleSaveConfiguration getSampleSaveConfig() {
        SampleSaveConfiguration sampleSaveConfiguration = new SampleSaveConfiguration();
        sampleSaveConfiguration.setTime(true);
        sampleSaveConfiguration.setLatency(true);
        sampleSaveConfiguration.setTimestamp(true);
        sampleSaveConfiguration.setSuccess(true);
        sampleSaveConfiguration.setLabel(true);
        sampleSaveConfiguration.setCode(true);
        sampleSaveConfiguration.setMessage(true);
        sampleSaveConfiguration.setThreadName(true);
        sampleSaveConfiguration.setDataType(true);
        sampleSaveConfiguration.setEncoding(true);
        sampleSaveConfiguration.setAssertions(true);
        sampleSaveConfiguration.setSubresults(true);
        sampleSaveConfiguration.setResponseData(true);
        sampleSaveConfiguration.setSamplerData(true);
        sampleSaveConfiguration.setAsXml(true);
        sampleSaveConfiguration.setFieldNames(true);
        sampleSaveConfiguration.setResponseHeaders(true);
        sampleSaveConfiguration.setRequestHeaders(false);
        sampleSaveConfiguration.setAssertionResultsFailureMessage(true);
        //sampleSaveConfiguration.setsserAtionsResultsToSave(0); assertionsResultsToSave
        sampleSaveConfiguration.setBytes(true);
        sampleSaveConfiguration.setSentBytes(true);
        sampleSaveConfiguration.setUrl(true);
        sampleSaveConfiguration.setThreadCounts(true);
        sampleSaveConfiguration.setIdleTime(true);
        sampleSaveConfiguration.setConnectTime(true);
        return sampleSaveConfiguration;
    }

    /**
     * 从结果文件读取响应内容
     * @param filePath
     * @return
     */
    private static Map<String, String> getResultMessageFromFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return null;
        }
        try {
            // 1. 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 2. 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 3. 解析XML文件，获取Document对象
            Document document = builder.parse(new File(filePath));
            // 4. 获取所有<httpSample>节点
            NodeList httpSampleList = document.getElementsByTagName("httpSample");
            Node httpSampleNode = httpSampleList.item(0);
            if (httpSampleNode.getNodeType() == Node.ELEMENT_NODE) {
                Map<String, String> resultMap = new HashMap<>();
                Element httpSampleElement = (Element) httpSampleNode;
                String costMiliseconds = httpSampleElement.getAttribute("t");
                String responseCode = httpSampleElement.getAttribute("rc");
                resultMap.put("responseCode", responseCode);
                resultMap.put("costMiliseconds", costMiliseconds);
                // 提取子节点<responseData>的内容
                NodeList responseDataList = httpSampleElement.getElementsByTagName("responseData");
                if (responseDataList.getLength() > 0) {
                    Element responseDataElement = (Element) responseDataList.item(0);
                    resultMap.put("responseBody", responseDataElement.getTextContent());
                }
                // 提取子节点<responseHeader>的内容
                NodeList responseHeaderList = httpSampleElement.getElementsByTagName("responseHeader");
                if (responseHeaderList.getLength() > 0) {
                    Element responseHeaderElement = (Element) responseHeaderList.item(0);
                    resultMap.put("responseHeader", responseHeaderElement.getTextContent());
                }
                return resultMap;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从响应头中读取Map信息结构
     * @param responseHeader
     * @return
     */
    public static Map<String, String> parseHeaders(String responseHeader) {
        Map<String, String> headerMap = new HashMap<>();
        if (responseHeader == null) {
            return headerMap;
        }
        // 按行拆分
        String[] lines = responseHeader.split("\n");
        // 遍历每一行
        for (String line : lines) {
            // 忽略空行和 HTTP 状态行
            if (line.trim().isEmpty() || line.startsWith("HTTP/")) {
                continue;
            }
            // 按冒号拆分键值对
            int colonIndex = line.indexOf(":");
            if (colonIndex > 0) {
                String key = line.substring(0, colonIndex).trim();
                String value = line.substring(colonIndex + 1).trim();
                headerMap.put(key, value);
            }
        }
        return headerMap;
    }

    /**
     * 根据 JSONPath 表达式从 JSON 中提取字段值
     *
     * @param json       JSON 字符串
     * @param expression JSONPath 表达式
     * @return 字段值，如果字段不存在则返回 null
     */
    public static String extractFieldValue(String json, String expression) {
        try {
            Object result = JsonPath.read(json, expression);
            return result != null ? result.toString() : null;
        } catch (PathNotFoundException e) {
            // 如果字段不存在，返回 null
            return null;
        }
    }

    public static void main(String[] args) {
        String paramJson = "{\"md5Value\":\"value1\",\"fileName\":\"value2\"}";
        paramJson = "{\"name\":\"John\",\"city\":\"New York\",\"age\":30}";
        String requestHeader = "{\"Content-Type\":\"application/json; charset=UTF-8\",\"Authorization\":\"Bearer token123\"}";
        String jmeterHomePath = "D:/apache-jmeter-5.4.3";
//        String result = getJmeterResult("http://127.0.0.1:3000/api/items/add", 3000, "POST", paramJson, requestHeader, jmeterHomePath);
//        getJmeterResult(123L, "http://127.0.0.1:3000/api/items/user", 3000, "GET", paramJson, requestHeader, jmeterHomePath);
//        System.out.println(result);
    }
}
