package com.zt.plat.module.base.util;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.*;

/**
 * 类信息扫描工具类，用于通过简单类名获取类字段及Schema注解信息
 * 增强版：支持通配符包路径扫描
 */
@Slf4j
public class ClassInfoScanner {

    // 缓存简单类名到Class的映射，提高性能
    private static final Map<String, Class<?>> CLASS_CACHE = new HashMap<>();
    // 已初始化标识
    private static boolean initialized = false;

    /**
     * 初始化扫描指定包路径下的所有类
     * @param basePackages 基础包路径，支持逗号分隔多个包，支持*和**通配符
     */
    public static synchronized void init(String[]  basePackages) {
        if (initialized) {
            return;
        }

        if (basePackages == null || basePackages.length==0) {
            throw new IllegalArgumentException("基础包路径不能为空");
        }
        Arrays.stream(basePackages).forEach(basePackage -> {
            String[] packages = basePackage.split("[,;\\s]+");
            for (String pkg : packages) {
                String trimmedPkg = pkg.trim();
                if (trimmedPkg.contains("**") || trimmedPkg.contains("*")) {
                    // 处理通配符包路径
                    scanPackageWithWildcard(trimmedPkg);
                    log.info("已扫描通配符包路径：{}", trimmedPkg);
                } else {
                    // 处理普通包路径
                    scanPackage(trimmedPkg);
                    log.info("已扫描普通包路径：{}", trimmedPkg);
                }
            }
        });


        initialized = true;
    }

    /**
     * 处理包含通配符的包路径扫描
     */
    private static void scanPackageWithWildcard(String wildcardPackage) {
        try {
            // 提取基础包路径（通配符之前的部分）
            String basePackage = extractBasePackage(wildcardPackage);
            String pattern = wildcardPackage.substring(basePackage.length());

            // 扫描基础包路径
            String packageDirName = basePackage.replace('.', '/');
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                String protocol = url.getProtocol();

                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
                    findClassesWithPattern(basePackage, filePath, pattern);
                } else if ("jar".equals(protocol)) {
                    JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
                    Enumeration<JarEntry> entries = jar.entries();
                    processJarEntriesWithPattern(basePackage, entries, pattern);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("扫描通配符包时发生错误: " + wildcardPackage, e);
        }
    }

    /**
     * 提取基础包路径（通配符之前的部分）
     */
    private static String extractBasePackage(String wildcardPackage) {
        int wildcardIndex = wildcardPackage.indexOf('*');
        if (wildcardIndex == -1) {
            return wildcardPackage;
        }

        String beforeWildcard = wildcardPackage.substring(0, wildcardIndex);
        int lastDotIndex = beforeWildcard.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return "";
        }

