# ExternalResponseUtil.java

    package com.yumu.noveltranslator.util;

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.yumu.noveltranslator.enums.ErrorCodeEnum;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.nodes.Node;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    public class ExternalResponseUtil {
        private static final ObjectMapper MAPPER = new ObjectMapper();

        /**
         * 从原始后端JSON响应中提取主要翻译文本。
         * 后端格式通常为：
         * {“code”：200，“data”：“<h1>...</h1>”，“engine”：“google”,...}
         * 该方法尝试共用键（data、translatedContent、translation）和
         * 在解析失败时，会退回返回原始的原始字符串。
         */
        /**
         * 从原始后端 JSON 响应中提取主要翻译文本
         * 支持的格式：
         * 1. 标准格式：{"success": true, "engine": "google", "translatedContent": "{...}"}
         * 2. 通用格式：{"code": 200, "data": "<h1>...</h1>", "engine": "google",...}
         *
         * @param rawJson 原始 JSON 响应
         * @return 翻译文本，如果失败返回 null
         */
        public static String extractDataField(String rawJson) {
            if (rawJson == null) return null;
            try {
                JsonNode root = MAPPER.readTree(rawJson);
                if (root == null) return null;

                // 1. 优先提取 translatedContent 字段（标准格式）
                if (root.has("translatedContent")) {
                    JsonNode translatedContent = root.get("translatedContent");
                    if (translatedContent.isTextual()) {
                        return translatedContent.asText();
                    }
                    return translatedContent.toString();
                }

                // 2. 验证状态码（仅对有 code 字段的格式）
                StatusCodeResult statusResult = validateStatusCode(root);
                if (!statusResult.isValid()) {
                    // 状态码不是 200，返回 null 表示失败
                    return null;
                }

                // 3. 提取 data 字段
                if (root.has("data")) {
                    JsonNode data = root.get("data");
                    if (data.isTextual()) return data.asText();
                    return data.toString();
                }

                // 4. 如果找不到已知键，尝试返回文本形式
                if (root.isTextual()) return root.asText();

                // 5. 返回原始 JSON 作为兜底
                return rawJson;
            } catch (Exception e) {
                // 解析失败——返回 null 表示失败
                return null;
            }
        }

        /**
         * 验证响应状态码
         * @param root JSON 根节点
         * @return 状态码验证结果
         */
        public static StatusCodeResult validateStatusCode(JsonNode root) {
            if (root.has("code")) {
                JsonNode code = root.get("code");
                int statusCode = code.asInt();
                return new StatusCodeResult(statusCode == 200, statusCode);
            }
            // 没有 code 字段时，假设响应有效（兼容旧格式）
            return new StatusCodeResult(true, 200);
        }

        /**
         * 状态码验证结果类
         */
        public static class StatusCodeResult {
            private final boolean valid;
            private final int statusCode;

            public StatusCodeResult(boolean valid, int statusCode) {
                this.valid = valid;
                this.statusCode = statusCode;
            }

            public boolean isValid() {
                return valid;
            }

            public int getStatusCode() {
                return statusCode;
            }
        }

        public static List<String> processingReader(String content){
            Document document = Jsoup.parse(content);
            List<String> orderedText = new ArrayList<>();
            traverseAllTags(document, orderedText);
            return orderedText;
        }

        private static void traverseAllTags(Node parentNode, List<String> resultList) {
            for (Node childNode : parentNode.childNodes()) {
                    String tagContent = childNode.outerHtml();
                    resultList.add(tagContent);
                    traverseAllTags(childNode, resultList);
            }
        }

        /**
         * 统一错误响应格式：
         * {
         *   "success": false,
         *   "error": "Error message description",
         *   "code": "ERROR_CODE",
         *   "details": { ... }
         * }
         */
        public static String buildErrorResponse(String error, String code, Map<String, Object> details) {
            try {
                ObjectNode root = MAPPER.createObjectNode();
                root.put("success", false);
                root.put("error", error);
                root.put("code", code);
                ObjectNode detailsNode = root.putObject("details");
                if (details != null) {
                    details.forEach((k, v) -> detailsNode.putPOJO(k, v));
                }
                return MAPPER.writeValueAsString(root);
            } catch (Exception e) {
                // 最后兜底，构造极简错误字符串
                return String.format("{\"success\":false,\"error\":\"%s\",\"code\":\"%s\"}", "Serialization failure", "FATAL_ERROR");
            }
        }

        /**
         * 使用枚举构建错误响应
         */
        public static String buildErrorResponse(ErrorCodeEnum errorCodeEnum, Map<String, Object> details) {
            return buildErrorResponse(errorCodeEnum.getMessage(), errorCodeEnum.getCode(), details);
        }

        /**
         * 构建翻译文件路径（在扩展名前插入 _translated）
         * @param originalPath 原始文件路径
         * @return 翻译后的文件路径
         */
        public static String buildTranslatedPath(String originalPath) {
            if (originalPath == null) return null;
            int lastDot = originalPath.lastIndexOf('.');
            if (lastDot > 0) {
                return originalPath.substring(0, lastDot) + "_translated" + originalPath.substring(lastDot);
            }
            return originalPath + "_translated";
        }

        /**
         * 使用枚举构建简单错误响应
         */
        public static String buildSimpleErrorResponse(ErrorCodeEnum errorCodeEnum) {
            return buildErrorResponse(errorCodeEnum.getMessage(), errorCodeEnum.getCode(), null);
        }
    }