package com.atmob.voiceai.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

public final class ReflectionUtil {
    public static List<Field> getAllField(Class<?> clazz) {
        ArrayList<Field> fields = new ArrayList<>();
        while (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    public static Object findField(Object origin, Class<?>... targetClass) {
        if (origin == null || targetClass == null || targetClass.length == 0) {
            return null;
        }
        HashSet<Class<?>> targetClasses = new HashSet<>(Arrays.asList(targetClass));
        List<Field> fields = getAllField(origin.getClass());
        for (Field field : fields) {
            if (targetClasses.contains(field.getType())) {
                try {
                    field.setAccessible(true);
                    return field.get(origin);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static Object findField(Object origin, String... targetName) {
        if (origin == null || targetName == null || targetName.length == 0) {
            return null;
        }
        HashSet<String> targetNames = new HashSet<>(Arrays.asList(targetName));
        List<Field> fields = getAllField(origin.getClass());
        for (Field field : fields) {
            if (targetNames.contains(field.getName())) {
                try {
                    field.setAccessible(true);
                    return field.get(origin);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static List<Method> getAllMethod(Class<?> clazz) {
        ArrayList<Method> methods = new ArrayList<>();
        while (clazz != null) {
            methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
            clazz = clazz.getSuperclass();
        }
        return methods;
    }

    public static Method findMethod(Object origin, String methodName, Class<?>... parameterTypes) {
        List<Method> allMethod = getAllMethod(origin.getClass());
        for (Method method : allMethod) {
            if (method.getName().equals(methodName) && Arrays.equals(method.getParameterTypes(), parameterTypes)) {
                method.setAccessible(true);
                return method;
            }
        }
        return null;
    }

    public static Object getFieldValue(Field field, Object origin) {
        try {
            field.setAccessible(true);
            return field.get(origin);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object invokeMethod(Method method, Object origin) {
        try {
            method.setAccessible(true);
            return method.invoke(origin);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
