package com.qqchen.deploy.backend.deploy.integration.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus;
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsJobResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsQueueBuildInfoResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsCrumbIssuerResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsViewResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.apache.commons.lang3.StringUtils;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.InputSource;

import java.nio.charset.Charset;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration {

    @Resource
    private IExternalSystemRepository systemRepository;

    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public boolean testConnection(ExternalSystem system) {
        try {
            String url = system.getUrl() + "/api/json";
            HttpHeaders headers = createHeaders(system);
            HttpEntity<String> entity = new HttpEntity<>(headers);

            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );

            return response.getStatusCode() == HttpStatus.OK;
        } catch (Exception e) {
            log.error("Failed to connect to Jenkins: {}", system.getUrl(), e);
            return false;
        }
    }

    private HttpHeaders createHeaders(ExternalSystem system) {
        HttpHeaders headers = new HttpHeaders();
        switch (system.getAuthType()) {
            case BASIC -> {
                String auth = system.getUsername() + ":" + system.getPassword();
                byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
                headers.set("Authorization", "Basic " + new String(encodedAuth));
            }
            case TOKEN -> headers.set("Authorization", "Bearer " + system.getToken());
            case OAUTH -> headers.set("Authorization", "Bearer " + system.getToken());
        }
        return headers;
    }

    private HttpEntity<String> createHttpEntity(ExternalSystem jenkins) {
        HttpHeaders headers = new HttpHeaders();

        // 根据认证类型设置认证信息
        switch (jenkins.getAuthType()) {
            case BASIC -> {
                // Basic认证
                String auth = jenkins.getUsername() + ":" + jenkins.getPassword();
                byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
                String authHeader = "Basic " + new String(encodedAuth);
                headers.set("Authorization", authHeader);
            }
            case TOKEN -> {
                // Token认证
                headers.set("Authorization", "Bearer " + jenkins.getToken());
            }
            default -> throw new RuntimeException("Unsupported authentication type: " + jenkins.getAuthType());
        }

        // 设置接受JSON响应
        headers.set("Accept", "application/json");

        return new HttpEntity<>(headers);
    }


    @Override
    public JenkinsCrumbIssuerResponse getJenkinsCrumbIssue() {
        ExternalSystem externalSystem = systemRepository.findById(1L).orElseThrow(() -> new RuntimeException("没有找到三方系统"));
        String url = externalSystem.getUrl() + "/crumbIssuer/api/json";
        HttpHeaders headers = createHeaders(externalSystem);
        HttpEntity<String> entity = new HttpEntity<>(headers);
        return convertResponse(restTemplate.exchange(url, HttpMethod.GET, entity, String.class));
    }

    @Override
    public String buildWithParameters(ExternalSystem externalSystem, String jobName, Map<String, String> parameters) {
        try {
            // 如果参数中包含PIPELINE_SCRIPT，确保Job配置中有该参数
            if (parameters.containsKey("PIPELINE_SCRIPT")) {
                ensurePipelineScriptParameter(externalSystem, jobName);
            }

            // 1. 获取Crumb
            JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue();

            // 2. 构建URL
            String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
                .path("/job/")
                .path(jobName)
                .path("/buildWithParameters")
                .build()
                .toUriString();

            // 3. 构建请求头
            HttpHeaders headers = createHeaders(externalSystem);
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
            headers.set("Cookie", jenkinsCrumbIssue.getCookie());

            // 4. 构建请求体
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            parameters.forEach(formData::add);

            // 5. 发送请求
            HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formData, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                entity,
                String.class
            );

            // 6. 获取队列ID
            String location = response.getHeaders().getFirst("Location");
            if (location == null) {
                throw new RuntimeException("未获取到构建队列信息");
            }
            return extractQueueId(location);
        } catch (Exception e) {
            log.error("Failed to trigger Jenkins build: job={}, error={}", jobName, e.getMessage(), e);
            throw new RuntimeException("触发Jenkins构建失败: " + jobName, e);
        }
    }

    /**
     * 确保Jenkins Job配置中包含PIPELINE_SCRIPT参数
     */
    private void ensurePipelineScriptParameter(ExternalSystem externalSystem, String jobName) {
        try {
            // 获取 Crumb
            JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue();

            // 获取Job配置
            String configUrl = String.format("%s/job/%s/config.xml", externalSystem.getUrl(), jobName);
            HttpHeaders headers = createHeaders(externalSystem);
            // 设置请求和响应的字符编码
            headers.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
            headers.set(HttpHeaders.CONTENT_TYPE, "application/xml;charset=UTF-8");
            headers.setAcceptCharset(Collections.singletonList(Charset.forName("UTF-8")));
            
            headers.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
            headers.set("Cookie", jenkinsCrumbIssue.getCookie());
            
            HttpEntity<String> entity = new HttpEntity<>(headers);
            
            // 配置RestTemplate，确保使用UTF-8编码
            restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
            
            ResponseEntity<String> response = restTemplate.exchange(
                configUrl,
                HttpMethod.GET,
                entity,
                String.class
            );

            if (response.getBody() == null) {
                throw new RuntimeException("无法获取Jenkins Job配置");
            }

            // 解析XML
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            DocumentBuilder builder = factory.newDocumentBuilder();
            
            // 使用UTF-8编码解析XML
            InputSource is = new InputSource(new StringReader(response.getBody()));
            is.setEncoding("UTF-8");
            Document doc = builder.parse(is);

            // 检查是否已存在PIPELINE_SCRIPT参数
            NodeList parameterDefinitions = doc.getElementsByTagName("parameterDefinitions");
            if (parameterDefinitions.getLength() > 0) {
                NodeList parameters = parameterDefinitions.item(0).getChildNodes();
                for (int i = 0; i < parameters.getLength(); i++) {
                    Node parameter = parameters.item(i);
                    if (parameter.getNodeType() == Node.ELEMENT_NODE) {
                        NodeList parameterChildren = parameter.getChildNodes();
                        for (int j = 0; j < parameterChildren.getLength(); j++) {
                            Node child = parameterChildren.item(j);
                            if ("name".equals(child.getNodeName()) && "PIPELINE_SCRIPT".equals(child.getTextContent())) {
                                // 参数已存在，无需添加
                                return;
                            }
                        }
                    }
                }
            }

            // 需要添加PIPELINE_SCRIPT参数
            Element root = doc.getDocumentElement();
            
            // 获取或创建properties元素
            NodeList propertiesList = doc.getElementsByTagName("properties");
            Element properties;
            if (propertiesList.getLength() == 0) {
                properties = doc.createElement("properties");
                root.appendChild(properties);
            } else {
                properties = (Element) propertiesList.item(0);
            }

            // 获取或创建ParametersDefinitionProperty元素
            NodeList paramDefProps = properties.getElementsByTagName("hudson.model.ParametersDefinitionProperty");
            Element paramDefProp;
            if (paramDefProps.getLength() == 0) {
                paramDefProp = doc.createElement("hudson.model.ParametersDefinitionProperty");
                properties.appendChild(paramDefProp);
            } else {
                paramDefProp = (Element) paramDefProps.item(0);
            }

            // 获取或创建parameterDefinitions元素
            NodeList paramDefs = paramDefProp.getElementsByTagName("parameterDefinitions");
            Element parameterDefs;
            if (paramDefs.getLength() == 0) {
                parameterDefs = doc.createElement("parameterDefinitions");
                paramDefProp.appendChild(parameterDefs);
            } else {
                parameterDefs = (Element) paramDefs.item(0);
            }

            // 创建PIPELINE_SCRIPT参数定义
            Element stringParam = doc.createElement("hudson.model.StringParameterDefinition");
            
            Element name = doc.createElement("name");
            name.setTextContent("PIPELINE_SCRIPT");
            stringParam.appendChild(name);
            
            Element description = doc.createElement("description");
            description.setTextContent("Pipeline脚本内容");
            stringParam.appendChild(description);
            
            Element defaultValue = doc.createElement("defaultValue");
            defaultValue.setTextContent("");
            stringParam.appendChild(defaultValue);
            
            Element trim = doc.createElement("trim");
            trim.setTextContent("false");
            stringParam.appendChild(trim);

            parameterDefs.appendChild(stringParam);

            // 更新Job配置时设置正确的编码
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.VERSION, "1.1");
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.STANDALONE, "no");
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(doc), new StreamResult(writer));
            String updatedConfig = writer.toString();

            // 更新Job配置
            HttpHeaders updateHeaders = createHeaders(externalSystem);
            updateHeaders.setContentType(MediaType.APPLICATION_XML);
            updateHeaders.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
            updateHeaders.set("Content-Type", "application/xml; charset=utf-8");
            updateHeaders.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
            updateHeaders.set("Cookie", jenkinsCrumbIssue.getCookie());
            HttpEntity<String> updateEntity = new HttpEntity<>(updatedConfig, updateHeaders);
            restTemplate.exchange(
                configUrl,
                HttpMethod.POST,
                updateEntity,
                String.class
            );

            log.info("Successfully added PIPELINE_SCRIPT parameter to Jenkins job: {}", jobName);
        } catch (Exception e) {
            log.error("Failed to ensure PIPELINE_SCRIPT parameter for Jenkins job: {}, error: {}", jobName, e.getMessage(), e);
            throw new RuntimeException("确保Jenkins Job PIPELINE_SCRIPT参数失败", e);
        }
    }

    /**
     * 清理XML内容，移除无效字符
     */
    private String cleanXmlContent(String xml) {
        if (xml == null) {
            return "";
        }
        
        // 移除XML中的无效字符
        StringBuilder cleanXml = new StringBuilder();
        for (int i = 0; i < xml.length(); i++) {
            char c = xml.charAt(i);
            // XML 1.1规范允许的字符范围（比1.0更宽松）
            if ((c == 0x9) ||
                (c == 0xA) ||
                (c == 0xD) ||
                ((c >= 0x20) && (c <= 0xD7FF)) ||
                ((c >= 0xE000) && (c <= 0xFFFD)) ||
                ((c >= 0x10000) && (c <= 0x10FFFF)) ||
                // 允许一些常见的控制字符
                (c >= 0x1) && (c <= 0x1F)) {
                cleanXml.append(c);
            }
        }
        return cleanXml.toString();
    }

    @Override
    public JenkinsQueueBuildInfoResponse getQueuedBuildInfo(String queueId) {
        ExternalSystem externalSystem = systemRepository.findById(1L).orElseThrow(() -> new RuntimeException("没有找到三方系统"));
        String queueUrl = String.format("%s/queue/item/%s/api/json", externalSystem.getUrl().trim(), queueId);
        ResponseEntity<Map<String, Object>> response = restTemplate.exchange(queueUrl, HttpMethod.GET, createHttpEntity(externalSystem), new ParameterizedTypeReference<>() {
        });

        Map<String, Object> queueInfo = response.getBody();
        if (queueInfo == null) {
            throw new RuntimeException("Failed to get queue information");
        }

        // 检查是否被取消
        Boolean cancelled = (Boolean) queueInfo.get("cancelled");
        if (Boolean.TRUE.equals(cancelled)) {
            throw new RuntimeException("Build was cancelled in queue");
        }

        // 检查是否已开始执行
        Map<String, Object> executable = (Map<String, Object>) queueInfo.get("executable");
        if (executable != null) {
            return new JenkinsQueueBuildInfoResponse(
                ((Number) executable.get("number")).intValue(),
                (String) executable.get("url")
            );
        }
        // 还在队列中
        return null;
    }


    @Override
    public JenkinsBuildStatus getBuildStatus(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
        try {
            String url = String.format("%s/job/%s/%d/api/json", externalSystem.getUrl().trim(), jobName, buildNumber);
            ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                createHttpEntity(externalSystem),
                new ParameterizedTypeReference<>() {
                }
            );
            if (response.getBody() == null) {
                return JenkinsBuildStatus.NOT_FOUND;
            }
            String result = (String) response.getBody().get("result");
            if (result == null) {
                return JenkinsBuildStatus.IN_PROGRESS;
            }
            return switch (result) {
                case "SUCCESS" -> JenkinsBuildStatus.SUCCESS;
                case "FAILURE" -> JenkinsBuildStatus.FAILURE;
                case "ABORTED" -> JenkinsBuildStatus.ABORTED;
                default -> JenkinsBuildStatus.IN_PROGRESS;
            };
        } catch (Exception e) {
            log.error("Failed to get build status: job={}, buildNumber={}", jobName, buildNumber, e);
            throw new RuntimeException("Failed to get build status", e);
        }
    }

    @Override
    public JenkinsBuildResponse getBuildDetails(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
        try {
            // 构建 tree 参数，只获取我们需要的字段
            String treeQuery = "number,url,result,duration,timestamp,building," +
                "changeSets[items[commitId,author,message]]," +
                "artifacts[fileName,relativePath,displayPath]";
            
            String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
                .path("/job/")
                .path(jobName)
                .path("/")
                .path(buildNumber.toString())
                .path("/api/json")
                .queryParam("tree", treeQuery)
                .build()
                .toUriString();

            HttpEntity<String> entity = new HttpEntity<>(createHeaders(externalSystem));
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                // 打印原始响应用于调试
                log.info("Jenkins build details raw response: {}", response.getBody());
                
                ObjectMapper mapper = new ObjectMapper();
                JenkinsBuildResponse buildResponse = mapper.readValue(response.getBody(), JenkinsBuildResponse.class);
                
                // 清理URL，移除基础URL部分
                if (buildResponse.getUrl() != null) {
                    String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
                    buildResponse.setUrl(buildResponse.getUrl().replace(baseUrl, ""));
                }
                
                return buildResponse;
            }
            
            throw new RuntimeException("Failed to get build details: empty response");
        } catch (Exception e) {
            log.error("Failed to get build details: job={}, buildNumber={}, error={}", 
                jobName, buildNumber, e.getMessage(), e);
            throw new RuntimeException("获取Jenkins构建详情失败: " + jobName + "#" + buildNumber, e);
        }
    }

    private String extractQueueId(String location) {
        // location格式: http://jenkins-url/queue/item/12345/
        return location.replaceAll(".*/item/(\\d+)/.*", "$1");
    }

    public JenkinsCrumbIssuerResponse convertResponse(ResponseEntity<String> response) {
        // 1. 从响应体中解析JSON
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode;
        try {
            jsonNode = objectMapper.readTree(response.getBody());
        } catch (JsonProcessingException e) {
            throw new RuntimeException("解析Jenkins响应失败", e);
        }

        // 2. 从响应头中获取cookie
        String cookie = response.getHeaders().getFirst(HttpHeaders.SET_COOKIE);  // 获取SET_COOKIE头的第一个值

        // 3. 构建返回对象
        JenkinsCrumbIssuerResponse result = new JenkinsCrumbIssuerResponse();
        result.setCrumb(jsonNode.get("crumb").asText());
        result.setCookie(cookie);

        return result;
    }

    /**
     * 通用的Jenkins API调用方法
     *
     * @param externalSystem Jenkins系统配置
     * @param path           API路径
     * @param treeQuery      tree查询参数
     * @param jsonArrayKey   JSON数组的key
     * @param responseType   响应类型的Class对象，用于类型安全
     * @param <T>            响应类型泛型
     * @return API响应结果
     */
    private <T> List<T> callJenkinsApi(ExternalSystem externalSystem,
                                       String path,
                                       String treeQuery,
                                       String jsonArrayKey,
                                       Class<T> responseType) {
        try {
            String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
                .path(path)
                .queryParam("tree", treeQuery)
                .build()
                .toUriString();

            HttpEntity<String> entity = new HttpEntity<>(createHeaders(externalSystem));
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                ObjectMapper mapper = new ObjectMapper();
                JsonNode root = mapper.readTree(response.getBody());
                // 使用responseType进行类型安全的转换
                return mapper.convertValue(root.get(jsonArrayKey),
                    mapper.getTypeFactory().constructCollectionType(List.class, responseType));
            }
            return Collections.emptyList();
        } catch (Exception e) {
            log.error("Failed to call Jenkins API: path={}, error={}, responseType={}",
                path, e.getMessage(), responseType.getSimpleName(), e);
            throw new RuntimeException("调用Jenkins API失败: " + path, e);
        }
    }

    /**
     * 查询所有视图
     *
     * @param externalSystem Jenkins系统配置
     * @return 视图列表
     */
    public List<JenkinsViewResponse> listViews(ExternalSystem externalSystem) {
        String treeQuery = "views[name,url,description,_class]";
        List<JenkinsViewResponse> views = callJenkinsApi(
            externalSystem,
            "/api/json",
            treeQuery,
            "views",
            JenkinsViewResponse.class
        );

        // 过滤和清洗数据
        return views.stream()
            .filter(view -> !"all".equalsIgnoreCase(view.getName()))
            .peek(view -> {
                // 清理描述中的多余空格
                if (view.getDescription() != null) {
                    view.setDescription(view.getDescription().trim());
                }
                // 转换URL为相对路径
                if (view.getUrl() != null) {
                    String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
                    view.setUrl(view.getUrl().replace(baseUrl, ""));
                }
            })
            .toList();
    }

    /**
     * 查询视图下的所有任务
     *
     * @param externalSystem Jenkins系统配置
     * @param viewName       视图名称
     * @return 任务列表
     */
    public List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName) {
        // 只查询必要的字段，确保包含lastBuild的timestamp字段
        String treeQuery = "jobs[name,url,description,buildable,nextBuildNumber," +
            "lastBuild[number,timestamp,result],color]";

        List<JenkinsJobResponse> jobs = callJenkinsApi(
            externalSystem,
            "/view/" + viewName + "/api/json",
            treeQuery,
            "jobs",
            JenkinsJobResponse.class
        );

        String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
        return jobs.stream()
            .peek(job -> {
                if (job.getDescription() != null) {
                    job.setDescription(job.getDescription().trim());
                }
                if (job.getUrl() != null) {
                    job.setUrl(job.getUrl().replace(baseUrl, ""));
                }
                if (job.getBuildable() == null) {
                    job.setBuildable(false);
                }
                if (job.getNextBuildNumber() == null) {
                    job.setNextBuildNumber(1);
                }
            })
            .toList();
    }

    @Override
    public JenkinsJobResponse job(ExternalSystem externalSystem, String jobName) {
        try {
            // 1. 构建请求URL
            String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
                .path("/job/")
                .path(jobName)
                .path("/api/json")
                .queryParam("tree", "name,url,description,buildable,nextBuildNumber,lastBuild[number,timestamp,result],color,healthReport[score,description]")
                .build()
                .toUriString();

            // 2. 发送请求
            HttpEntity<String> entity = new HttpEntity<>(createHeaders(externalSystem));
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );

            // 3. 解析响应
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                ObjectMapper mapper = new ObjectMapper();
                JenkinsJobResponse jobResponse = mapper.readValue(response.getBody(), JenkinsJobResponse.class);

                // 4. 清理URL，移除基础URL部分
                if (jobResponse.getUrl() != null) {
                    String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
                    jobResponse.setUrl(jobResponse.getUrl().replace(baseUrl, ""));
                }

                return jobResponse;
            }

            return null;
        } catch (Exception e) {
            log.error("Failed to get Jenkins job: jobName={}, error={}", jobName, e.getMessage(), e);
            throw new RuntimeException("获取Jenkins任务失败: " + jobName, e);
        }
    }

    /**
     * 查询任务的构建信息
     *
     * @param externalSystem Jenkins系统配置
     * @param jobName        任务名称
     * @return 构建信息列表
     */
    public List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName) {
        String treeQuery = "builds[number,url,result,timestamp,duration,building,actions[_class,parameters[_class,name,value]]]";
        List<JenkinsBuildResponse> builds = callJenkinsApi(
            externalSystem,
            "/job/" + jobName + "/api/json",
            treeQuery,
            "builds",
            JenkinsBuildResponse.class
        );

        String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
        return builds.stream()
            .peek(build -> {
                if (build.getUrl() != null) {
                    build.setUrl(build.getUrl().replace(baseUrl, ""));
                }
            })
            .toList();
    }
}
