package cd.casic.framework.mongo.utils;

import cd.casic.framework.mongo.core.sdk.SFunction;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class ConvertUtils {

    public static final String GET = "get";

    public static final String IS = "is";

    private static final Map<Class<?>,String> CLASS_FIELD_META_MAP = new ConcurrentHashMap<>();

    private ConvertUtils(){
    }

    public static <T> String convertToFieldName(SFunction<T, ?> function){

        SerializedLambda lambda = getSerializedLambda(function);
        String cacheDate = CLASS_FIELD_META_MAP.get(function.getClass());
        if (Objects.nonNull(cacheDate)){
            return cacheDate;
        }
        String methodName = lambda.getImplMethodName();
        if (methodName.startsWith(GET)){
            methodName = methodName.substring(3);
        }
        else if (methodName.startsWith(IS)){
            methodName = methodName.substring(2);
        }
        else {
            throw new IllegalArgumentException("无效的getter方法" + methodName);
        }
        try{
            String fieldMeta = StringUtils.firstToLowerCase(methodName);
            CLASS_FIELD_META_MAP.put(function.getClass(),fieldMeta);
            return fieldMeta;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public static SerializedLambda getSerializedLambda(Serializable serializable){

        SerializedLambda serializedLambda;
        try{
            Method method = serializable.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            serializedLambda = (SerializedLambda) method.invoke(serializable);
        }catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e){
            throw new RuntimeException(e);
        }
        return serializedLambda;
    }
}
