package cd.casic.plugin.utils.dBUtils;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class AnnotationScanner {

    public static List<Class<?>> scanPackageForAnnotatedClasses(String packageName, Class<? extends Annotation> annotationClass, ClassLoader classLoader) throws IOException, ClassNotFoundException {
        List<Class<?>> annotatedClasses = new ArrayList<>();
        // 获取包所在的URL
        Enumeration<URL> urls = classLoader.getResources(packageName.replace('.', '/'));
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            String protocol = url.getProtocol();
            if ("file".equals(protocol)) {
                // 处理文件系统中的包
                File packageDir = new File(url.getFile());
                scanDirectoryForAnnotatedClasses(packageDir, packageName, annotationClass, annotatedClasses);
            } else if ("jar".equals(protocol)) {
                // 处理JAR文件中的包
                JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
                scanJarFileForAnnotatedClasses(jarFile, packageName, annotationClass, annotatedClasses, classLoader);
            }
        }
        return annotatedClasses;
    }

    private static void scanDirectoryForAnnotatedClasses(File directory, String packageName, Class<? extends Annotation> annotationClass, List<Class<?>> annotatedClasses) throws ClassNotFoundException {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    scanDirectoryForAnnotatedClasses(file, packageName + "." + file.getName(), annotationClass, annotatedClasses);
                } else if (file.isFile() && file.getName().endsWith(".class")) {
                    String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                    Class<?> clazz = Class.forName(className);
                    if (clazz.isAnnotationPresent(annotationClass)) {
                        annotatedClasses.add(clazz);
                    }
                }
            }
        }
    }

    private static void scanJarFileForAnnotatedClasses(JarFile jarFile, String packageName, Class<? extends Annotation> annotationClass, List<Class<?>> annotatedClasses, ClassLoader classLoader) {
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String entryName = entry.getName();
            if (entryName.endsWith(".class") && entryName.startsWith(packageName.replace('.', '/')) && !entryName.contains("$")) { // 忽略内部类
                String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
                try {
                    Class<?> clazz = classLoader.loadClass(className);
                    if (clazz.isAnnotationPresent(annotationClass)) {
                        annotatedClasses.add(clazz);
                    }
                } catch (Exception e) {
                    System.err.println("Class not found: " + className);
                    ;
                }
            }
        }
    }
}