package cd.casic.plugin.core.register.config;

import cd.casic.plugin.annotation.PluginConfiguration;
import cd.casic.plugin.config.PluginProperties;
import cd.casic.plugin.dataobject.pojo.PluginInfo;
import cd.casic.plugin.function.IPluginProcessor;
import cd.casic.plugin.utils.ConfigFileUtils;
import cd.casic.plugin.utils.PathUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.TreeTraversingParser;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.pf4j.RuntimeMode;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.nio.file.Path;

/**
 * @description: 自定义的配置文件
 * @author: mianbin
 * @date: 2025/5/22 9:45
 * @version: 1.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ConfigurationFileProcessor implements IPluginProcessor {

    private final PluginProperties pluginProperties;

    @Override
    public void initialize() throws Exception {
        log.info("Start to hand the configuration Class for plugin");
    }

    @Override
    public void registry(PluginInfo plugin) throws Exception {
        RuntimeMode runtimeMode = pluginProperties.getRuntimeMode();
        for (Class<?> aClass : plugin.getClassList()) {
            PluginConfiguration configDefinition = aClass.getAnnotation(PluginConfiguration.class);
            if (configDefinition == null) {
                continue;
            }
            String fileName = getConfigFileName(configDefinition, runtimeMode);
            DefaultListableBeanFactory defaultListableBeanFactory = plugin.getPluginApplicationContext().getDefaultListableBeanFactory();
            String name = aClass.getSimpleName();
            Path yamlPath = PathUtils.getYamlPath(plugin.getPluginWrapper().getPluginPath(), fileName);
            Resource resource = new FileSystemResource(yamlPath);
            Object parseObject = convert(resource, aClass);
            if (!defaultListableBeanFactory.containsSingleton(name)) {
                defaultListableBeanFactory.registerSingleton(name, parseObject);
            }
        }
    }

    @Override
    public void unRegistry(PluginInfo plugin) throws Exception {
        if (!plugin.getPluginConfigObjects().isEmpty()) {
            plugin.getPluginConfigObjects().clear();
        }
    }

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



    private Object convert(Resource resource, Class<?> configClass) throws Exception {
        // 创建 ObjectMapper 和 YAMLFactory 实例
        ObjectMapper objectMapper = new ObjectMapper();
        YAMLFactory yamlFactory = new YAMLFactory();

        // 使用 try-with-resources 语句自动管理资源
        try (InputStream inputStream = resource.getInputStream();
             YAMLParser yamlParser = yamlFactory.createParser(inputStream)) {
            final JsonNode node = objectMapper.readTree(yamlParser);
            if (node == null) {
                return configClass.getConstructor().newInstance();
            }
            try (TreeTraversingParser treeTraversingParser = new TreeTraversingParser(node)) {
                return objectMapper.readValue(treeTraversingParser, configClass);
            }
        }
    }
}
