package com.fufan.mtsaas.util;

import lombok.extern.slf4j.Slf4j;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 设置对象属性，获取对象
 * Liby
 * 2025-02-26
 */
@Slf4j
public class SetGetUtil {

    /**
     * 通用设置对象属性值方法
     *
     * @param obj       目标对象
     * @param fieldName 属性名
     * @param value     属性值
     */
    public static void setFieldByObject(Object obj, String fieldName, Object value, Class<?> clazz) {
        if (Objects.isNull(obj) || Objects.isNull(fieldName) || Objects.isNull(clazz)) {
            return;
        }

        try {
            //首字母改成大写
            fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

            // 根据字段类型获取对应的set方法名，例如"setFieldName"
            String methodName = "set" + fieldName;

            // 获取set方法对象
            Method method = obj.getClass().getMethod(methodName, clazz);

            // 调用set方法设置属性值
            method.invoke(obj, JSonUtil.toBean(JSonUtil.toJSONString(value), clazz));

        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            String className = obj.getClass().getName().substring(obj.getClass().getName().lastIndexOf(".") + 1);
            log.error("设置对象属性失败 " + className + " " + fieldName + ", " + e.getLocalizedMessage());
        }
    }

    /**
     * 通用设置普通属性值方法
     *
     * @param obj       目标对象
     * @param fieldName 属性名
     * @param value     属性值
     */
    public static void setField(Object obj, String fieldName, Object value) {
        if (Objects.isNull(obj) || Objects.isNull(fieldName)) {
            return;
        }

        try {
            // 获取目标对象的Class对象
            Class<?> clazz = obj.getClass();


            //首字母改成小写
            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);

            // 获取目标字段对象
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
            } catch (Exception e) {
                try {
                    field = clazz.getSuperclass().getDeclaredField(fieldName);
                } catch (Exception e1) {
                    field = clazz.getSuperclass().getSuperclass().getDeclaredField(fieldName);
                }
            }

            // 设置字段为可访问（即使是私有字段也可以访问）
            field.setAccessible(true);

            // 获取字段的类型
            Class<?> fieldType = field.getType();

            //首字母改成大写
            fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

            // 根据字段类型获取对应的set方法名，例如"setFieldName"
            String methodName = "set" + fieldName;

            // 获取set方法对象
            Method method = clazz.getMethod(methodName, fieldType);

            // 调用set方法设置属性值
            method.invoke(obj, value);

        } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            String className = obj.getClass().getName().substring(obj.getClass().getName().lastIndexOf(".") + 1);
            log.error("设置普通属性失败 " + className + " " + fieldName + ", " + e.getLocalizedMessage());
        }
    }

    /**
     * 通用获取属性值方法
     * 获取简单的pojo对象的属性
     *
     * @param obj       目标对象
     * @param fieldName 属性名
     */
    public static Object getField(Object obj, String fieldName) {
        if (Objects.isNull(obj) || Objects.isNull(fieldName)) {
            return null;
        }

        Object value = null;

        try {
            // 获取目标对象的Class对象
            Class<?> clazz = obj.getClass();

            //首字母改成小写
            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);

            // 获取目标字段对象
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
            } catch (Exception e) {
                try {
                    field = clazz.getSuperclass().getDeclaredField(fieldName);
                } catch (Exception e1) {
                    field = clazz.getSuperclass().getSuperclass().getDeclaredField(fieldName);
                }
            }

            // 设置字段为可访问（即使是私有字段也可以访问）
            field.setAccessible(true);

            //获取返回数据
            value = field.get(obj);

        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();

            String className = obj.getClass().getName().substring(obj.getClass().getName().lastIndexOf(".") + 1);
            log.error("获取属性失败 " + className + " " + fieldName + ", " + e.getLocalizedMessage());
        }

        return value;
    }

    /**
     * @param clazz
     * @param instance
     * @param methodName
     * @param param
     * @return
     * @throws Throwable
     */
    public static Object invokeMethodHandle(Class<?> clazz, Object instance, String methodName, Object retClazz, Long param) throws Throwable {
        Object result = null;

        try {
            // 1. 获取 MethodHandles.Lookup 对象
            MethodHandles.Lookup lookup = MethodHandles.lookup();

            // 检查方法是否存在
            Method retClass1 = clazz.getDeclaredMethod("queryByEventId", Long.class);
            if (Objects.isNull(retClass1)) {
                log.error("动态调用方法失败 " + methodName + " 不存在");
                return null;
            }

            // 2. 获取目标方法的 MethodHandle 对象
            MethodType methodType = MethodType.methodType(retClazz.getClass(), Long.class);

            MethodHandle selectHandle = lookup.findVirtual(clazz, methodName, methodType);

            // 3. 调用方法
            result = selectHandle.invoke(instance, param);
        } catch (Exception e) {
            e.printStackTrace();

            log.error("动态调用方法失败 " + methodName + ", " + e.getLocalizedMessage());
        }

        return result;
    }

}
