//! CLI configuration.

use std::fs;
use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

/// CLI configuration.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CliConfig {
    /// RPC server URL.
    pub rpc_url: String,

    /// Default wallet name.
    pub default_wallet: String,

    /// Wallet directory.
    pub wallet_dir: PathBuf,

    /// Network (mainnet, testnet, devnet).
    pub network: String,

    /// Default output format.
    pub output_format: String,
}

impl Default for CliConfig {
    fn default() -> Self {
        CliConfig {
            rpc_url: "http://127.0.0.1:16110".to_string(),
            default_wallet: "default".to_string(),
            wallet_dir: default_wallet_dir(),
            network: "mainnet".to_string(),
            output_format: "text".to_string(),
        }
    }
}

impl CliConfig {
    /// Loads config from file or returns default.
    pub fn load_or_default(path: Option<&Path>) -> Self {
        if let Some(p) = path {
            Self::load(p).unwrap_or_default()
        } else if let Some(default_path) = default_config_path() {
            Self::load(&default_path).unwrap_or_default()
        } else {
            Self::default()
        }
    }

    /// Loads config from file.
    pub fn load(path: &Path) -> anyhow::Result<Self> {
        let content = fs::read_to_string(path)?;
        let config: CliConfig = toml::from_str(&content)?;
        Ok(config)
    }

    /// Saves config to file.
    pub fn save(&self, path: &Path) -> anyhow::Result<()> {
        let content = toml::to_string_pretty(self)?;
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        fs::write(path, content)?;
        Ok(())
    }

    /// Gets wallet file path.
    pub fn wallet_path(&self, name: &str) -> PathBuf {
        self.wallet_dir.join(format!("{}.wallet", name))
    }

    /// Gets default wallet path.
    pub fn default_wallet_path(&self) -> PathBuf {
        self.wallet_path(&self.default_wallet)
    }
}

/// Gets default config directory.
pub fn default_config_dir() -> Option<PathBuf> {
    dirs::config_dir().map(|d| d.join("synor"))
}

/// Gets default config path.
pub fn default_config_path() -> Option<PathBuf> {
    default_config_dir().map(|d| d.join("cli.toml"))
}

/// Gets default wallet directory.
pub fn default_wallet_dir() -> PathBuf {
    dirs::data_dir()
        .unwrap_or_else(|| PathBuf::from("."))
        .join("synor")
        .join("wallets")
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn test_config_save_load() {
        let dir = tempdir().unwrap();
        let path = dir.path().join("config.toml");

        let config = CliConfig::default();
        config.save(&path).unwrap();

        let loaded = CliConfig::load(&path).unwrap();
        assert_eq!(loaded.rpc_url, config.rpc_url);
    }
}
