package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jdt.core.dom.*;

@Slf4j
public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {

    public HeuristicCallGraphEngine(CodebaseContext context) {
        super(context);
    }

    @Override
    protected String callGraphCacheKey() {
        return "heuristicCallGraph";
    }

    @Override
    protected String resolveCalledMethod(MethodInvocation node) {
        Expression receiver = node.getExpression();
        String methodName = node.getName().getIdentifier();

        if (receiver instanceof MethodInvocation miReceiver) {
            String returnType = resolveMethodInvocationReturnType(miReceiver);
            if (returnType != null) {
                return returnType + "." + methodName;
            }
        }

        TypeDeclaration enclosingType = findEnclosingType(node);

        if (receiver instanceof SuperMethodInvocation) {
            return InheritanceCallTargetResolver.resolveSuperMethod(context, enclosingType, methodName);
        }

        if (receiver == null) {
            return InheritanceCallTargetResolver.resolveInstanceMethod(context, enclosingType, methodName);
        }

        ITypeBinding binding = receiver.resolveTypeBinding();
        if (binding != null) {
            return binding.getQualifiedName() + "." + methodName;
        }

        if (receiver instanceof ThisExpression) {
            return InheritanceCallTargetResolver.resolveInstanceMethod(context, enclosingType, methodName);
        }

        if (receiver instanceof SimpleName sn) {
            String fallbackTypeFqn = resolveReceiverTypeFallback(sn);
            if (fallbackTypeFqn != null) {
                return fallbackTypeFqn + "." + methodName;
            }
            return sn.getIdentifier() + "." + methodName;
        }

        if (receiver instanceof QualifiedName qn) {
            String fqn = qn.getFullyQualifiedName();
            TypeDeclaration td = context.getTypeDeclaration(fqn);
            if (td != null) {
                return fqn + "." + methodName;
            }
            return fqn + "." + methodName;
        }

        return null;
    }
}
