package com.benyun.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

import java.io.IOException;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/************************************************
 * Copyright (c)  by goldensoft
 * All right reserved.
 * Create Date: 2018-8-15
 * Create Author: fengwang
 * File Name:  json工具
 * Last version:  1.0
 * Function:这里写注释
 * Last Update Date:
 * Change Log:
 **************************************************/

public class JsonUtil {
    private static JsonUtil allJsonUtil;
    private static JsonUtil notNullJsonUtil;
    private static JsonUtil notDefJsonUtil;
    private static JsonUtil notEmpJsonUtil;

    public JsonUtil() {

    }

    public static JsonUtil getAllJsonUtil() {
        return allJsonUtil;
    }

    public static void setAllJsonUtil(JsonUtil allJsonUtil) {
        JsonUtil.allJsonUtil = allJsonUtil;
    }

    public static JsonUtil getNotNullJsonUtil() {
        return notNullJsonUtil;
    }

    public static void setNotNullJsonUtil(JsonUtil notNullJsonUtil) {
        JsonUtil.notNullJsonUtil = notNullJsonUtil;
    }

    public static JsonUtil getNotDefJsonUtil() {
        return notDefJsonUtil;
    }

    public static void setNotDefJsonUtil(JsonUtil notDefJsonUtil) {
        JsonUtil.notDefJsonUtil = notDefJsonUtil;
    }

    public static JsonUtil getNotEmpJsonUtil() {
        return notEmpJsonUtil;
    }

    public static void setNotEmpJsonUtil(JsonUtil notEmpJsonUtil) {
        JsonUtil.notEmpJsonUtil = notEmpJsonUtil;
    }

    private static final Map<String, JsonUtil> INSTANCES = new HashMap<>();

    private static ObjectMapper mapper;

