package click.kamil.springstatemachineexporter.analysis.index;

import click.kamil.springstatemachineexporter.analysis.pipeline.FieldInitializerFinder;
import click.kamil.springstatemachineexporter.ast.common.AstUtils;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public final class GetterChainIndexBuilder {

    public GetterChainIndex build(CodebaseContext context, AccessorIndex accessorIndex) {
        if (context == null || accessorIndex == null) {
            return GetterChainIndex.empty();
        }

        FieldInitializerFinder fieldInitializerFinder = new FieldInitializerFinder(context);
        Map<String, Map<String, GetterChainEdge>> edges = new HashMap<>();
        int edgeCount = 0;

        for (Map.Entry<String, Map<String, AccessorSummary>> ownerEntry : accessorIndex.asMap().entrySet()) {
            String ownerFqn = ownerEntry.getKey();
            for (AccessorSummary accessor : ownerEntry.getValue().values()) {
                if (!accessor.isGetter()) {
                    continue;
                }
                GetterChainEdge edge = buildEdge(context, fieldInitializerFinder, ownerFqn, accessor);
                if (edge == null) {
                    continue;
                }
                edges.computeIfAbsent(ownerFqn, ignored -> new HashMap<>())
                        .put(accessor.methodName(), edge);
                edgeCount++;
            }
        }

        log.info("Built getter-chain index: {} edges across {} types", edgeCount, edges.size());
        return new GetterChainIndex(edges, edgeCount);
    }

    private static GetterChainEdge buildEdge(
            CodebaseContext context,
            FieldInitializerFinder fieldInitializerFinder,
            String ownerFqn,
            AccessorSummary accessor) {
        String nextType = null;
        ClassInstanceCreation fieldInitializerCic = null;

        if (accessor.fieldName() != null) {
            fieldInitializerCic = fieldInitializerFinder.findFieldInitializerCic(ownerFqn, accessor.fieldName());
            nextType = fieldInitializerFinder.resolveFieldTypeName(ownerFqn, accessor.fieldName());
            if (fieldInitializerCic != null) {
                nextType = AstUtils.extractSimpleTypeName(fieldInitializerCic.getType());
            }
        }

        if (nextType == null) {
            TypeDeclaration ownerType = context.getTypeDeclaration(ownerFqn);
            MethodDeclaration getter = ownerType != null
                    ? context.findMethodDeclaration(ownerType, accessor.methodName(), true)
                    : null;
            if (getter != null && getter.getReturnType2() != null) {
                nextType = getter.getReturnType2().toString();
            }
        }

        if (nextType == null) {
            return null;
        }
        return new GetterChainEdge(ownerFqn, accessor.methodName(), nextType, fieldInitializerCic);
    }
}
