package cd.casic.plugin.utils;


import cd.casic.plugin.dataobject.dao.PluginFacadeMemoryCache;
import cd.casic.plugin.dataobject.pojo.PluginFacade;
import cd.casic.plugin.dataobject.pojo.PluginInfo;
import cd.casic.plugin.exception.YmalNotExistsException;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * @Author：mianbin
 * @Package：cd.casic.plugin.utils
 * @Project：ops
 * @name：PluginsUtils
 * @Date：2024/03/18 10:19
 * @Filename：PluginsUtils
 * @description：插件工具类
 */
public class PluginsUtils {

    public static Props getSetting(String pluginId) throws Exception {
        Optional.of(PluginFacadeMemoryCache.getPluginSepc(pluginId)).map(descriptor -> {
                    Props props = new Props();
                    if (!StrUtil.isEmptyIfStr(descriptor.getMapperXmlDir())) {
                        props.put("mybatis.mapper.location", descriptor.getMapperXmlDir());
                    }
                    if (!StrUtil.isEmptyIfStr(descriptor.getStaticDir())) {
                        props.put("static.locations", descriptor.getStaticDir());
                    }
                    return props;
                })
                .orElseThrow(() -> new YmalNotExistsException(List.of("配置文件读取失败")));
        return new Props();
    }

    public static <T> List<T> getAllPluginProxyClass(Class<T> clazz) {
        List<T> result = new ArrayList<>();
        Map<String, PluginFacade> allPlugin = PluginFacadeMemoryCache.getAllPlugin();
        for (String key : allPlugin.keySet()) {
            PluginInfo pluginInfo = allPlugin.get(key).getPluginInfo();
            if (!pluginInfo.getPluginWrapper().getPluginState().equals(PluginState.STARTED)) {
                continue;
            }
            Optional.of(pluginInfo.getPluginApplicationContext().getBean(clazz)).ifPresent(result::add);
        }
        return result;
    }

    /**
     * 扫描插件所在包,获取插件中所有的类名
     *
     * @param basePackage   插件所在包名
     * @param pluginWrapper 插件对象包装类
     * @return 所有的类名集合
     */
    public static Set<String> scanClassPackageName(String basePackage,
                                                   PluginWrapper pluginWrapper) throws IOException {
        Path pluginPath = pluginWrapper.getPluginPath();
        if (pluginPath == null || !Files.exists(pluginPath)) {
            throw new RuntimeException("错误的插件路径");
        }
        File pluginFile = pluginPath.toFile();
        Set<String> classPackageNames = new HashSet<>();
        try (JarFile jar = new JarFile(pluginFile)) {
            // 使用 Enumeration 转 Stream 工具方法将 jarEntries 转换为 Stream
            return Collections.list(jar.entries()).stream()
                    .map(JarEntry::getName)
                    // 过滤出 .class 文件且包名以 basePackage 开头的条目
                    .filter(jarEntryName -> jarEntryName.contains(".class") && jarEntryName.replaceAll("/", ".").startsWith(basePackage))
                    .map(jarEntryName -> jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", "."))
                    .collect(Collectors.toSet());
        }
    }

}
