package click.kamil.springstatemachineexporter.analysis.pipeline;

import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

import java.util.HashSet;
import java.util.Set;

/**
 * Finds {@code new ...()} field initializers, walking the inheritance chain once.
 */
public final class FieldInitializerFinder {

    private final CodebaseContext context;

    public FieldInitializerFinder(CodebaseContext context) {
        this.context = context;
    }

    public ClassInstanceCreation findFieldInitializerCic(String ownerFqn, String fieldName) {
        if (fieldName == null || ownerFqn == null) {
            return null;
        }
        TypeDeclaration td = context.getTypeDeclaration(ownerFqn);
        return findFieldInitializerCic(td, fieldName, new HashSet<>());
    }

    public ClassInstanceCreation findFieldInitializerCic(TypeDeclaration td, String fieldName, Set<String> visited) {
        if (td == null || fieldName == null) {
            return null;
        }
        String typeFqn = context.getFqn(td);
        if (typeFqn == null || !visited.add(typeFqn)) {
            return null;
        }

        for (FieldDeclaration fd : td.getFields()) {
            for (Object fragObj : fd.fragments()) {
                if (fragObj instanceof VariableDeclarationFragment frag
                        && frag.getName().getIdentifier().equals(fieldName)
                        && frag.getInitializer() instanceof ClassInstanceCreation cic) {
                    return cic;
                }
            }
        }

        String superFqn = context.getSuperclassFqn(td);
        if (superFqn != null) {
            TypeDeclaration superTd = context.getTypeDeclaration(superFqn);
            ClassInstanceCreation inherited = findFieldInitializerCic(superTd, fieldName, visited);
            if (inherited != null) {
                return inherited;
            }
        }
        return null;
    }

    public String resolveFieldTypeName(String ownerFqn, String fieldName) {
        if (ownerFqn == null || fieldName == null) {
            return null;
        }
        TypeDeclaration td = context.getTypeDeclaration(ownerFqn);
        return resolveFieldTypeName(td, fieldName, new HashSet<>());
    }

    public String resolveFieldTypeName(TypeDeclaration td, String fieldName, Set<String> visited) {
        if (td == null || fieldName == null) {
            return null;
        }
        String typeFqn = context.getFqn(td);
        if (typeFqn == null || !visited.add(typeFqn)) {
            return null;
        }

        for (FieldDeclaration fd : td.getFields()) {
            for (Object fragObj : fd.fragments()) {
                if (fragObj instanceof VariableDeclarationFragment frag
                        && frag.getName().getIdentifier().equals(fieldName)) {
                    return fd.getType().toString();
                }
            }
        }

        String superFqn = context.getSuperclassFqn(td);
        if (superFqn != null) {
            TypeDeclaration superTd = context.getTypeDeclaration(superFqn);
            return resolveFieldTypeName(superTd, fieldName, visited);
        }
        return null;
    }
}
