package com.njzscloud.common.core.jackson;

import cn.hutool.core.date.DatePattern;
import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.core.jackson.serializer.BigDecimalModule;
import com.njzscloud.common.core.jackson.serializer.LongModule;
import com.njzscloud.common.core.jackson.serializer.TimeModule;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Jackson 工具<br/>
 * 从 Spring 中获取 ObjectMapper
 */
@Slf4j
public class Jackson {
    private static final ObjectMapper objectMapper;
    private static final XmlMapper xmlMapper;

    static {
        ObjectMapper temp;
        try {
            temp = SpringUtil.getBean(ObjectMapper.class);
        } catch (Throwable e) {
            log.warn("从 Spring 中获取 ObjectMapper 失败");
            temp = createObjectMapper();
        }
        objectMapper = temp;
        XmlMapper _xmlMapper;
        try {
            _xmlMapper = SpringUtil.getBean(XmlMapper.class);
        } catch (Throwable e) {
            log.warn("从 Spring 中获取 XmlMapper 失败");
            _xmlMapper = createXmlMapper();
        }
        xmlMapper = _xmlMapper;
    }


    /**
     * 序列化为 JSON 字符串
     *
     * @param o 数据
     * @return String
     */
    public static String toJsonStr(Object o) {
        try {
            return objectMapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            // log.error("Jackson 序列化失败", e);
            throw Exceptions.error(e, "Jackson 序列化失败");
        }
    }

    /**
     * 序列化为 JSON 字节数组
     *
     * @param o 数据
     * @return byte[]
     */
    public static byte[] toJsonBytes(Object o) {
        try {
            return objectMapper.writeValueAsBytes(o);
        } catch (JsonProcessingException e) {
            // log.error("Jackson 序列化失败", e);
            throw Exceptions.error(e, "Jackson 序列化失败");
        }
    }

    /**
     * 反序列化(泛型支持)<br/>
     * 如: new TypeReference&lt;List&lt;String&gt;&gt;(){}, 类型对象建议缓存
     *
     * @param json json JSON 字符串
     * @param type 类型
     * @return T
     * @see TypeReference
     */
    public static <T> T toBean(String json, Type type) {
        try {
            return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
        } catch (JsonProcessingException e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }

    public static <T> T toBean(InputStream json, Type type) {
        try {
            return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
        } catch (Exception e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }

    public static <T> T toBean(byte[] json, Type type) {
        try {
            return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
        } catch (Exception e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }


    /**
     * 序列化为 JSON 字符串
     *
     * @param o 数据
     * @return String
     */
    public static String toXmlStr(Object o) {
        try {
            return xmlMapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            // log.error("Jackson 序列化失败", e);
            throw Exceptions.error(e, "Jackson 序列化失败");
        }
    }

    /**
     * 序列化为 JSON 字节数组
     *
     * @param o 数据
     * @return byte[]
     */
    public static byte[] toXmlBytes(Object o) {
        try {
            return xmlMapper.writeValueAsBytes(o);
        } catch (JsonProcessingException e) {
            // log.error("Jackson 序列化失败", e);
            throw Exceptions.error(e, "Jackson 序列化失败");
        }
    }

    public static <T> T xmlToBean(String json, Type type) {
        try {
            return xmlMapper.readValue(json, xmlMapper.getTypeFactory().constructType(type));
        } catch (JsonProcessingException e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }

    public static <T> T xmlToBean(InputStream json, Type type) {
        try {
            return xmlMapper.readValue(json, xmlMapper.getTypeFactory().constructType(type));
        } catch (Exception e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }

    public static <T> T xmlToBean(byte[] json, Type type) {
        try {
            return xmlMapper.readValue(json, xmlMapper.getTypeFactory().constructType(type));
        } catch (Exception e) {
            // log.error("Jackson 反序列化失败", e);
            throw Exceptions.error(e, "Jackson 反序列化失败");
        }
    }

    /**
     * 创建 ObjectMapper
     *
     * @return ObjectMapper
     */
    private static ObjectMapper createObjectMapper() {
        return new ObjectMapper()
                .setLocale(Locale.CHINA)
                .setTimeZone(TimeZone.getTimeZone("GMT+8"))
                .setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN))
                .setSerializationInclusion(JsonInclude.Include.ALWAYS)
                // .configure(SerializationFeature.INDENT_OUTPUT, true) // 格式化输出
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true) // 对Map中的KeyValue按照Key做排序后再输出。在有些验签的场景需要使用这个Feature
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                // .configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true)
                .configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true)
                .registerModules(new TimeModule(), new LongModule(), new BigDecimalModule())
                ;
    }


    private static XmlMapper createXmlMapper() {
        return XmlMapper.xmlBuilder()
                .defaultLocale(Locale.CHINA)
                .defaultTimeZone(TimeZone.getTimeZone("GMT+8"))
                .defaultDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN))
                .serializationInclusion(JsonInclude.Include.ALWAYS)
                .configure(SerializationFeature.INDENT_OUTPUT, true)
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true) // 对Map中的KeyValue按照Key做排序后再输出。在有些验签的场景需要使用这个Feature
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .addModules(new TimeModule(), new LongModule(), new BigDecimalModule())
                .build()
                ;
    }

    /**
     * 获取 objectMapper
     *
     * @return ObjectMapper
     */
    public static ObjectMapper objectMapper() {
        return objectMapper;
    }

    public static XmlMapper xmlMapper() {
        return xmlMapper;
    }
}
