package me.eternal.purrfect.common.util.ktx;

import com.highcapable.kavaref.KavaRef;
import com.highcapable.kavaref.condition.FieldCondition;
import com.highcapable.kavaref.resolver.FieldResolver;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;

import java.util.ArrayList;
import java.util.List;

public final class KavaRefFieldBridge {
    private KavaRefFieldBridge() {}

    private static FieldResolver<Object> resolveField(Object instance, String fieldName) {
        Class<?> current = instance.getClass();
        while (current != null && current != Object.class) {
            @SuppressWarnings("unchecked")
            KavaRef.MemberScope<Object> scope = (KavaRef.MemberScope<Object>) KavaRef.resolveClass((Class<Object>) current);
            FieldResolver<Object> resolver = scope.firstFieldOrNull(new Function1<FieldCondition<Object>, Unit>() {
                @Override
                public Unit invoke(FieldCondition<Object> condition) {
                    condition.name(fieldName);
                    return Unit.INSTANCE;
                }
            });
            if (resolver != null) return resolver.of(instance);
            current = current.getSuperclass();
        }
        return null;
    }

    public static Object getField(Object instance, String fieldName) throws NoSuchFieldException {
        FieldResolver<Object> resolver = resolveField(instance, fieldName);
        if (resolver == null) throw new NoSuchFieldException(instance.getClass().getName() + "#" + fieldName);
        return resolver.get();
    }

    public static void setField(Object instance, String fieldName, Object value) throws NoSuchFieldException {
        FieldResolver<Object> resolver = resolveField(instance, fieldName);
        if (resolver == null) throw new NoSuchFieldException(instance.getClass().getName() + "#" + fieldName);
        resolver.set(value);
    }

    public static String[] getAllFieldNames(Object instance) {
        List<String> result = new ArrayList<>();
        Class<?> current = instance.getClass();
        while (current != null && current != Object.class) {
            @SuppressWarnings("unchecked")
            KavaRef.MemberScope<Object> scope = (KavaRef.MemberScope<Object>) KavaRef.resolveClass((Class<Object>) current);
            List<FieldResolver<Object>> fields = scope.field(new Function1<FieldCondition<Object>, Unit>() {
                @Override
                public Unit invoke(FieldCondition<Object> condition) {
                    return Unit.INSTANCE;
                }
            });
            for (FieldResolver<Object> field : fields) result.add(field.getSelf().getName());
            current = current.getSuperclass();
        }
        return result.toArray(new String[0]);
    }
}
