//! Configuration module for the web dashboard
//!
//! Supports configuration via:
//! 1. Environment variables (DASHBOARD_*)
//! 2. Configuration file (.dashboard/config.toml or custom path)
//! 3. Hardcoded defaults

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Dashboard configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashboardConfig {
    /// Server settings
    pub server: ServerConfig,
    /// API server settings
    pub api: ApiConfig,
    /// Features
    #[serde(default)]
    pub features: FeaturesConfig,
}

/// Server configuration (web dashboard)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    /// Server host
    #[serde(default = "default_dashboard_host")]
    pub host: String,
    /// Server port
    #[serde(default = "default_dashboard_port")]
    pub port: u16,
    /// Environment (development, production, staging)
    #[serde(default = "default_environment")]
    pub environment: String,
}

/// API server configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiConfig {
    /// API base URL
    #[serde(default = "default_api_base")]
    pub base_url: String,
    /// WebSocket URL for real-time updates
    #[serde(default = "default_ws_url")]
    pub ws_url: String,
    /// API request timeout in seconds
    #[serde(default = "default_api_timeout")]
    pub timeout_secs: u64,
    /// Enable automatic sync with server
    #[serde(default = "default_enable_sync")]
    pub enable_sync: bool,
    /// Sync interval in seconds
    #[serde(default = "default_sync_interval")]
    pub sync_interval_secs: u64,
}

/// Features configuration
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FeaturesConfig {
    /// Enable real-time sync via WebSocket
    #[serde(default)]
    pub realtime_sync: bool,
    /// Enable auto-refresh
    #[serde(default)]
    pub auto_refresh: bool,
    /// Enable dark mode support
    #[serde(default)]
    pub dark_mode: bool,
    /// Enable offline mode
    #[serde(default)]
    pub offline_mode: bool,
}

// Default values
fn default_dashboard_host() -> String {
    "127.0.0.1".to_string()
}

fn default_dashboard_port() -> u16 {
    3001
}

fn default_environment() -> String {
    "development".to_string()
}

fn default_api_base() -> String {
    "http://localhost:3000/api".to_string()
}

fn default_ws_url() -> String {
    "ws://localhost:3000/ws".to_string()
}

fn default_api_timeout() -> u64 {
    30
}

fn default_enable_sync() -> bool {
    true
}

fn default_sync_interval() -> u64 {
    5
}

impl Default for DashboardConfig {
    fn default() -> Self {
        Self {
            server: ServerConfig {
                host: default_dashboard_host(),
                port: default_dashboard_port(),
                environment: default_environment(),
            },
            api: ApiConfig {
                base_url: default_api_base(),
                ws_url: default_ws_url(),
                timeout_secs: default_api_timeout(),
                enable_sync: default_enable_sync(),
                sync_interval_secs: default_sync_interval(),
            },
            features: FeaturesConfig::default(),
        }
    }
}

impl DashboardConfig {
    /// Load configuration from file or environment
    pub fn load() -> Self {
        // Try to load from config file first
        if let Ok(config) = Self::load_from_file() {
            return config;
        }

        // Load from environment variables
        Self::load_from_env()
    }

    /// Load configuration from TOML file
    fn load_from_file() -> Result<Self, Box<dyn std::error::Error>> {
        let config_path = PathBuf::from(".dashboard/config.toml");
        if !config_path.exists() {
            return Err("Config file not found".into());
        }

        let content = std::fs::read_to_string(&config_path)?;
        let config: DashboardConfig = toml::from_str(&content)?;
        tracing::info!("Dashboard config loaded from {}", config_path.display());
        Ok(config)
    }

    /// Load configuration from environment variables
    fn load_from_env() -> Self {
        let mut config = Self::default();

        // Override from environment variables
        if let Ok(host) = std::env::var("DASHBOARD_HOST") {
            config.server.host = host;
        }
        if let Ok(port) = std::env::var("DASHBOARD_PORT") {
            if let Ok(p) = port.parse() {
                config.server.port = p;
            }
        }
        if let Ok(env) = std::env::var("DASHBOARD_ENVIRONMENT") {
            config.server.environment = env;
        }

        if let Ok(base_url) = std::env::var("API_BASE_URL") {
            config.api.base_url = base_url;
        }
        if let Ok(ws_url) = std::env::var("API_WS_URL") {
            config.api.ws_url = ws_url;
        }
        if let Ok(timeout) = std::env::var("API_TIMEOUT_SECS") {
            if let Ok(t) = timeout.parse() {
                config.api.timeout_secs = t;
            }
        }
        if let Ok(enable_sync) = std::env::var("ENABLE_SYNC") {
            config.api.enable_sync = enable_sync.to_lowercase() == "true";
        }

        tracing::info!("Dashboard config loaded from environment");
        config
    }

    /// Log configuration (mask sensitive values)
    pub fn log_config(&self) {
        tracing::info!("=== Dashboard Configuration ===");
        tracing::info!(
            "Server: {}:{} ({})",
            self.server.host,
            self.server.port,
            self.server.environment
        );
        tracing::info!("API Base URL: {}", self.api.base_url);
        tracing::info!(
            "WebSocket URL: {}",
            if self.api.ws_url.is_empty() {
                "(disabled)"
            } else {
                &self.api.ws_url
            }
        );
        tracing::info!("API Timeout: {}s", self.api.timeout_secs);
        tracing::info!("Real-time Sync: {}", self.api.enable_sync);
        if self.api.enable_sync {
            tracing::info!("Sync Interval: {}s", self.api.sync_interval_secs);
        }
        tracing::info!("Features: {:?}", self.features);
    }
}

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

    #[test]
    fn test_default_config() {
        let config = DashboardConfig::default();
        assert_eq!(config.server.port, 3001);
        assert_eq!(config.api.base_url, "http://localhost:3000/api");
        assert!(config.api.enable_sync);
    }

    #[test]
    fn test_config_from_env() {
        std::env::set_var("DASHBOARD_PORT", "3002");
        std::env::set_var("API_BASE_URL", "http://localhost:3001/api");

        let config = DashboardConfig::load_from_env();
        assert_eq!(config.server.port, 3002);
        assert_eq!(config.api.base_url, "http://localhost:3001/api");
    }
}
