package com.yeejoin.amos.boot.module.jg.biz.edit.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.math.BigDecimal;
import java.util.Iterator;

public class JsonDiffUtil {

    public static boolean jsonEqualsIgnoreType(String json1, String json2) {
        ObjectMapper mapper = new ObjectMapper();
        // 处理输入的 null 和空字符串视为相等
        if (isNullOrEmpty(json1) && isNullOrEmpty(json2)) return true;
        if (isNullOrEmpty(json1) || isNullOrEmpty(json2)) return false;
        JsonNode node1 = null;
        try {
            node1 = mapper.readTree(json1);
            JsonNode node2 = mapper.readTree(json2);
            return equalsIgnoreType(node1, node2);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    private static boolean equalsIgnoreType(JsonNode node1, JsonNode node2) {
        // === 第1阶段：处理null值 ===
        // 情况1a：两个都是Java null（对象不存在）
        if (node1 == null && node2 == null) return true;

        // 情况1b：一个是Java null，另一个是JSON Null节点
        if (node1 == null) return node2.isNull();
        if (node2 == null) return node1.isNull();

        // === 第2阶段：处理JSON Null节点 ===
        // 现在确定两个node都不为null（Java对象层面）
        if (node1.isNull() || node2.isNull()) {
            // 只有两个都是JSON Null才相等
            return node1.isNull() && node2.isNull();
        }

        // === 第3阶段：类型不同时的转换比较 ===
        if (!node1.getNodeType().equals(node2.getNodeType())) {
            // 情况3a：数字与字符串数字比较（如 42 和 "42"）
            if (node1.isNumber() && node2.isTextual()) {
                try {
                    return node1.decimalValue().compareTo(new BigDecimal(node2.asText())) == 0;
                } catch (NumberFormatException e) {
                    return false;
                }
            }
            if (node2.isNumber() && node1.isTextual()) {
                try {
                    return node2.decimalValue().compareTo(new BigDecimal(node1.asText())) == 0;
                } catch (NumberFormatException e) {
                    return false;
                }
            }

            // 情况3b：布尔与字符串布尔比较（如 true 和 "true"）
            if (node1.isBoolean() && node2.isTextual()) {
                return node1.asBoolean() == Boolean.parseBoolean(node2.asText());
            }
            if (node2.isBoolean() && node1.isTextual()) {
                return node2.asBoolean() == Boolean.parseBoolean(node1.asText());
            }

            // 其他类型不匹配情况
            return false;
        }

        // === 第4阶段：相同类型详细比较 ===
        switch (node1.getNodeType()) {
            case OBJECT:
                if (node1.size() != node2.size()) return false;
                Iterator<String> fieldNames = node1.fieldNames();
                while (fieldNames.hasNext()) {
                    String fieldName = fieldNames.next();
                    JsonNode value2 = node2.get(fieldName);
                    if (value2 == null) return false; // key不存在
                    if (!equalsIgnoreType(node1.get(fieldName), value2)) {
                        return false;
                    }
                }
                return true;

            case ARRAY:
                if (node1.size() != node2.size()) return false;
                for (int i = 0; i < node1.size(); i++) {
                    if (!equalsIgnoreType(node1.get(i), node2.get(i))) {
                        return false;
                    }
                }
                return true;

            case STRING:
                // 字符串严格比较（区分大小写）
                return node1.asText().equals(node2.asText());

            case NUMBER:
                // 精确数字比较（避免浮点误差）
                return node1.decimalValue().compareTo(node2.decimalValue()) == 0;

            case BOOLEAN:
                return node1.asBoolean() == node2.asBoolean();

            case NULL:
                // 理论上不会执行到这里，因为前面已经处理过null
                return true;

            default:
                return false; // 未知类型不相等
        }
    }

    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().isEmpty() || "null".equals(str);
    }

}
