package link.at17.mid.tushare.system.util;
import java.util.HashSet;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.json.JsonMapper;

public class SmartViewWriter {
    private static final ObjectMapper normalMapper = new ObjectMapper();
    private static final ObjectMapper withViewMapper = JsonMapper.builder()
            .configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false)
            .build();

    public SmartViewWriter() {
    }

    /**
     * 智能序列化：如果对象包含 @JsonView 注解字段，则只输出视图字段；否则输出全部字段
     */
    public String writeWithSmartView(Object obj, Class<?> viewClass) {
        if (hasJsonViewRecursive(obj.getClass(), new HashSet<>())) {
            try {
                ObjectWriter writer = withViewMapper.writerWithView(viewClass);
                writer = writer.with(SerializationFeature.INDENT_OUTPUT);
                return writer.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                throw new RuntimeException("Serialization failed", e);
            }
        } else {
            try {
                ObjectWriter writer = normalMapper.writer();
                writer = writer.with(SerializationFeature.INDENT_OUTPUT);
                return writer.writeValueAsString(obj); // 无视图注解，走默认序列化
            } catch (JsonProcessingException e) {
                throw new RuntimeException("Serialization failed", e);
            }
        }
    }

    private boolean hasJsonViewRecursive(Class<?> clazz, Set<Class<?>> visited) {
        if (clazz == null || clazz.getName().startsWith("java.") || visited.contains(clazz)) {
            return false;
        }

        visited.add(clazz);

        JavaType javaType = normalMapper.getTypeFactory().constructType(clazz);
        BeanDescription beanDesc = normalMapper.getSerializationConfig().introspect(javaType);

        for (BeanPropertyDefinition prop : beanDesc.findProperties()) {
            AnnotatedMember accessor = prop.getAccessor();
            if (accessor != null && accessor.hasAnnotation(JsonView.class)) {
                return true;
            }

            JavaType fieldType = prop.getPrimaryType();

            if (fieldType == null) continue;

            if (fieldType.isCollectionLikeType()) {
                // 处理 List<T>, Set<T>
                JavaType contentType = fieldType.getContentType();
                if (hasJsonViewRecursive(contentType.getRawClass(), visited)) {
                    return true;
                }
            } else if (fieldType.isArrayType()) {
                JavaType elemType = fieldType.getContentType();
                if (hasJsonViewRecursive(elemType.getRawClass(), visited)) {
                    return true;
                }
            } else if (fieldType.isMapLikeType()) {
                JavaType valueType = fieldType.getContentType();
                if (hasJsonViewRecursive(valueType.getRawClass(), visited)) {
                    return true;
                }
            } else if (!fieldType.isPrimitive() && !fieldType.isEnumType()) {
                // 普通对象类型递归
                if (hasJsonViewRecursive(fieldType.getRawClass(), visited)) {
                    return true;
                }
            }
        }

        return false;
    }
}