package click.kamil.springstatemachineexporter.analysis.enricher.path;

import click.kamil.springstatemachineexporter.analysis.model.CallChain;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SymbolicPathValueEstimator implements PathValueEstimator {

    @Override
    public List<String> estimatePossibleValues(CallChain chain, CodebaseContext context) {
        if (chain.getMethodChain() == null || chain.getMethodChain().isEmpty()) {
            return null;
        }

        Set<String> collectedConstants = new HashSet<>();

        for (String methodFqn : chain.getMethodChain()) {
            int lastDot = methodFqn.lastIndexOf('.');
            if (lastDot == -1) continue;
            
            String className = methodFqn.substring(0, lastDot);
            String methodName = methodFqn.substring(lastDot + 1);

            TypeDeclaration td = context.getTypeDeclaration(className);
            if (td == null) continue;

            MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
            if (md == null || md.getBody() == null) continue;

            md.getBody().accept(new ASTVisitor() {
                @Override
                public boolean visit(MethodInvocation node) {
                    if ((node.getName().getIdentifier().equals("equals") || node.getName().getIdentifier().equals("equalsIgnoreCase")) 
                        && node.arguments().size() == 1) {
                        
                        Expression caller = node.getExpression();
                        Expression arg = (Expression) node.arguments().get(0);
                        
                        click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver resolver = new click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver();
                        
                        if (caller != null) {
                            String callerVal = resolver.resolve(caller, context);
                            if (callerVal != null && !callerVal.isEmpty()) {
                                addValue(collectedConstants, callerVal);
                            }
                        }
                        
                        String argVal = resolver.resolve(arg, context);
                        if (argVal != null && !argVal.isEmpty()) {
                            addValue(collectedConstants, argVal);
                        }
                    }
                    return super.visit(node);
                }

                @Override
                public boolean visit(InfixExpression node) {
                    if (node.getOperator() == InfixExpression.Operator.EQUALS) {
                        click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver resolver = new click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver();
                        String left = resolver.resolve(node.getLeftOperand(), context);
                        if (left != null && !left.isEmpty()) {
                            addValue(collectedConstants, left);
                        }
                        String right = resolver.resolve(node.getRightOperand(), context);
                        if (right != null && !right.isEmpty()) {
                            addValue(collectedConstants, right);
                        }
                    }
                    return super.visit(node);
                }

                @Override
                public boolean visit(SwitchStatement node) {
                    for (Object stmt : node.statements()) {
                        if (stmt instanceof SwitchCase sc && !sc.isDefault()) {
                            for (Object expr : sc.expressions()) {
                                click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver resolver = new click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver();
                                String val = resolver.resolve((Expression) expr, context);
                                if (val != null && !val.isEmpty()) {
                                    addValue(collectedConstants, val);
                                }
                            }
                        }
                    }
                    return super.visit(node);
                }
                
                @Override
                public boolean visit(SwitchExpression node) {
                    for (Object stmt : node.statements()) {
                        if (stmt instanceof SwitchCase sc && !sc.isDefault()) {
                            for (Object expr : sc.expressions()) {
                                click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver resolver = new click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver();
                                String val = resolver.resolve((Expression) expr, context);
                                if (val != null && !val.isEmpty()) {
                                    addValue(collectedConstants, val);
                                }
                            }
                        }
                    }
                    return super.visit(node);
                }
            });
        }

        if (collectedConstants.isEmpty()) return null;
        return new ArrayList<>(collectedConstants);
    }
    
    private void addValue(Set<String> collectedConstants, String val) {
        if (val.startsWith("ENUM_SET:")) {
            for (String eVal : val.substring(9).split(",")) {
                String parsed = parseEnumSetElement(eVal);
                if (!collectedConstants.contains(parsed)) collectedConstants.add(parsed);
            }
        } else {
            collectedConstants.add(val);
        }
    }
    
    private String parseEnumSetElement(String element) {
        if (element.contains(".")) {
            return element.substring(element.lastIndexOf('.') + 1);
        }
        return element;
    }
}
