package org.jeecg.config.init;

import com.chanjx.utils.JsonUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @author 陈俊雄
 * @since 2020/7/28
 **/
@Configuration
public class JacksonConfig {

    @Autowired
    private ObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        // Jackson对LocalDateTime进行支持
        final JavaTimeModule javaTimeModule = new JavaTimeModule();
        JsonUtils.registerModule(javaTimeModule);
        objectMapper.registerModule(javaTimeModule);
        // Jackson序列化Date加上时区
        final StdDateFormat stdDateFormat = new StdDateFormat().withColonInTimeZone(true);
        JsonUtils.setDateFormat(stdDateFormat);
        objectMapper.setDateFormat(stdDateFormat);
        // 禁用将时间序列化成时间戳
        JsonUtils.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }

    /**
     * 将Long类型字段转Json字符串时转换为String类型防止前端Js精度丢失
     *
     * @return simpleModule
     */
    @Bean
    public Module getSerializerLong2String() {
        final SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        return simpleModule;
    }

    /**
     * 将Double类型字段转Json字符串时转换为String类型防止前端Js精度丢失
     *
     * @return simpleModule
     */
    @Bean
    public Module getSerializerDouble2String() {
        final SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Double.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Double.TYPE, ToStringSerializer.instance);
        return simpleModule;
    }

    /**
     * LocalDateTime序列化、反序列化支持
     *
     * @return javaTimeModule
     */
    @Bean
    public Module javaTimeModule() {
        return new JavaTimeModule();
    }

    /**
     * 时间戳与LocalDateTime互转
     *
     * @return module
     */
    // @Bean
    public Module getSerializerLocalDateTime2Timestamp() {
        final SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(LocalDateTime.class, LocalDateTime2TimestampSerializer.instance);
        simpleModule.addDeserializer(LocalDateTime.class, Timestamp2LocalDateTimeSerializer.instance);
        return simpleModule;
    }

    /**
     * LocalDateTime序列化时间戳实现
     */
    public static class LocalDateTime2TimestampSerializer extends StdSerializer<LocalDateTime> {
        final static LocalDateTime2TimestampSerializer instance = new LocalDateTime2TimestampSerializer();

        protected LocalDateTime2TimestampSerializer() {
            super(LocalDateTime.class);
        }

        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        }
    }

    /**
     * LocalDateTime反序列化时间戳实现
     */
    public static class Timestamp2LocalDateTimeSerializer extends StdDeserializer<LocalDateTime> {
        final static Timestamp2LocalDateTimeSerializer instance = new Timestamp2LocalDateTimeSerializer();

        protected Timestamp2LocalDateTimeSerializer() {
            super(LocalDateTime.class);
        }

        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return Instant.ofEpochMilli(p.getValueAsLong()).atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
    }
}
