import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zz.framework.constant.AppConstant;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;

/**
 * json工具
 *
 * @author Gao Zhengxing
 * @date 2022-04-29  18:18
 */
@Slf4j
public class JsonUtil {

    private JsonUtil() {
    }

    /**
     * 对象转Map (fastjson 方式)
     *
     * @param bean 需要转换的bean
     * @return
     */
    public static Map<String, Object> fastJsonBean2Map(Object bean) {
        return JSON.parseObject(JSON.toJSONString(bean),
                new TypeReference<>() {
                });
    }

    /**
     * 对象转Map (fastjson 方式) 转换为x_x 蛇形格式
     *
     * @param bean 需要转换的bean
     * @return
     */
    public static Map<String, Object> javaBean2SnakeMap(Object bean) {
        return JSON.parseObject(JSON.toJSONString(bean, Singleton.INSTANCE.getSnakeCaseSerializeConfig()),
                new TypeReference<>() {
                });
    }

    /**
     * 比较2个json数据格式是否一致
     *
     * @param sourceJsonObj   json模板
     * @param responseJsonObj 调用接口组合的json返回值
     * @return
     */
    public static boolean compareFormat(JSONObject sourceJsonObj, JSONObject responseJsonObj) {
        StringBuilder errorMessage = new StringBuilder();
        containsJsonObject(sourceJsonObj, responseJsonObj, errorMessage);
        if (errorMessage.length() > 0) {
            log.error("JsonUtil#compareFormat 比较json错误信息:" + errorMessage);
            return false;
        }
        return true;
    }

    /**
     * @param sourceJsonObj   来源数据
     * @param responseJsonObj 与返回数据k
     * @param errorMessage    错误信息
     */
    public static void containsJsonObject(JSONObject sourceJsonObj, JSONObject responseJsonObj, StringBuilder errorMessage) {
        Set<String> responseSet = responseJsonObj.keySet();
        Set<String> sourceSet0 = sourceJsonObj.keySet();
        //报告模板包含返回报告
        if (!sourceSet0.isEmpty() && !responseSet.isEmpty() && sourceSet0.equals(responseSet)) {
            for (String key : responseSet) {
                Object responseObj = responseJsonObj.get(key);
                Object sourceObj = sourceJsonObj.get(key);
                //来源和返回都是最终value
                if (judgeSourceAndResponseIsValue(sourceObj, responseObj)) {
                    boolean responseObjIsEmpty = responseObj == null || responseObj.toString().length() == 0;
                    //如果与返回数据k为空, 使用默认值
                    if (responseObjIsEmpty && sourceObj != null) {
                        responseJsonObj.put(key, sourceObj);
                    }
                } else {
                    sourceContainsResponse(key, null, errorMessage, sourceObj, responseObj);
                }
            }
        } else {
            errorMessage.append("模板数据key:" + sourceSet0 + "与返回数据key:" + responseSet + "不匹配. ");
        }
    }

    /**
     * 来源和返回都是最终value
     *
     * @param sourceObj
     * @param responseObj
     * @return
     */
    static boolean judgeSourceAndResponseIsValue(Object sourceObj, Object responseObj) {
        //responseObj 为最终value 不能继续递归为JSONObject或JSONArray
        boolean judgeResponseObj = responseObj instanceof JSONObject || responseObj instanceof JSONArray;
        boolean judgeSourceObj = sourceObj instanceof JSONObject || sourceObj instanceof JSONArray;
        return !judgeResponseObj && !judgeSourceObj;
    }

    /**
     * 递归判断
     *
     * @param key          JSONObject 的参数
     * @param size         JSONArray 的参数
     * @param errorMessage
     * @param sourceObj
     * @param responseObj
     */
    static void sourceContainsResponse(String key, Integer size, StringBuilder errorMessage, Object sourceObj, Object responseObj) {
        if (responseObj instanceof JSONObject && sourceObj instanceof JSONObject) {
            //保留value为null的key
            String responseStr = JSON.toJSONString(responseObj, SerializerFeature.WriteMapNullValue);
            JSONObject responseJson = JSON.parseObject(responseStr);
            JSONObject sourceJson = JSON.parseObject(sourceObj.toString());
            containsJsonObject(sourceJson, responseJson, errorMessage);
        } else if (responseObj instanceof JSONArray && sourceObj instanceof JSONArray) {
            //保留value为null的key
            String responseStr = JSON.toJSONString(responseObj, SerializerFeature.WriteMapNullValue);
            JSONArray responseJson = JSON.parseArray(responseStr);
            JSONArray sourceJson = JSON.parseArray(sourceObj.toString());
            containsJsonArray(sourceJson, responseJson, errorMessage);
        } else {
            if (key == null) {
                errorMessage.append("第" + size + "个" + sourceObj + "层数据格式不匹配" + responseObj + ". ");
            } else {
                errorMessage.append(key + "层数据格式不匹配" + ". ");
            }
        }
    }


    /**
     * @param sourceJsonObj   来源数据
     * @param responseJsonObj 与返回数据k
     * @param errorMessage    错误信息
     */
    public static void containsJsonArray(JSONArray sourceJsonObj, JSONArray responseJsonObj, StringBuilder errorMessage) {
        //报告模板包含返回报告
        if (!sourceJsonObj.isEmpty() && !responseJsonObj.isEmpty() && sourceJsonObj.size() == responseJsonObj.size()) {
            for (int i = 0; i < responseJsonObj.size(); i++) {
                Object responseObj = responseJsonObj.get(i);
                Object sourceObj = sourceJsonObj.get(i);
                //来源和返回为JSON格式
                if (!judgeSourceAndResponseIsValue(sourceObj, responseObj)) {
                    sourceContainsResponse(null, i, errorMessage, sourceObj, responseObj);
                }
            }
        } else {
            errorMessage.append("模板数据:" + sourceJsonObj + "与返回数据:" + responseJsonObj + "不匹配. ");
        }
    }

}