package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;

/**
 * Resolves call-graph target FQNs for {@code this}, implicit, and {@code super} dispatch hops.
 * Uses the declaring type of the resolved method (parent class for inherited members).
 */
final class InheritanceCallTargetResolver {

    private InheritanceCallTargetResolver() {
    }

    static String resolveInstanceMethod(
            CodebaseContext context,
            TypeDeclaration enclosingType,
            String methodName) {
        if (context == null || enclosingType == null || methodName == null || methodName.isBlank()) {
            return null;
        }
        MethodDeclaration method = context.findMethodDeclaration(enclosingType, methodName, true);
        if (method == null) {
            return null;
        }
        TypeDeclaration declaringType = findEnclosingTypeDeclaration(method);
        if (declaringType == null) {
            return null;
        }
        String fqn = context.getFqn(declaringType);
        return fqn == null ? null : fqn + "." + methodName;
    }

    static String resolveSuperMethod(
            CodebaseContext context,
            TypeDeclaration enclosingType,
            String methodName) {
        if (context == null || enclosingType == null || methodName == null || methodName.isBlank()) {
            return null;
        }
        String superFqn = context.getSuperclassFqn(enclosingType);
        if (superFqn == null) {
            return null;
        }
        TypeDeclaration superType = context.getTypeDeclaration(superFqn);
        if (superType == null) {
            return superFqn + "." + methodName;
        }
        String resolved = resolveInstanceMethod(context, superType, methodName);
        return resolved != null ? resolved : superFqn + "." + methodName;
    }

    private static TypeDeclaration findEnclosingTypeDeclaration(ASTNode node) {
        ASTNode current = node;
        while (current != null) {
            if (current instanceof TypeDeclaration typeDeclaration) {
                return typeDeclaration;
            }
            current = current.getParent();
        }
        return null;
    }
}
