package click.kamil.springstatemachineexporter.ast.common;

import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NameQualifiedType;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.Type;

public final class AstUtils {
    private AstUtils() {
    }

    public static String extractSimpleTypeName(Type type) {
        if (type.isSimpleType()) {
            Name name = ((SimpleType) type).getName();
            if (name instanceof QualifiedName qn) {
                return qn.getName().getIdentifier();
            }
            return name.toString();
        } else if (type.isParameterizedType()) {
            Type rawType = ((ParameterizedType) type).getType();
            return extractSimpleTypeName(rawType);
        } else if (type.isQualifiedType()) {
            return ((QualifiedType) type).getName().getIdentifier();
        } else if (type.isNameQualifiedType()) {
            return ((NameQualifiedType) type).getName().getIdentifier();
        } else if (type.isArrayType()) {
            return extractSimpleTypeName(((ArrayType) type).getElementType());
        } else if (type.isPrimitiveType()) {
            return ((PrimitiveType) type).getPrimitiveTypeCode().toString();
        } else {
            return type.toString(); // fallback
        }
    }

    public static boolean isFunctionalCollectionMethod(org.eclipse.jdt.core.dom.MethodInvocation node) {
        if (node.getExpression() == null) {
            return false;
        }

        org.eclipse.jdt.core.dom.ITypeBinding typeBinding = node.getExpression().resolveTypeBinding();
        if (typeBinding != null) {
            if (isCollectionOrStreamType(typeBinding)) {
                return true;
            }
            return false;
        }
        
        String methodName = node.getName().getIdentifier();
        if (methodName.equals("forEach") || methodName.equals("map") || 
            methodName.equals("filter") || methodName.equals("flatMap") || 
            methodName.equals("anyMatch") || methodName.equals("allMatch") || 
            methodName.equals("noneMatch") || methodName.equals("reduce") ||
            methodName.equals("collect") || methodName.equals("removeIf") ||
            methodName.equals("ifPresent") || methodName.equals("ifPresentOrElse") ||
            methodName.equals("compute") || methodName.equals("computeIfAbsent") ||
            methodName.equals("computeIfPresent") || methodName.equals("replaceAll") ||
            methodName.equals("merge") || methodName.equals("peek") ||
            methodName.equals("doOnNext") || methodName.equals("doOnSuccess") ||
            methodName.equals("doOnError") || methodName.equals("concatMap") ||
            methodName.equals("switchMap")) {
            return true;
        }
        
        return false; 
    }

    private static boolean isCollectionOrStreamType(org.eclipse.jdt.core.dom.ITypeBinding typeBinding) {
        if (typeBinding == null) return false;
        String fqn = typeBinding.getErasure().getQualifiedName();
        if (fqn.startsWith("java.util.stream.") || 
            fqn.equals("java.lang.Iterable") || 
            fqn.equals("java.util.Collection") || 
            fqn.equals("java.util.List") || 
            fqn.equals("java.util.Set") || 
            fqn.equals("java.util.Map") || 
            fqn.equals("java.util.Iterator") || 
            fqn.equals("java.util.Optional") ||
            fqn.equals("reactor.core.publisher.Flux") ||
            fqn.equals("reactor.core.publisher.Mono")) {
            return true;
        }
        
        for (org.eclipse.jdt.core.dom.ITypeBinding intf : typeBinding.getInterfaces()) {
            if (isCollectionOrStreamType(intf)) return true;
        }
        
        if (typeBinding.getSuperclass() != null) {
            return isCollectionOrStreamType(typeBinding.getSuperclass());
        }
        
        return false;
    }

    public static String findConditionConstraint(org.eclipse.jdt.core.dom.ASTNode node) {
        java.util.List<String> conditions = new java.util.ArrayList<>();
        org.eclipse.jdt.core.dom.ASTNode current = node;
        while (current != null && !(current instanceof org.eclipse.jdt.core.dom.MethodDeclaration)) {
            org.eclipse.jdt.core.dom.ASTNode parent = current.getParent();
            if (parent instanceof org.eclipse.jdt.core.dom.IfStatement ifStmt) {
                if (ifStmt.getExpression() != current) {
                    org.eclipse.jdt.core.dom.Expression cond = ifStmt.getExpression();
                    if (current == ifStmt.getElseStatement()) {
                        conditions.add("!(" + cond.toString() + ")");
                    } else {
                        conditions.add(cond.toString());
                    }
                }
            }
            current = parent;
        }
        if (conditions.isEmpty()) return null;
        java.util.Collections.reverse(conditions);
        return String.join(" && ", conditions);
    }
}
