package com.ecep.contract.config;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Collections;

import org.hibernate.Hibernate;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import com.ecep.contract.model.IdentityEntity;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

/**
 * Jackson配置类，用于配置JSON序列化相关的设置，解决循环引用问题
 */
@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.build();

        // 关闭日期时间格式化输出为时间戳，而是输出为ISO格式的字符串
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 配置处理循环引用的策略，使用INDENT_OUTPUT格式化输出
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        // 处理循环引用，启用引用处理功能
        objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);

        // 配置Java 8时间模块的序列化格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        // LocalDate
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
        // LocalTime
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
        // LocalDateTime
        javaTimeModule.addSerializer(LocalDateTime.class,
                new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        javaTimeModule.addDeserializer(LocalDateTime.class,
                new LocalDateTimeDeserializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

        objectMapper.registerModule(javaTimeModule);

        // 添加自定义模块，用于处理JPA/Hibernate代理对象
        SimpleModule proxyModule = new SimpleModule("HibernateProxyModule");

        // 添加代理对象序列化器，只输出ID字段
        proxyModule.addSerializer(HibernateProxy.class, new HibernateProxySerializer());
        // 使用BeanSerializerModifier来处理IdentityEntity类型，避免递归调用
        proxyModule.setSerializerModifier(new BeanSerializerModifier() {
            @Override
            public JsonSerializer<?> modifySerializer(SerializationConfig config,
                    BeanDescription beanDesc,
                    JsonSerializer<?> serializer) {
                // 只对IdentityEntity类型进行修改
                if (IdentityEntity.class.isAssignableFrom(beanDesc.getBeanClass()) &&
                        !HibernateProxy.class.isAssignableFrom(beanDesc.getBeanClass())) {
                    return new IdentityEntitySerializer(serializer);
                }
                return serializer;
            }
        });

        objectMapper.registerModule(proxyModule);

        return objectMapper;
    }

    /**
     * 专门用于处理Hibernate代理对象的序列化器
     */
    private static class HibernateProxySerializer extends StdSerializer<HibernateProxy> {

        protected HibernateProxySerializer() {
            super(HibernateProxy.class);
        }

        @Override
        public void serialize(HibernateProxy value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            // 尝试初始化代理对象，如果未初始化则只输出ID
            try {
                Object unwrapped = value.getHibernateLazyInitializer().getImplementation();
                // 检查是否为IdentityEntity实现类
                if (unwrapped instanceof IdentityEntity) {
                    gen.writeStartObject();
                    gen.writeNumberField("id", ((IdentityEntity) unwrapped).getId());
                    gen.writeEndObject();
                } else {
                    // 如果不是IdentityEntity，使用默认序列化
                    serializers.defaultSerializeValue(unwrapped, gen);
                }
            } catch (Exception e) {
                // 如果初始化失败，只输出ID
                if (value instanceof IdentityEntity) {
                    gen.writeStartObject();
                    gen.writeNumberField("id", ((IdentityEntity) value).getId());
                    gen.writeEndObject();
                } else {
                    // 如果不是IdentityEntity，输出对象的基本信息
                    gen.writeStartObject();
                    gen.writeStringField("class", value.getClass().getName());
                    gen.writeEndObject();
                }
            }
        }
    }

    /**
     * 用于处理集合类型的序列化器，避免懒加载集合在会话关闭时无法序列化的问题
     */
    private static class CollectionSerializer extends StdSerializer<Collection<?>> {

        protected CollectionSerializer() {
            super((Class<Collection<?>>) (Class<?>) Collection.class);
        }

        @Override
        public void serialize(Collection<?> value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            // 检查集合是否为Hibernate的持久化集合
            if (value instanceof PersistentCollection) {
                PersistentCollection persistentCollection = (PersistentCollection) value;
                // 如果集合未初始化，返回空集合
                if (!persistentCollection.wasInitialized()) {
                    gen.writeStartArray();
                    gen.writeEndArray();
                    return;
                }
            }

            // 如果已初始化，使用默认序列化
            serializers.defaultSerializeValue(value, gen);
        }
    }

    /**
     * 用于处理IdentityEntity类型的序列化器包装器
     */
    private static class IdentityEntitySerializer extends StdSerializer<Object> {
        private final JsonSerializer<?> delegate;

        protected IdentityEntitySerializer(JsonSerializer<?> delegate) {
            super(Object.class);
            this.delegate = delegate;
        }

        @Override
        public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            // 对于IdentityEntity对象，如果未初始化，则只输出ID
            if (value instanceof IdentityEntity && !Hibernate.isInitialized(value)) {
                gen.writeStartObject();
                gen.writeNumberField("id", ((IdentityEntity) value).getId());
                gen.writeStringField("_proxy_", value.getClass().getName());
                gen.writeEndObject();
            } else {
                // 已初始化的实体，使用原始的序列化器进行序列化，避免递归调用
                ((JsonSerializer<Object>) delegate).serialize(value, gen, serializers);
            }
        }
    }

    /**
     * 用于处理对象引用的序列化器，通过检测和管理对象引用避免循环引用问题
     */
    private static class IdentityReferenceSerializer extends StdSerializer<Object> {
        private final JsonSerializer<?> delegate;
        private final ThreadLocal<java.util.Set<Object>> visitedObjects = ThreadLocal
                .withInitial(java.util.HashSet::new);

        protected IdentityReferenceSerializer(JsonSerializer<?> delegate) {
            super(Object.class);
            this.delegate = delegate;
        }

        @Override
        public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            // 处理null值
            if (value == null) {
                serializers.defaultSerializeNull(gen);
                return;
            }

            java.util.Set<Object> visited = visitedObjects.get();
            try {
                // 检查对象是否已经被访问过
                if (visited.contains(value)) {
                    // 如果对象实现了IdentityEntity，只输出ID
                    if (value instanceof IdentityEntity) {
                        gen.writeStartObject();
                        gen.writeNumberField("id", ((IdentityEntity) value).getId());
                        gen.writeStringField("_ref_", "" + ((IdentityEntity) value).getId());
                        gen.writeEndObject();
                    } else {
                        // 对于非IdentityEntity对象，输出对象的toString或hashCode
                        gen.writeString(value.toString());
                    }
                    return;
                }

                // 标记对象为已访问
                visited.add(value);

                // 使用委托序列化器进行正常序列化
                ((JsonSerializer<Object>) delegate).serialize(value, gen, serializers);
            } finally {
                // 清理访问记录
                visited.remove(value);
                if (visited.isEmpty()) {
                    visitedObjects.remove();
                }
            }
        }
    }
}