        return beforeWildcard.substring(0, lastDotIndex);
    }

    /**
     * 在文件系统中按模式查找类
     */
    private static void findClassesWithPattern(String basePackage, String basePath, String pattern) {
        File baseDir = new File(basePath);
        if (!baseDir.exists() || !baseDir.isDirectory()) {
            return;
        }

        findClassesRecursive(baseDir, basePackage, pattern);
    }

    /**
     * 递归查找匹配模式的类
     */
    private static void findClassesRecursive(File dir, String packageName, String pattern) {
        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归处理子目录
                String subPackageName = packageName + "." + file.getName();
                findClassesRecursive(file, subPackageName, pattern);
            } else if (file.getName().endsWith(".class")) {
                // 检查是否匹配模式
                String className = file.getName().substring(0, file.getName().length() - 6);
                String fullClassName = packageName + "." + className;

                if (matchesPattern(fullClassName, pattern)) {
                    try {
                        Class<?> clazz = Class.forName(fullClassName);
                        CLASS_CACHE.put(clazz.getSimpleName(), clazz);
                    } catch (ClassNotFoundException e) {
                        // 忽略无法加载的类
                    }
                }
            }
        }
    }

    /**
     * 在JAR包中按模式查找类
     */
    private static void processJarEntriesWithPattern(String basePackage, Enumeration<JarEntry> entries, String pattern) {
        String basePackagePath = basePackage.replace('.', '/');

        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String entryName = entry.getName();

            if (entryName.charAt(0) == '/') {
                entryName = entryName.substring(1);
            }

            if (entryName.startsWith(basePackagePath) && !entry.isDirectory() && entryName.endsWith(".class")) {
                String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');

                if (matchesPattern(className, pattern)) {
                    try {
                        Class<?> clazz = Class.forName(className);
                        CLASS_CACHE.put(clazz.getSimpleName(), clazz);
                    } catch (ClassNotFoundException e) {
                        // 忽略无法加载的类
                    }
                }
            }
        }
    }

    /**
     * 检查类名是否匹配通配符模式
     */
    private static boolean matchesPattern(String className, String pattern) {
        if (pattern.isEmpty()) {
            return true;
        }

        // 简单的通配符匹配实现
        if (pattern.startsWith(".")) {
            pattern = pattern.substring(1);
        }

        // 处理 **.vo 模式
        if (pattern.equals("**.vo")) {
            return className.endsWith(".vo") ||
                    (className.contains(".") && className.substring(className.lastIndexOf('.') + 1).toLowerCase().contains("vo"));
        }

        // 处理其他模式
        String[] patternParts = pattern.split("\\*\\*");
        if (patternParts.length == 2) {
            String prefix = patternParts[0];
            String suffix = patternParts[1];
            return className.contains(prefix) && className.endsWith(suffix);
        }

        return className.contains(pattern.replace("*", ""));
    }

    /**
     * 通过简单类名获取类的字段及Schema注解信息
     * @param simpleClassName 简单类名
     * @return 包含字段名和label的列表
     */
    public static List<Map<String, Object>> getClassFieldInfo(String simpleClassName) {
        if (!initialized) {
            throw exception(UTIL_NOT_INIT);
        }

        if (simpleClassName == null || !simpleClassName.endsWith("VO")) {
            throw exception(PARAMS_IS_NULL_OR_ERR);
        }

        Class<?> targetClass = CLASS_CACHE.get(simpleClassName);
        if (targetClass == null) {
            throw exception(NOT_FOUND_CLASS);
        }

        List<Map<String, Object>> resultList = new ArrayList<>();
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Schema.class)) {
                Schema schema = field.getAnnotation(Schema.class);
                Map<String, Object> fieldMap = new HashMap<>();
                fieldMap.put("fieldName", field.getName());
                fieldMap.put("label", schema.description().isEmpty() ?null:schema.description().split(";")[0]);
                fieldMap.put("required", schema.requiredMode() == Schema.RequiredMode.REQUIRED);
                fieldMap.put("example", schema.example());
                //获取字段的类型
                fieldMap.put("type", field.getType().getSimpleName());
                fieldMap.put("orgnType", "class");
                resultList.add(fieldMap);
            }
        }

        return resultList;
    }

    /**
     * 扫描指定包下的所有类（原有方法保持不变）
     */
    private static void scanPackage(String basePackage) {
        try {
            String packageDirName = basePackage.replace('.', '/');
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                String protocol = url.getProtocol();

                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
                    findAndAddClassesInPackageByFile(basePackage, filePath);
                } else if ("jar".equals(protocol)) {
                    JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
                    Enumeration<JarEntry> entries = jar.entries();
                    processJarEntries(basePackage, entries);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("扫描包时发生错误: " + basePackage, e);
        }
    }

    /**
     * 处理文件系统中的类文件
     */
    private static void findAndAddClassesInPackageByFile(String packageName, String packagePath) {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }

        File[] dirFiles = dir.listFiles(file ->
                (file.isDirectory()) || (file.getName().endsWith(".class"))
        );

        if (dirFiles == null) {
            return;
        }

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(),
                        file.getAbsolutePath());
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    Class<?> clazz = Class.forName(packageName + '.' + className);
                    CLASS_CACHE.put(clazz.getSimpleName(), clazz);
                } catch (ClassNotFoundException e) {
                    // 忽略无法加载的类
                }
            }
        }
    }

    /**
     * 处理JAR包中的类
     */
    private static void processJarEntries(String basePackage, Enumeration<JarEntry> entries) {
        String packageDirName = basePackage.replace('.', '/');

        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName();

            if (name.charAt(0) == '/') {
                name = name.substring(1);
            }

            if (name.startsWith(packageDirName) && !entry.isDirectory() && name.endsWith(".class")) {
                String className = name.substring(0, name.length() - 6).replace('/', '.');
                try {
                    Class<?> clazz = Class.forName(className);
                    CLASS_CACHE.put(clazz.getSimpleName(), clazz);
                } catch (ClassNotFoundException e) {
                    // 忽略无法加载的类
                }
            }
        }
    }

    /**
     * 清除缓存，重新初始化时使用
     */
    public static synchronized void clearCache() {
        CLASS_CACHE.clear();
        initialized = false;
    }

    /**
     * 获取缓存的类数量（用于调试）
     */
    public static int getCachedClassCount() {
        return CLASS_CACHE.size();
    }

    /**
     * 获取所有缓存的类名（用于调试）
     */
    public static Set<String> getCachedClassNames() {
        return CLASS_CACHE.keySet();
    }
}