    static {
        mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME));
        mapper.registerModule(javaTimeModule);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        setTimeZone(Calendar.getInstance().getTimeZone());
    }

    static JsonUtil pick(String instanceId) {
        return INSTANCES.computeIfAbsent(instanceId, k -> new JsonUtil());
    }

    public static void setTimeZone(TimeZone tz) {
        mapper.setTimeZone(tz);
    }

    public static String toJsonString(Object obj) {
        if (obj instanceof String) {
            return (String) obj;
        } else {
            try {
                return mapper.writeValueAsString(obj);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }



    public static <E> List<E> toList(Object obj, Class<E> clazz) {
        return (List<E>) toGeneric(obj, List.class, clazz);
    }

    public static <E> Set<E> toSet(Object obj, Class<E> clazz) {
        return (Set<E>) toGeneric(obj, Set.class, clazz);
    }

    public static <K, V> Map<K, V> toMap(Object obj, Class<K> keyClazz, Class<V> valueClazz) {
        return (Map<K, V>) toGeneric(obj, Map.class, keyClazz, valueClazz);
    }

    public static Object toGeneric(Object obj, Class<?> parametrized, Class... parameterClasses) {
        JavaType type = mapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
        return toGeneric(obj, type);
    }

    private static Object toGeneric(Object obj, JavaType type) {
        try {
            if (obj instanceof String) {
                return mapper.readValue((String) obj, type);
            } else if (obj instanceof JsonNode) {
                return mapper.readValue(obj.toString(), type);
            } else {
                return mapper.readValue(mapper.writeValueAsString(obj), type);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <E> E toObject(Object obj, Class<E> clazz) {
        try {
            if (obj instanceof String) {
                if (clazz == String.class) {
                    return (E) obj;
                } else {
                    return mapper.readValue((String) obj, clazz);
                }
            } else if (obj instanceof JsonNode) {
                return mapper.readValue(obj.toString(), clazz);
            } else {
                return mapper.readValue(mapper.writeValueAsString(obj), clazz);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void setMapper(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    public JsonUtil(JsonInclude.Include include) {
        mapper = new ObjectMapper();
        mapper.setSerializationInclusion(include);
        //设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //禁止使用int代表Enum的order()來反序列化Enum,非常危險
        mapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
        //mapper.setSerializerProvider(p);

        //增加对map的过滤
        switch (include) {
            case NON_NULL:
            case NON_EMPTY:
                mapper.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
            default:
                break;
        }
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Date.class, new CustomDateDeserializer<Date>());
        mapper.registerModule(module);
        setDateFormat("yyyy-MM-dd HH:mm:ss");

    }

    @SuppressWarnings("hiding")
    public class CustomDateDeserializer<Date> extends DateDeserializers.DateDeserializer {
        /**
         *
         */
        private static final long serialVersionUID = -3912203293075877780L;

        @Override
        public java.util.Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            try {
                return super.deserialize(jp, ctxt);
            } catch (JsonMappingException e) {
                return retryParse(jp.getText());
            }
        }

        private java.util.Date retryParse(String dateStr) {

            if (StringUtils.isBlank(dateStr)) return null;

            try {
                if (dateStr.length() == DateUtils.YYYY_MM_DD.length()) {
                    return new SimpleDateFormat(DateUtils.YYYY_MM_DD).parse(dateStr);
                } else if (dateStr.length() == DateUtils.DATESTOREFORMAT.length()) {
                    return new SimpleDateFormat(DateUtils.DATESTOREFORMAT).parse(dateStr);
                } else if (dateStr.length() == DateUtils.YYYYMMDDHHMMSS.length()) {
                    return new SimpleDateFormat(DateUtils.YYYYMMDDHHMMSS).parse(dateStr);
                }
            } catch (Exception e) {
                return null;
            }
            return null;
        }
    }

    /**
     * 创建输出全部属性
     *
     * @return
     */
    public static JsonUtil buildNormalBinder() {
        synchronized (JsonUtil.class) {
            if (JsonUtil.allJsonUtil == null) {
                JsonUtil.allJsonUtil = new JsonUtil(JsonInclude.Include.ALWAYS);
            }
        }
        return JsonUtil.allJsonUtil;
    }

    /**
     * 创建只输出非空属性的
     *
     * @return
     */
    public static JsonUtil buildNonNullBinder() {
        synchronized (JsonUtil.class) {
            if (JsonUtil.notNullJsonUtil == null) {
                JsonUtil.notNullJsonUtil = new JsonUtil(JsonInclude.Include.NON_NULL);
            }
        }
        return JsonUtil.notNullJsonUtil;
    }

    /**
     * 创建只输出初始值被改变的属性
     *
     * @return
     */
    public static JsonUtil buildNonDefaultBinder() {
        synchronized (JsonUtil.class) {
            if (JsonUtil.notDefJsonUtil == null) {
                JsonUtil.notDefJsonUtil = new JsonUtil(JsonInclude.Include.NON_DEFAULT);
            }
        }
        return JsonUtil.notDefJsonUtil;
    }

    /**
     * 创建只输出初始值被改变的属性
     *
     * @return
     */
    public static JsonUtil buildNonEmptyBinder() {
        synchronized (JsonUtil.class) {
            if (JsonUtil.notEmpJsonUtil == null) {
                JsonUtil.notEmpJsonUtil = new JsonUtil(JsonInclude.Include.NON_EMPTY);
            }
        }
        return JsonUtil.notEmpJsonUtil;
    }

    /**
     * 把json字符串转成对象
     *
     * @param json
     * @param clazz
     * @return
     */
    public <T> T getJsonToObject(String json, Class<T> clazz) {
        T object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, clazz);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成list
     *
     * @param json  [{"...":"...","...":"...","...":"..."}]
     * @param clazz map
     * @return
     */
    @SuppressWarnings({"rawtypes"})
    public Object getJsonToList(String json, Class clazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, clazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    public <T, P extends List<T>> List<T> getList(String json, Class<P> collectionType, Class<T> clazz) {
        if (StringUtils.isBlank(json)) {
            return Collections.emptyList();
        }
        try {
            return getMapper().readValue(json, TypeFactory.defaultInstance().constructCollectionType(collectionType, clazz));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 把JSON转成list中是MAP《String，clazz》
     *
     * @param json
     * @param clazz
     * @return
     */
    @SuppressWarnings({"rawtypes"})
    public Object getJsonToListByMap(String json, Class clazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructArrayType(TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, clazz)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }



    /**
     * 功能描述: <br>           把utf-8字符串转成  Unicode编码的字符串
     * * 〈〉
     *
     * @Param: [gbString]
     * @Return: java.lang.String
     * @Author: Mr_Feng
     * @Date: 2020/6/23 11:43
     */
    public static String str2unicode(final String gbString) {
        char[] utfBytes = gbString.toCharArray();
        String unicodeBytes = "";
        for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) {
            String hexB = Integer.toHexString(utfBytes[byteIndex]);
            if (hexB.length() <= 2) {
                hexB = "00" + hexB;
            }
            unicodeBytes = unicodeBytes + "\\\\u" + hexB;
        }
        return unicodeBytes;
    }

    @SuppressWarnings({"rawtypes"})
    public Object[] getJsonToArray(String json, Class clazz) {
        Object[] object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructArrayType(clazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    public byte[] getJsonTobyteArray(String json) {
        byte[] object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructArrayType(byte.class));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成Map
     *
     * @param json
     * @param keyclazz
     * @param valueclazz
     * @return
     */
    @SuppressWarnings({"rawtypes", "deprecation"})
    public Object getJsonToMap(String json, Class keyclazz, Class valueclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructParametricType(HashMap.class, keyclazz, valueclazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成Map(有序)
     *
     * @param json
     * @param keyclazz
     * @param valueclazz
     * @return
     */
    @SuppressWarnings({"rawtypes", "deprecation"})
    public Object getJsonToLinkedMap(String json, Class keyclazz, Class valueclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructParametricType(LinkedHashMap.class, keyclazz, valueclazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成并发Map
     *
     * @param json
     * @param keyclazz
     * @param valueclazz
     * @return
     */
    @SuppressWarnings({"rawtypes", "deprecation"})
    public Object getJsonToConcMap(String json, Class keyclazz, Class valueclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructParametricType(ConcurrentHashMap.class, keyclazz, valueclazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成Map<> value是MAP类型(KEY string )
     *
     * @param json
     * @param keyclazz
     * @param valueclazz MAP中的value CLASS
     * @return
     */
    @SuppressWarnings("rawtypes")
    public Object getJsonToMapByMap(String json, Class keyclazz, Class valueclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructMapType(HashMap.class, TypeFactory.defaultInstance().uncheckedSimpleType(keyclazz), TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, valueclazz)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把JSON转成Map<> value是LIST类型
     *
     * @param json
     * @param keyclazz
     * @param valueclazz LIST中的CLASS
     * @return
     */
    @SuppressWarnings("rawtypes")
    public Object getJsonToMapByList(String json, Class keyclazz, Class valueclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructMapType(HashMap.class, TypeFactory.defaultInstance().uncheckedSimpleType(keyclazz), TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, valueclazz)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把json格式数据装成map
     *
     * @param str
     * @return
     */
    public  Map<String, String> getJsonToMap(String str) {
        Map<String, String> map = new HashMap<String, String>();
        if (StringUtils.isNotBlank(str)) {
            String[] s = str.split(",");
            if (s.length > 0) {
                for (int i = 0; i < s.length; i++) {
                    String con = s[i];
                    int s1 = con.indexOf(":");
                    if (s1 > 0) {
                        map.put(con.substring(0, s1).trim().replace("\"", ""), con.substring(s1 + 1).replace("\"", ""));
                    } else {
                        map.put(con.trim().replace("\"", ""), "");
                    }
                }
            }
        }
        return map;
    }

    /**
     * 把map转成combo数据格式的json格式
     *
     * @return String (json)
     */
    public String getMapToJson(Map<String, String> map) {
        List<String[]> list = new ArrayList<String[]>();
        if (null != map && !map.isEmpty()) {
            for (String key : map.keySet()) {
                String[] strS = new String[2];
                strS[0] = key;
                strS[1] = map.get(key);
                list.add(strS);
            }
        }
        return jsonObject(list);
    }

    /**
     * 把对象转成json格式
     *
     * @param list 需要转的对象
     * @return String
     */
    @SuppressWarnings("rawtypes")
    public String jsonObject(List list) {
        StringWriter sw = new StringWriter();
        JsonGenerator gen;
        try {
            gen = new JsonFactory().createGenerator(sw);
            getMapper().writeValue(gen, list);
            gen.close();
        } catch (Exception e) {

        }
        return sw.toString();
    }

    /**
     * 把JSON转成Object
     *
     * @param json
     * @param objclazz
     * @param pclazz
     * @return
     */
    @SuppressWarnings({"rawtypes", "deprecation"})
    public Object getJsonToObject(String json, Class objclazz, Class... pclazz) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, TypeFactory.defaultInstance().constructParametricType(objclazz, pclazz));
            } catch (Exception e) {
            }
        }
        return object;
    }

    /**
     * 把JSON转成Object
     *
     * @param <T>
     * @param json
     * @param typeReference
     * @return
     */
    public <T> Object getJsonToObject(String json, TypeReference<T> typeReference) {
        Object object = null;
        if (StringUtils.isNotBlank(json)) {
            try {
                object = getMapper().readValue(json, typeReference);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return object;
    }

    /**
     * 把对象转成字符串
     *
     * @param object
     * @return
     */
    public String toJson(Object object) {
        String json = null;
        try {
            json = getMapper().writeValueAsString(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return json;
    }

    /**
     * 设置日期格式
     *
     * @param pattern
     */
    public void setDateFormat(String pattern) {
        if (StringUtils.isNotBlank(pattern)) {
            DateFormat df = new SimpleDateFormat(pattern);
            getMapper().setDateFormat(df);
            getMapper().setTimeZone(TimeZone.getDefault());
        }
    }

    public static Object getResultObject(String json) {
//    	Map<String, Object> map = (Map<String, Object>) buildNormalBinder().getJsonToMap(json, String.class, Object.class);
//    	if (map != null ) {
//    		return map.get("result");
//    	}else {
        return json;
//    	}
    }
    public static JsonNode path(JsonNode jsonNode, String pathStr) {
        String[] splitPaths = pathStr.split("\\.");
        jsonNode = jsonNode.path(splitPaths[0]);
        if (jsonNode instanceof MissingNode) {
            return null;
        } else if (splitPaths.length == 1) {
            return jsonNode;
        } else {
            return path(jsonNode, pathStr.substring(pathStr.indexOf(".") + 1));
        }
    }

    public static ObjectNode createObjectNode() {
        return mapper.createObjectNode();
    }

    public static ArrayNode createArrayNode() {
        return mapper.createArrayNode();
    }

    public static ObjectMapper getMapper() {
        return mapper;
    }

    public static Map<String, JsonUtil> getINSTANCES() {
        return INSTANCES;
    }
}
