package cd.casic.framework.mongo.utils;

import org.springframework.data.annotation.Id;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class ClassUtils {

    private ClassUtils(){
    }

    /**
     *  缓存目标类型上的泛型值
     */
    private static final Map<Class<?>, Class<?>> CACHE = new ConcurrentHashMap<>(64);

    /**
     * 缓存mongo实体的主键字段
     */
    private static final Map<Class<?>, Field> FIELD_CACHE = new ConcurrentHashMap<>(64);


    /**
     * 获取集合实体的主键值
     */
    public static Serializable getId(Object object){

        Field field = getIdField(object);
        field.setAccessible(true);
        try {
            return (Serializable) field.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("not exist id value");
        }
    }

    /**
     * 获取集合实体的主键字段
     */
    public static Field getIdField(Object object){

        Class<?> clazz = object.getClass();
        Field result = FIELD_CACHE.get(clazz);
        if (Objects.nonNull(result)){
            return result;
        }
        for (Field field : clazz.getDeclaredFields()){
            Id annotation = field.getAnnotation(Id.class);
            if (Objects.nonNull(annotation)){
                FIELD_CACHE.put(clazz,field);
                return field;
            }
        }
        throw new RuntimeException("no exist id");
    }

    /**
     * 获取对象上的泛型
     */
    public static Class<?> getClass(Object object){

        if (Objects.isNull(object)){
            return null;
        }
        Class<?> clazz = object.getClass();
        Class<?> result = CACHE.get(clazz);
        if (Objects.nonNull(result)){
            return result;
        }
        Type aClass = object.getClass().getGenericSuperclass();
        Type subType = ((ParameterizedType) aClass).getActualTypeArguments()[0];
        result = (Class<?>) subType;
        CACHE.put(clazz,result);
        return result;
    }
}
