revoke-cli 0.3.0

Command-line interface for managing Revoke microservices infrastructure
use anyhow::{Result, Context};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use directories::ProjectDirs;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub consul_address: String,
    pub config_namespace: String,
    pub trace_endpoint: String,
    pub default_timeout: u64,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            consul_address: "http://localhost:8500".to_string(),
            config_namespace: "revoke".to_string(),
            trace_endpoint: "http://localhost:4317".to_string(),
            default_timeout: 30,
        }
    }
}

pub fn load_config(path: Option<&str>) -> Result<Config> {
    if let Some(path) = path {
        // Load from specified path
        let content = std::fs::read_to_string(path)
            .context(format!("Failed to read config file: {}", path))?;
        
        let config: Config = toml::from_str(&content)
            .context("Failed to parse config file")?;
        
        Ok(config)
    } else {
        // Try to load from default locations
        if let Some(config_path) = get_default_config_path() {
            if config_path.exists() {
                let content = std::fs::read_to_string(&config_path)?;
                let config: Config = toml::from_str(&content)?;
                return Ok(config);
            }
        }
        
        // Return default config
        Ok(Config::default())
    }
}

fn get_default_config_path() -> Option<PathBuf> {
    if let Some(proj_dirs) = ProjectDirs::from("com", "revoke", "revoke-cli") {
        let config_dir = proj_dirs.config_dir();
        Some(config_dir.join("config.toml"))
    } else {
        None
    }
}

pub fn save_config(config: &Config) -> Result<()> {
    if let Some(config_path) = get_default_config_path() {
        // Create config directory if it doesn't exist
        if let Some(parent) = config_path.parent() {
            std::fs::create_dir_all(parent)?;
        }
        
        let content = toml::to_string_pretty(config)?;
        std::fs::write(config_path, content)?;
        
        Ok(())
    } else {
        Err(anyhow::anyhow!("Failed to determine config directory"))
    }
}