package top.gtb520.java.pve_back_api.config;

import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 配置文件管理器
 * 负责配置文件的检测、创建、加载和解析
 */
public class ConfigManager {
    
    private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private static final String CONFIG_TEMPLATE_PATH = "config.yaml";
    private static final String CONFIG_DIR_NAME = "conf";
    private static final String CONFIG_FILE_NAME = "config.yaml";
    
    /**
     * 初始化配置系统
     * @return 配置文件路径
     */
    public static String initializeConfig() {
        lock.writeLock().lock();
        try {
            String jarDir = getApplicationDirectory();
            Path configDir = Paths.get(jarDir, CONFIG_DIR_NAME);
            Path configFile = configDir.resolve(CONFIG_FILE_NAME);
            
            System.out.println("应用运行目录: " + jarDir);
            
            // 确保配置目录存在
            createConfigDirectory(configDir);
            
            // 检查并创建配置文件
            if (!Files.exists(configFile)) {
                createDefaultConfigFile(configFile);
            } else {
                System.out.println("配置文件已存在: " + configFile.toString());
            }
            
            // 加载配置到全局变量
            loadConfiguration(configFile.toString());
            
            return configFile.toString();
            
        } catch (Exception e) {
            System.err.println("配置初始化失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        } finally {
            lock.writeLock().unlock();
        }
    }
    
    /**
     * 获取应用运行目录
     */
    private static String getApplicationDirectory() {
        try {
            String classPath = ConfigManager.class.getProtectionDomain()
                    .getCodeSource().getLocation().getPath();
            classPath = java.net.URLDecoder.decode(classPath, "UTF-8");
            
            File classFile = new File(classPath);
            
            if (classFile.isFile() && classPath.endsWith(".jar")) {
                return classFile.getParent();
            } else if (classFile.isDirectory()) {
                String projectDir = classFile.getAbsolutePath();
                if (projectDir.contains("target" + File.separator + "classes")) {
                    return projectDir.substring(0, projectDir.indexOf("target"));
                }
                return projectDir;
            }
        } catch (Exception e) {
            System.err.println("获取应用目录失败: " + e.getMessage());
        }
        return System.getProperty("user.dir");
    }
    
    /**
     * 创建配置目录
     */
    private static void createConfigDirectory(Path configDir) throws IOException {
        if (!Files.exists(configDir)) {
            Files.createDirectories(configDir);
            System.out.println("创建配置目录: " + configDir.toString());
        }
    }
    
    /**
     * 创建默认配置文件
     */
    private static void createDefaultConfigFile(Path configFile) throws IOException {
        System.out.println("创建默认配置文件: " + configFile.toString());
        
        try (InputStream templateStream = getResourceAsStream(CONFIG_TEMPLATE_PATH);
             OutputStream outputStream = Files.newOutputStream(configFile)) {
            
            if (templateStream == null) {
                createMinimalConfigFile(configFile);
            } else {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = templateStream.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, length);
                }
                System.out.println("从模板创建配置文件成功");
            }
        }
    }
    
    /**
     * 创建最小化配置文件（当模板不可用时）
     */
    private static void createMinimalConfigFile(Path configFile) throws IOException {
        String minimalConfig = "# PVE后端API配置文件\n" +
                "global:\n" +
                "  http_ip: \"0.0.0.0\"\n" +
                "  http_port: \"8080\"\n\n" +
                "database:\n" +
                "  mysql_jdbc: \"\"\n" +
                "  mysql_username: \"\"\n" +
                "  mysql_password: \"\"\n\n" +
                "pve:\n" +
                "  # 推荐使用拆分配置（优先级更高）\n" +
                "  hostname_ip: \"10.168.2.18\"\n" +
                "  port: \"8006\"\n" +
                "  protocol: \"https\"\n" +
                "  # 或者使用完整URL（向后兼容）\n" +
                "  url: \"https://10.168.2.18:8006/\"\n" +
                "  # API Token配置\n" +
                "  api_tocken_name: \"dev\"\n" +
                "  api_token_id: \"root@pam!dev\"\n" +
                "  api_token_secret: \"68e9dac5-3110-4f1b-b33a-feeaa4014f63\"\n";
        
        Files.write(configFile, minimalConfig.getBytes("UTF-8"));
        System.out.println("创建最小化配置文件成功");
    }
    
    /**
     * 从资源获取输入流
     */
    private static InputStream getResourceAsStream(String resourcePath) {
        // 首先尝试从类路径获取
        InputStream stream = ConfigManager.class.getClassLoader().getResourceAsStream(resourcePath);
        if (stream != null) {
            return stream;
        }
        
        // 如果类路径中没有，尝试从文件系统获取
        try {
            Path resourceFile = Paths.get(resourcePath);
            if (Files.exists(resourceFile)) {
                return Files.newInputStream(resourceFile);
            }
        } catch (IOException e) {
            // 忽略文件系统访问异常
        }
        
        return null;
    }
    
    /**
     * 加载配置文件到全局变量
     * @param configFilePath 配置文件路径
     */
    private static void loadConfiguration(String configFilePath) {
        try {
            Map<String, Object> configData = loadYamlConfig(configFilePath);
            
            if (configData == null) {
                handleEmptyConfig();
                return;
            }
            
            // 解析并设置配置值
            parseAndSetConfig(configData);
            AppConfig.markAsLoaded();
            
            System.out.println("✅ 配置加载成功!");
            AppConfig.printCurrentConfig();
            
        } catch (Exception e) {
            handleConfigLoadError(e);
        }
    }

    /**
     * 加载YAML配置文件
     */
    private static Map<String, Object> loadYamlConfig(String configFilePath) throws IOException {
        Yaml yaml = new Yaml();
        try (InputStream inputStream = Files.newInputStream(Paths.get(configFilePath))) {
            return yaml.load(inputStream);
        }
    }
    
    /**
     * 处理空配置情况
     */
    private static void handleEmptyConfig() {
        System.err.println("❌ 配置文件为空或格式错误");
    }
    
    /**
     * 处理配置加载错误
     */
    private static void handleConfigLoadError(Exception e) {
        System.err.println("❌ 加载配置文件失败: " + e.getMessage());
        e.printStackTrace();
    }

    /**
     * 解析配置数据并设置到全局变量
     * @param data 配置数据映射
     */
    private static void parseAndSetConfig(Map<String, Object> data) {
        try {
            parseGlobalSection(data);
            parseDatabaseSection(data);
            parsePveSection(data);

        } catch (Exception e) {
            System.err.println("❌ 解析配置数据时发生错误: " + e.getMessage());
            throw e;
        }
    }
    
    /**
     * 解析全局配置部分
     */
    private static void parseGlobalSection(Map<String, Object> data) {
        if (!data.containsKey("global")) {
            return;
        }
        
        @SuppressWarnings("unchecked")
        Map<String, Object> global = (Map<String, Object>) data.get("global");
        AppConfig.HTTP_IP = getStringValue(global, "http_ip", AppConfig.HTTP_IP);
        AppConfig.HTTP_PORT = getStringValue(global, "http_port", AppConfig.HTTP_PORT);
    }
    
    /**
     * 解析数据库配置部分
     */
    private static void parseDatabaseSection(Map<String, Object> data) {
        if (!data.containsKey("database")) {
            return;
        }
        
        @SuppressWarnings("unchecked")
        Map<String, Object> database = (Map<String, Object>) data.get("database");
        AppConfig.MYSQL_JDBC = getStringValue(database, "mysql_jdbc", AppConfig.MYSQL_JDBC);
        AppConfig.MYSQL_USERNAME = getStringValue(database, "mysql_username", AppConfig.MYSQL_USERNAME);
        AppConfig.MYSQL_PASSWORD = getStringValue(database, "mysql_password", AppConfig.MYSQL_PASSWORD);
    }
    
    /**
     * 解析PVE配置部分
     */
    private static void parsePveSection(Map<String, Object> data) {
        if (!data.containsKey("pve")) {
            return;
        }
        
        @SuppressWarnings("unchecked")
        Map<String, Object> pve = (Map<String, Object>) data.get("pve");
        processPveUrlConfig(pve);
        processPveApiTokens(pve);
    }
    
    /**
     * 处理PVE URL相关配置
     */
    private static void processPveUrlConfig(Map<String, Object> pve) {
        // 保留原始URL配置
        AppConfig.PVE_URL = getStringValue(pve, "url", AppConfig.PVE_URL);

        // 解析拆分后的PVE配置（优先级更高）
        AppConfig.PVE_HOSTNAME_IP = getStringValue(pve, "hostname_ip", AppConfig.PVE_HOSTNAME_IP);
        AppConfig.PVE_PORT = getStringValue(pve, "port", AppConfig.PVE_PORT);
        AppConfig.PVE_PROTOCOL = getStringValue(pve, "protocol", AppConfig.PVE_PROTOCOL);

        // 如果提供了拆分配置，同时更新URL
        if (hasValidHostname()) {
            AppConfig.PVE_URL = buildPveUrl();
        }
        // 如果只有URL而没有拆分配置，则解析URL
        else if (hasValidUrl()) {
            parsePveUrl(AppConfig.PVE_URL);
        }
    }
    
    /**
     * 处理PVE API令牌配置
     */
    private static void processPveApiTokens(Map<String, Object> pve) {
        AppConfig.PVE_API_TOKEN_NAME = getStringValue(pve, "api_tocken_name", AppConfig.PVE_API_TOKEN_NAME);
        AppConfig.PVE_API_TOKEN_ID = getStringValue(pve, "api_token_id", AppConfig.PVE_API_TOKEN_ID);
        AppConfig.PVE_API_TOKEN_SECRET = getStringValue(pve, "api_token_secret", AppConfig.PVE_API_TOKEN_SECRET);
    }
    
    /**
     * 检查是否有有效的主机名配置
     */
    private static boolean hasValidHostname() {
        return AppConfig.PVE_HOSTNAME_IP != null && !AppConfig.PVE_HOSTNAME_IP.isEmpty();
    }
    
    /**
     * 检查是否有有效的URL配置
     */
    private static boolean hasValidUrl() {
        return AppConfig.PVE_URL != null && !AppConfig.PVE_URL.isEmpty();
    }
    
    /**
     * 构建PVE完整URL
     */
    private static String buildPveUrl() {
        return AppConfig.PVE_PROTOCOL + "://" + AppConfig.PVE_HOSTNAME_IP + ":" + AppConfig.PVE_PORT + "/";
    }

    /**
     * 从完整URL解析PVE主机和端口信息
     */
    private static void parsePveUrl(String url) {
        try {
            if (url == null || url.isEmpty()) {
                return;
            }
            
            // 移除末尾的斜杠
            if (url.endsWith("/")) {
                url = url.substring(0, url.length() - 1);
            }
            
            // 解析协议
            if (url.startsWith("https://")) {
                AppConfig.PVE_PROTOCOL = "https";
                url = url.substring(8);
            } else if (url.startsWith("http://")) {
                AppConfig.PVE_PROTOCOL = "http";
                url = url.substring(7);
            }
            
            // 解析主机和端口
            int portIndex = url.lastIndexOf(":");
            if (portIndex > 0) {
                AppConfig.PVE_HOSTNAME_IP = url.substring(0, portIndex);
                String portStr = url.substring(portIndex + 1);
                if (!portStr.isEmpty()) {
                    AppConfig.PVE_PORT = portStr;
                }
            } else {
                AppConfig.PVE_HOSTNAME_IP = url;
            }
            
        } catch (Exception e) {
            System.err.println("解析PVE URL时发生错误: " + e.getMessage());
        }
    }

    /**
     * 安全获取字符串值
     */
    private static String getStringValue(Map<String, Object> map, String key, String defaultValue) {
        if (map.containsKey(key)) {
            Object value = map.get(key);
            return value != null ? value.toString() : defaultValue;
        }
        return defaultValue;
    }
    
    /**
     * 重新加载配置
     */
    public static boolean reloadConfiguration() {
        lock.writeLock().lock();
        try {
            String jarDir = getApplicationDirectory();
            Path configFile = Paths.get(jarDir, CONFIG_DIR_NAME, CONFIG_FILE_NAME);
            
            if (Files.exists(configFile)) {
                AppConfig.resetToDefaults();
                loadConfiguration(configFile.toString());
                return true;
            } else {
                System.err.println("配置文件不存在，无法重新加载");
                return false;
            }
        } catch (Exception e) {
            System.err.println("重新加载配置失败: " + e.getMessage());
            return false;
        } finally {
            lock.writeLock().unlock();
        }
    }
}
