package com.quantgroup.asset.distribution.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nullable;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author : shj
 * TIME: 2020/7/1 14:31
 * DESCRIPTION:
 */
@Slf4j
public class JacksonUtil {
    public static final ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.disable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
        mapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // 序列化不需要null的
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    }

    public static String serialize(Object data) {
        try {
            return mapper.writeValueAsString(data);
        } catch (IOException e) {
            log.error("serialize data error", e);
            return null;
        }
    }

    public static <T> T deserialize(String content, Class<T> clazz) {
        try {
            if (StringUtils.isEmpty(content)) {
                return null;
            }
            return mapper.readValue(content, clazz);
        } catch (IOException e) {
            log.error("deserialize object error: {}", content, e);
            return null;
        }
    }

    public static <T> T deserialize(String content, TypeReference<T> clazz) {
        try {
            return mapper.readValue(content, clazz);
        } catch (IOException e) {
            log.error("deserialize object error: {}", content, e);
            return null;
        }
    }

    public static void main(String[] args) {
        String s = "{ \"guarantee\": {\n" +
                "    \"3\": \"0.014179\",\n" +
                "    \"6\": \"0.012641\",\n" +
                "    \"9\": \"0.012263\",\n" +
                "    \"12\": \"0.012173\"\n" +
                "  }\n" +
                "}";

        Map<String, Object> guaranteeMap = JacksonUtil.deserialize(s, new TypeReference<Map<String, Object>>() {
        });
        System.out.println((LinkedHashMap<Integer,BigDecimal>)guaranteeMap.get("guarantee"));
    }

    public static <K, V> Map<K, V> deserializeMap(String content, Class<K> clazzKey, Class<V> clazzValue) {
        try {
            JavaType javaType = mapper.getTypeFactory().constructParametricType(Map.class, clazzKey, clazzValue);
            return mapper.readValue(content, javaType);
        } catch (IOException e) {
            log.error("deserialize with java type object error: {}", content, e);
            return null;
        }
    }

    public static <T> List<T> deserializeList(String content, Class<T> elementClass) {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, elementClass);
        List<T> t = Lists.newArrayList();
        try {
            t = mapper.readValue(content, javaType);
        } catch (Exception e) {
            log.error("deserialize list with java type object error: {}", content, e);
        }
        return t;
    }

    public static <T> Set<T> deserializeSet(String content, Class<T> elementClass) {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(Set.class, elementClass);
        Set<T> t = Sets.newHashSet();
        try {
            t = mapper.readValue(content, javaType);
        } catch (Exception e) {
            log.error("deserialize set with java type object error: {}", content, e);
        }
        return t;
    }

    public static String timeStampSerialize(Object data) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.disable(SerializationFeature.INDENT_OUTPUT);
            objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
            return objectMapper.writeValueAsString(data);
        } catch (IOException e) {
            log.error("serialize data error", e);
            return null;
        }
    }

    @Nullable
    public static JsonNode readTree(String content) {
        JsonNode ret = null;
        try {
            ret = mapper.readTree(content);
        } catch (IOException e) {
            log.error("readTree io exception: ", e);
        }
        return ret;
    }
}
