package click.kamil.springstatemachineexporter.analysis.resolver;

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

@Slf4j
public class ConstantResolver {

    public String resolve(Expression expr, CodebaseContext context) {
        if (expr == null) return null;

        // 1. Literal?
        if (expr instanceof StringLiteral sl) {
            return sl.getLiteralValue();
        }
        if (expr instanceof NumberLiteral nl) {
            return nl.getToken();
        }
        if (expr instanceof BooleanLiteral bl) {
            return String.valueOf(bl.booleanValue());
        }

        // 2. JDT Bindings? (Most robust)
        IVariableBinding binding = null;
        if (expr instanceof SimpleName sn) {
            IBinding b = sn.resolveBinding();
            if (b instanceof IVariableBinding vb) binding = vb;
        } else if (expr instanceof QualifiedName qn) {
            IBinding b = qn.resolveBinding();
            if (b instanceof IVariableBinding vb) binding = vb;
        }

        if (binding != null && binding.isField()) {
            Object value = binding.getConstantValue();
            if (value != null) return value.toString();
        }

        // 3. Fallback: Manual AST Traversal (if bindings not available or resolved)
        if (expr instanceof InfixExpression infix) {
            return resolveInfix(infix, context);
        }
        if (expr instanceof QualifiedName qn) {
            return resolveManual(qn, context);
        }

        return null;
    }

    private String resolveInfix(InfixExpression expr, CodebaseContext context) {
        if (expr.getOperator() != InfixExpression.Operator.PLUS) return null;

        String left = resolve(expr.getLeftOperand(), context);
        String right = resolve(expr.getRightOperand(), context);

        if (left == null || right == null) return null;

        StringBuilder sb = new StringBuilder(left + right);
        if (expr.hasExtendedOperands()) {
            for (Object operand : expr.extendedOperands()) {
                String val = resolve((Expression) operand, context);
                if (val == null) return null;
                sb.append(val);
            }
        }
        return sb.toString();
    }

    private String resolveManual(QualifiedName qn, CodebaseContext context) {
        String qualifier = qn.getQualifier().toString();
        String name = qn.getName().getIdentifier();
        
        CompilationUnit contextCu = (CompilationUnit) qn.getRoot();
        TypeDeclaration td = context.getTypeDeclaration(qualifier, contextCu);
        
        if (td != null) {
            for (FieldDeclaration fd : td.getFields()) {
                for (Object fragmentObj : fd.fragments()) {
                    if (fragmentObj instanceof VariableDeclarationFragment fragment) {
                        if (fragment.getName().getIdentifier().equals(name)) {
                            Expression initializer = fragment.getInitializer();
                            // Simple recursive resolve (be careful of cycles)
                            if (initializer instanceof StringLiteral sl) return sl.getLiteralValue();
                        }
                    }
                }
            }
        }
        
        return null;
    }
}
