//! Configuration module for pickleball-elo
//!
//! Loads application configuration from:
//! - config.toml (for static values)
//! - Environment variables (for sensitive values like SMTP credentials)

use serde::{Deserialize, Serialize};
use anyhow::Result;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EloConfig {
    /// K-factor for ELO calculation (typically 32)
    pub k_factor: f64,
    /// Starting rating for new players (typically 1500.0)
    pub starting_rating: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    /// Timezone for match records and daily summaries
    pub timezone: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SmtpConfig {
    /// SMTP server hostname (from PICKLEBALL_SMTP_HOST env var)
    pub host: String,
    /// SMTP server port (from PICKLEBALL_SMTP_PORT env var)
    pub port: u16,
    /// SMTP username (from PICKLEBALL_SMTP_USERNAME env var)
    pub username: String,
    /// SMTP password (from PICKLEBALL_SMTP_PASSWORD env var)
    pub password: String,
    /// From email address (from PICKLEBALL_SMTP_FROM_EMAIL env var)
    pub from_email: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub elo: EloConfig,
    pub app: AppConfig,
    #[serde(skip)]
    pub smtp: Option<SmtpConfig>,
}

impl Config {
    /// Load configuration from config.toml and environment variables
    pub fn load(config_path: &str) -> Result<Self> {
        // Load static config from TOML
        let toml_content = std::fs::read_to_string(config_path)?;
        let mut config: Config = toml::from_str(&toml_content)?;
        
        // Load SMTP config from environment variables (if available)
        if let Ok(host) = std::env::var("PICKLEBALL_SMTP_HOST") {
            config.smtp = Some(SmtpConfig {
                host,
                port: std::env::var("PICKLEBALL_SMTP_PORT")
                    .ok()
                    .and_then(|p| p.parse().ok())
                    .unwrap_or(587),
                username: std::env::var("PICKLEBALL_SMTP_USERNAME").unwrap_or_default(),
                password: std::env::var("PICKLEBALL_SMTP_PASSWORD").unwrap_or_default(),
                from_email: std::env::var("PICKLEBALL_SMTP_FROM_EMAIL")
                    .unwrap_or_else(|_| "noreply@pickleball-elo.local".to_string()),
            });
        }
        
        Ok(config)
    }
    
    /// Load configuration with defaults if file doesn't exist
    pub fn load_or_default(config_path: &str) -> Self {
        match Self::load(config_path) {
            Ok(config) => config,
            Err(_) => {
                eprintln!("Warning: Could not load config from {}, using defaults", config_path);
                Config::default()
            }
        }
    }
}

impl Default for Config {
    fn default() -> Self {
        Self {
            elo: EloConfig {
                k_factor: 32.0,
                starting_rating: 1500.0,
            },
            app: AppConfig {
                timezone: "America/New_York".to_string(),
            },
            smtp: None,
        }
    }
}

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

    #[test]
    fn test_default_config() {
        let config = Config::default();
        assert_eq!(config.elo.k_factor, 32.0);
        assert_eq!(config.elo.starting_rating, 1500.0);
        assert_eq!(config.app.timezone, "America/New_York");
        assert!(config.smtp.is_none());
    }
    
    #[test]
    fn test_config_from_env() {
        // This would require setting env vars in the test environment
        // Skipped for now as we don't set them here
    }
}
