package com.infoepoch.pms.agent.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Json工具类
 *
 * @author 余浩
 * @date 2019-07-02
 * @vision 1.0
 */
public class JsonUtils {

    private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);

    // 定义 ObjectMappe 对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        MAPPER.registerModule(new JavaTimeModule());
        MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 私有构造器，禁止外部实例化。
     */
    private JsonUtils() {
    }

    /**
     * java 对象转换为 json 字符串
     *
     * @param objectData java 对象
     * @return String    json 字符串
     */
    public static String objectToJson(Object objectData) {
        try {
            String string = MAPPER.writeValueAsString(objectData);
            return string;
        } catch (JsonProcessingException e) {
            logger.info("java 对象转换为 json 字符串 出错:{}", e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * json 字符串转换为 java 对象
     *
     * @param jsonData json 字符串
     * @param beanType java 对象类型
     * @return T
     */
    public static <T> T jsonToObject(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("json 字符串转换为 java 对象 出错:", e);
            throw new RuntimeException("JSON字符转换失败！");
        }
    }

    public static <T> T jsonToObject(String jsonData, TypeReference<T> typeReference) {
        try {
            T t = MAPPER.readValue(jsonData, typeReference);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("json 字符串转换为 java 对象 出错:", e);
            throw new RuntimeException("JSON字符转换失败！");
        }
    }

    /**
     * jsonNode 转换为 java 对象
     *
     * @param jsonNode jsonNode对象
     * @param beanType java 对象类型
     * @param <T>
     * @return
     */
    public static <T> T jsonNodeToObject(JsonNode jsonNode, Class<T> beanType) {
        String jsonData = objectToJson(jsonNode);
        return jsonToObject(jsonData, beanType);
    }

    /**
     * java 对象转换为 JsonNode
     *
     * @param data java 对象
     * @return JsonNode
     */
    public static JsonNode objectToJsonNode(Object data) {
        JsonNode jsonNode = MAPPER.valueToTree(data);
        return jsonNode;
    }

    /**
     * json 字符串转换为 JsonNode
     *
     * @param jsonData json 字符串
     * @return JsonNode
     */
    public static JsonNode jsonToJsonNode(String jsonData) {
        try {
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            return jsonNode;
        } catch (IOException e) {
            logger.info("json 字符串转换为 JsonNode 出错:{}", e);
        }
        return null;
    }

    /**
     * json 字符串转换为包含 java 对象的 List
     *
     * @param jsonData json 字符串
     * @param beanType java 对象类型
     * @return List<T>
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            logger.info("json 字符串转换为包含 java 对象的 List 出错:{}", e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * JsonNode 对象转换为包含 java 对象的 List
     *
     * @param jsonNode JsonNode 对象
     * @param beanType java 对象类型
     * @return List<T>
     */
    public static <T> List<T> jsonNodeToList(JsonNode jsonNode, Class<T> beanType) {
        String jsonData = objectToJson(jsonNode);
        return jsonToList(jsonData, beanType);
    }

    // region 包含头信息json序列化

    private final static String JSON_HEAD = "version";
    private final static String JSON_HEAD_MESSAGE = "v1";
    private final static String JSON_BODY = "item";

    /**
     * 将json格式化
     */
    public static String formatToJson(String jsonStr) {
        return "{\"" + JSON_HEAD + "\":\"" + JSON_HEAD_MESSAGE + "\",\"" + JSON_BODY + "\":" + (io.micrometer.common.util.StringUtils.isNotBlank(jsonStr) ? jsonStr : "[]") + "}";
    }

    /**
     * 将集合转为json
     *
     * @param <T> 对象类型
     */
    public static <T> String toJson(List<T> items) {
        ObjectNode objectNode = new ObjectNode(JsonNodeFactory.instance);
        objectNode.put(JSON_HEAD, JSON_HEAD_MESSAGE);
        objectNode.set(JSON_BODY, new ObjectMapper().valueToTree(items));
        return JsonUtils.objectToJson(objectNode);
    }

    /**
     * 将json转为行集合
     *
     * @param <T> 对象类型
     */
    public static <T> List<T> parseJson(String jsonStr, Class<T> tClass) {
        JsonNode jsonNode = jsonToJsonNode(jsonStr);
        if (jsonNode == null || jsonNode.get(JSON_HEAD) == null)
            return null;
        String version = jsonNode.get(JSON_HEAD).asText();
        return JSON_HEAD_MESSAGE.equalsIgnoreCase(version) ? jsonNodeToList(jsonNode.get(JSON_BODY), tClass) : null;
    }

    // endregion

    public static String filterToString(SimpleFilterProvider simpleFilterProvider, Object object) {
        MAPPER.setFilterProvider(simpleFilterProvider);
        try {
            return MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            logger.info("序列化过滤错误！\n{}", printToJsonString(object));
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 美化JSON输出
     */
    public static String printToJsonString(Object object) {
        try {
            return "\n" + MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            logger.info("JSON打印异常。");
            e.printStackTrace();
        }
        return "";
    }

    public static Map<String, Object> jsonToMap(String jsonStr) {
        Map<String, Object> tmpMap = new HashMap<>();
        try {
            tmpMap = MAPPER.readValue(jsonStr, Map.class);
        } catch (Exception ex) {
            logger.info("JSON转换异常。");
            ex.printStackTrace();
        }
        return tmpMap;
    }

    public static Map<String, String> jsonToMapString(String jsonStr){
        Map<String, String> tmpMap = new HashMap<>();
        try {
            tmpMap = MAPPER.readValue(jsonStr, new TypeReference<Map<String, String>>() {});
        } catch (Exception ex) {
            logger.info("JSON转换异常。");
            ex.printStackTrace();
        }
        return tmpMap;
    }

    public static List<Map<String, Object>> jsonToMapList(String jsonStr) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        try {
            mapList = MAPPER.readValue(jsonStr, new TypeReference<List<Map<String, Object>>>() {
                @Override
                public Type getType() {
                    return super.getType();
                }
            });
        } catch (Exception ex) {
            logger.info("JSON转换异常。");
            ex.printStackTrace();
        }
        return mapList;
    }

}
