package com.aicheck.parser;

import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;

import java.util.Optional;

/**
 * 从 Java 源文件路径或 AST 解析类名（简单名 / 全限定名）及类级中文说明。
 */
public class ClassDeclParser {

    /**
     * 从源码 AST 提取主类名；解析失败或未找到时回退为路径推导的类名。
     */
    public String resolveClassName(String source, String fallbackFromPath) {
        if (source == null || source.isBlank()) {
            return fallbackFromPath;
        }
        try {
            CompilationUnit cu = StaticJavaParser.parse(source);
            for (TypeDeclaration<?> type : cu.getTypes()) {
                if (type instanceof ClassOrInterfaceDeclaration) {
                    return type.getNameAsString();
                }
            }
        } catch (Exception ignored) {
            // 回退路径类名
        }
        return fallbackFromPath;
    }

    /** 从 .java 路径提取文件名（无扩展名）作为类名 */
    public static String classNameFromPath(String path) {
        String fileName = path.substring(path.lastIndexOf('/') + 1);
        if (!fileName.endsWith(".java")) {
            return fileName;
        }
        return fileName.substring(0, fileName.length() - 5);
    }

    /**
     * 全限定类名：package + 类名；源码无 package 时从文件路径推断。
     */
    public String resolveQualifiedClassName(String source, String relativePath, String fallbackClassName) {
        String simpleName = resolveClassName(source, fallbackClassName);
        if (source != null && !source.isBlank()) {
            try {
                CompilationUnit cu = StaticJavaParser.parse(source);
                String packageName = cu.getPackageDeclaration()
                        .map(p -> p.getNameAsString())
                        .orElse("");
                if (!packageName.isBlank()) {
                    return packageName + "." + simpleName;
                }
            } catch (Exception ignored) {
                // 回退路径推断
            }
        }
        return inferQualifiedFromPath(relativePath, simpleName);
    }

    /**
     * 提取类级中文说明：@Schema(description/title) &gt; 类 Javadoc 首段。
     */
    public String extractClassDescription(String source, String expectedClassName) {
        if (source == null || source.isBlank()) {
            return "";
        }
        try {
            CompilationUnit cu = StaticJavaParser.parse(source);
            ClassOrInterfaceDeclaration classDecl = findClass(cu, expectedClassName);
            if (classDecl == null) {
                return "";
            }
            String fromSchema = readSchemaDescription(classDecl);
            if (!fromSchema.isEmpty()) {
                return fromSchema;
            }
            return extractClassJavadoc(classDecl);
        } catch (Exception ignored) {
            return "";
        }
    }

    private ClassOrInterfaceDeclaration findClass(CompilationUnit cu, String expectedClassName) {
        if (expectedClassName != null && !expectedClassName.isBlank()) {
            for (TypeDeclaration<?> type : cu.getTypes()) {
                if (type instanceof ClassOrInterfaceDeclaration) {
                    ClassOrInterfaceDeclaration classDecl = (ClassOrInterfaceDeclaration) type;
                    if (classDecl.getNameAsString().equals(expectedClassName)) {
                        return classDecl;
                    }
                }
            }
        }
        for (TypeDeclaration<?> type : cu.getTypes()) {
            if (type instanceof ClassOrInterfaceDeclaration) {
                return (ClassOrInterfaceDeclaration) type;
            }
        }
        return null;
    }

    private String readSchemaDescription(ClassOrInterfaceDeclaration classDecl) {
        for (AnnotationExpr annotation : classDecl.getAnnotations()) {
            if (!"Schema".equals(annotation.getNameAsString())) {
                continue;
            }
            String description = readAnnotationStringValue(annotation, "description");
            if (!description.isEmpty()) {
                return description;
            }
            String title = readAnnotationStringValue(annotation, "title");
            if (!title.isEmpty()) {
                return title;
            }
        }
        return "";
    }

    private String readAnnotationStringValue(AnnotationExpr annotation, String attributeName) {
        if (annotation.isNormalAnnotationExpr()) {
            NormalAnnotationExpr normal = annotation.asNormalAnnotationExpr();
            for (var pair : normal.getPairs()) {
                if (pair.getNameAsString().equals(attributeName)) {
                    return literalString(pair.getValue());
                }
            }
            return "";
        }
        if (annotation.isSingleMemberAnnotationExpr()) {
            SingleMemberAnnotationExpr single = annotation.asSingleMemberAnnotationExpr();
            if ("value".equals(attributeName) || "description".equals(attributeName)) {
                return literalString(single.getMemberValue());
            }
        }
        return "";
    }

    private String literalString(Expression expression) {
        if (expression.isStringLiteralExpr()) {
            return expression.asStringLiteralExpr().getValue().trim();
        }
        return "";
    }

    private String extractClassJavadoc(ClassOrInterfaceDeclaration classDecl) {
        Optional<JavadocComment> javadoc = classDecl.getJavadocComment();
        if (javadoc.isEmpty()) {
            return "";
        }
        String text = javadoc.get().parse().getDescription().toText();
        return text == null ? "" : text.trim().replaceAll("\\s+", " ");
    }

    /** 从 src/main/java/ 后的路径推断 package.className */
    public static String inferQualifiedFromPath(String relativePath, String className) {
        if (relativePath == null || relativePath.isBlank()) {
            return className;
        }
        String normalized = relativePath.replace('\\', '/');
        String marker = "src/main/java/";
        int idx = normalized.indexOf(marker);
        if (idx < 0) {
            return className;
        }
        String subPath = normalized.substring(idx + marker.length());
        int lastSlash = subPath.lastIndexOf('/');
        if (lastSlash <= 0) {
            return className;
        }
        String packageName = subPath.substring(0, lastSlash).replace('/', '.');
        return packageName + "." + className;
    }
}
