package click.kamil.springstatemachineexporter.ast.common;

import org.eclipse.jdt.core.dom.*;
import java.util.Set;

public final class BindingResolver {

    private BindingResolver() {
        // Prevent instantiation
    }

    /**
     * Resolves the type binding for a given AST Type node.
     */
    public static ITypeBinding resolveType(Type type) {
        if (type == null) return null;
        return type.resolveBinding();
    }

    /**
     * Resolves the type binding for a given AST Expression node.
     */
    public static ITypeBinding resolveType(Expression expression) {
        if (expression == null) return null;
        return expression.resolveTypeBinding();
    }

    /**
     * Resolves the method binding for a MethodInvocation.
     */
    public static IMethodBinding resolveMethod(MethodInvocation invocation) {
        if (invocation == null) return null;
        return invocation.resolveMethodBinding();
    }

    /**
     * Resolves the constructor binding for a ClassInstanceCreation.
     */
    public static IMethodBinding resolveConstructor(ClassInstanceCreation creation) {
        if (creation == null) return null;
        return creation.resolveConstructorBinding();
    }

    /**
     * Resolves the constructor binding for a ConstructorInvocation (e.g. this(...)).
     */
    public static IMethodBinding resolveConstructor(ConstructorInvocation invocation) {
        if (invocation == null) return null;
        return invocation.resolveConstructorBinding();
    }

    /**
     * Resolves the constructor binding for a SuperConstructorInvocation (e.g. super(...)).
     */
    public static IMethodBinding resolveConstructor(SuperConstructorInvocation invocation) {
        if (invocation == null) return null;
        return invocation.resolveConstructorBinding();
    }

    /**
     * Resolves the type binding of a TypeDeclaration.
     */
    public static ITypeBinding resolveType(TypeDeclaration td) {
        if (td == null) return null;
        return td.resolveBinding();
    }

    /**
     * Gets the fully qualified name of a type binding, safely handling nulls and erasure.
     */
    public static String getFullyQualifiedName(ITypeBinding binding) {
        if (binding == null) return null;
        return binding.getErasure().getQualifiedName();
    }

    public static boolean isSubtypeOf(ITypeBinding childBinding, String targetFqn) {
        return isSubtypeOf(childBinding, targetFqn, new java.util.HashSet<>());
    }

    private static boolean isSubtypeOf(ITypeBinding childBinding, String targetFqn, Set<String> visited) {
        if (childBinding == null || targetFqn == null) return false;
        
        String key = childBinding.getKey();
        if (key != null && !visited.add(key)) {
            return false;
        }

        // Direct match
        if (targetFqn.equals(childBinding.getErasure().getQualifiedName())) {
            return true;
        }

        // Check interfaces
        for (ITypeBinding intf : childBinding.getInterfaces()) {
            if (isSubtypeOf(intf, targetFqn, visited)) {
                return true;
            }
        }

        // Check superclass
        ITypeBinding superclass = childBinding.getSuperclass();
        if (superclass != null) {
            return isSubtypeOf(superclass, targetFqn, visited);
        }

        return false;
    }
}
