package com.ym.im.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;

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

/**
 * Json对象操作工具
 *
 * @author 陈俊雄
 **/
public class JsonUtils {
    private static ObjectMapper MAPPER = new ObjectMapper()
            // 忽略Json对象在实体类中没有的字段
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    public static void setObjectMapper(ObjectMapper objectMapper) {
        MAPPER = objectMapper;
    }

    /**
     * 实体类转json字符串
     *
     * @param obj obj
     * @return jsonStr
     * @throws JsonProcessingException e
     */
    public static String obj2Json(Object obj) throws JsonProcessingException {
        return MAPPER.writeValueAsString(obj);
    }

    /**
     * 实体类转json字符串，并忽略实体类为空的字段
     *
     * @param obj obj
     * @return jsonStr
     * @throws JsonProcessingException e
     */
    public static String obj2JsonNonNull(Object obj) throws JsonProcessingException {
        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return MAPPER.writeValueAsString(obj);
    }

    /**
     * json字符串转实体类
     *
     * @param jsonData jsonStr
     * @param beanType Class
     * @param <T>      T
     * @return T
     * @throws IOException e
     */
    public static <T> T json2Obj(String jsonData, Class<T> beanType) throws IOException {
        return MAPPER.readValue(jsonData, beanType);
    }


    /**
     * json字符串转实体类
     *
     * @param jsonData jsonStr
     * @param javaType javaType可通过{@link #getJavaType}获取
     * @param <T>      T
     * @return T
     * @throws IOException e
     */
    public static <T> T json2Obj(String jsonData, JavaType javaType) throws IOException {
        return MAPPER.readValue(jsonData, javaType);
    }

    /**
     * json字符串转实体类
     * {@link #getJavaType(Class, JavaType...)}
     *
     * @param jsonData         jsonStr
     * @param parametrized     class
     * @param parameterClasses class[]
     * @param <T>              T
     * @return T
     * @throws IOException e
     */
    public static <T> T json2Obj(String jsonData, Class<?> parametrized, Class<?>... parameterClasses) throws IOException {
        return MAPPER.readValue(jsonData, getJavaType(parametrized, parameterClasses));
    }

    /**
     * 获取JavaType
     * 如：JsonUtils.getJavaType(String.class);
     *
     * @param type class
     * @return {@link JavaType}
     */
    public static JavaType getJavaType(Type type) {
        return MAPPER.getTypeFactory().constructType(type);
    }

    /**
     * 获取JavaType，常用于复杂对象
     * 如json转Map<String, Long>：
     * JsonUtils.getJavaType(Map.class, String.class, Long.class);
     * 更复杂的对象则是对上面示例进行嵌套，泛型同理
     * 如json转Map<String, Map<Long, List<Integer>>：
     * 首先使用{@link #getJavaType(Class, Class[])}获取List<Integer>的javaType
     * JavaType listType = JsonUtils.getJavaType(List.class, Integer.class);
     * 其次使用{@link #getJavaType(Class, JavaType...)}来创建Map的javaType
     * JavaType mapType = JsonUtils.getJavaType(Map.class, listType);
     * 最后使用{@link #json2Obj(String, JavaType)}将json字符串转换成map对象
     * Map<String, Map<Long, List<Integer>> map = JsonUtils.json2Obj(jsonStr, mapType);
     *
     * @param parametrized     class
     * @param parameterClasses class[]
     * @return {@link JavaType}
     */
    public static JavaType getJavaType(Class<?> parametrized, Class<?>... parameterClasses) {
        return MAPPER.getTypeFactory().constructParametricType(parametrized, parameterClasses);
    }

    /**
     * 获取JavaType，常用于复杂对象
     * 参考{@link #getJavaType(Class, Class[])}
     *
     * @param rawType        class
     * @param parameterTypes javaType[]
     * @return {@link JavaType}
     */
    public static JavaType getJavaType(Class<?> rawType, JavaType... parameterTypes) {
        return MAPPER.getTypeFactory().constructParametricType(rawType, parameterTypes);
    }

    /**
     * json字符串转Map
     *
     * @param jsonData jsonStr
     * @param k        key
     * @param v        value
     * @param <K>      key class
     * @param <V>      value class
     * @return map
     * @throws IOException e
     */
    public static <K, V> HashMap<K, V> json2HashMap(String jsonData, Class<K> k, Class<V> v) throws IOException {
        return MAPPER.readValue(jsonData, TypeFactory.defaultInstance().constructMapType(HashMap.class, k, v));
    }

    /**
     * json字符串转list
     *
     * @param jsonData jsonStr
     * @param t        class
     * @param <T>      T
     * @return list
     * @throws IOException e
     */
    public static <T> List<T> json2List(String jsonData, Class<T> t) throws IOException {
        return MAPPER.readValue(jsonData, TypeFactory.defaultInstance().constructCollectionType(List.class, t));
    }

    /**
     * map等对象转实体类，通过映射方式
     *
     * @param obj      obj
     * @param beanType class
     * @param <T>      T
     * @return T
     */
    public static <T> T obj2Class(Object obj, Class<T> beanType) {
        return MAPPER.convertValue(obj, beanType);
    }
}
