package cd.casic.plugin.register.config;

import cd.casic.plugin.PluginConfigWrapper;
import cd.casic.plugin.PluginInfo;
import cd.casic.plugin.PluginProperties;
import cd.casic.plugin.PluginYamlConfigurationParser;
import cd.casic.plugin.annotation.PluginConfiguration;
import cd.casic.plugin.register.BasePluginHandler;
import org.pf4j.RuntimeMode;
import org.pf4j.util.StringUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 配置文件处理器，用于处理插件独立的配置文件
 */
public class ConfigurationFileHandler implements BasePluginHandler {
    private final PluginYamlConfigurationParser configurationParser;

    public ConfigurationFileHandler(){
        this.configurationParser = new PluginYamlConfigurationParser();
    }

    @Override
    public void initialize() throws Exception {

    }

    @Override
    public void registry(PluginInfo plugin) throws Exception {
        PluginProperties pluginProperties = plugin.getMainApplicationContext().getBean(PluginProperties.class);
        RuntimeMode runtimeMode = pluginProperties.getRuntimeMode();
        for(Class<?> aClass : plugin.getClassList()){
            PluginConfiguration configDefinition = aClass.getAnnotation(PluginConfiguration.class);
            if(configDefinition == null){
                continue;
            }
            String fileName = getConfigFileName(configDefinition, runtimeMode);
            Object parseObject;
            if(!StringUtils.isNullOrEmpty(fileName)){
                PluginConfigWrapper pluginConfigWrapper =
                        new PluginConfigWrapper(fileName, aClass);
                parseObject = configurationParser.parse(plugin, pluginConfigWrapper);
            } else {
                try {
                    parseObject = aClass.getDeclaredConstructor().newInstance();
                } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) {
                    throw new RuntimeException("Failed to instantiate class " + aClass.getName(), e);
                }
            }

            String name = aClass.getSimpleName();
            DefaultListableBeanFactory listableBeanFactory = plugin.getPluginApplicationContext().getDefaultListableBeanFactory();
            if(!listableBeanFactory.containsSingleton(name)) {
                listableBeanFactory.registerSingleton(name, parseObject);
            }
            plugin.addPluginConfigObject(parseObject);
        }
    }

    @Override
    public void unRegistry(PluginInfo plugin) throws Exception {
        /*上面的写法没有考虑到资源泄露，这里把clear，关闭资源*/
        List<Object> objectsToClear = new ArrayList<>(plugin.getPluginConfigObjects());
        plugin.getPluginConfigObjects().clear();
        for (Object obj : objectsToClear) {
            if (obj instanceof AutoCloseable) {
                ((AutoCloseable) obj).close();
            }
        }
    }

    /**
     * 获取插件独立配置文件的文件名
     * @param pluginConfiguration 插件配置类上的自定义注解
     * @param runtimeMode 插件系统运行模式
     * @return 插件独立配置文件的文件名
     */
    private String getConfigFileName(PluginConfiguration pluginConfiguration, RuntimeMode runtimeMode){
        String fileName = pluginConfiguration.fileName();
        if(StringUtils.isNullOrEmpty(fileName)){
            return null;
        }
        String suffix = "";
        if(runtimeMode == RuntimeMode.DEPLOYMENT){
            // deployment模式
            suffix = pluginConfiguration.deploySuffix();
        } else if(runtimeMode == RuntimeMode.DEVELOPMENT){
            // development模式
            suffix = pluginConfiguration.devSuffix();
        }
        return joinConfigFileName(fileName, suffix);
    }

    /**
     * 拼接插件独立配置文件的文件名和环境后缀
     * @param fileName 插件独立配置文件文件名
     * @param suffix 配置文件环境后缀，PluginConfiguration中定义
     * @return 拼接后的文件名
     */
    private String joinConfigFileName(String fileName, String suffix){
        if(StringUtils.isNullOrEmpty(fileName)){
            return null;
        }
        String fileNamePrefix;
        String fileNamePrefixSuffix;

        if(fileName.lastIndexOf(".") == -1) {
            fileNamePrefix = fileName;
            fileNamePrefixSuffix = "";
        } else {
            int index = fileName.lastIndexOf(".");
            fileNamePrefix = fileName.substring(0, index);
            fileNamePrefixSuffix = fileName.substring(index);
        }
        if(suffix == null){
            suffix = "";
        }
        if(StringUtils.isNotNullOrEmpty(suffix) && !suffix.startsWith("-")){
            suffix = "-" + suffix;
        }
        return fileNamePrefix + suffix + fileNamePrefixSuffix;
    }
}