//! Runtime configuration layer for environment-aware defaults.
//!
//! This module provides Tier 2 runtime configuration that complements the
//! compile-time constants in `common::thresholds`. Values here can be overridden
//! via environment variables to support different deployment environments
//! (development, staging, production) without recompilation.
//!
//! # Architecture
//!
//! - Tier 1 (Compile-time): `common::thresholds` - Performance-critical constants
//! - Tier 2 (Runtime): This module - Environment-aware operational parameters
//! - Tier 3 (Database): Hot-reload via PostgreSQL NOTIFY/LISTEN
//!
//! # Environment Variables
//!
//! ## Database Configuration
//! - `DATABASE_QUERY_TIMEOUT_MS` - Query timeout in milliseconds (default: environment-aware)
//! - `DATABASE_CONNECTION_TIMEOUT_MS` - Connection timeout in milliseconds
//! - `DATABASE_POOL_SIZE` - Connection pool size
//! - `DATABASE_MAX_POOL_SIZE` - Maximum pool size
//! - `DATABASE_ACQUIRE_TIMEOUT_MS` - Pool acquire timeout in milliseconds
//!
//! ## Cache Configuration
//! - `CACHE_POSITION_TTL_SECS` - Position cache TTL in seconds
//! - `CACHE_VAR_TTL_SECS` - VaR calculation cache TTL in seconds
//! - `CACHE_COMPLIANCE_TTL_SECS` - Compliance check cache TTL in seconds
//! - `CACHE_MARKET_DATA_TTL_SECS` - Market data cache TTL in seconds
//! - `CACHE_MODEL_PREDICTION_TTL_SECS` - Model prediction cache TTL in seconds
//!
//! ## Network Configuration
//! - `NETWORK_GRPC_CONNECT_TIMEOUT_SECS` - gRPC connect timeout in seconds
//! - `NETWORK_GRPC_REQUEST_TIMEOUT_SECS` - gRPC request timeout in seconds
//! - `NETWORK_KEEP_ALIVE_INTERVAL_SECS` - Keep-alive interval in seconds
//! - `NETWORK_KEEP_ALIVE_TIMEOUT_SECS` - Keep-alive timeout in seconds
//! - `NETWORK_MAX_CONCURRENT_CONNECTIONS` - Maximum concurrent connections
//!
//! ## Retry Configuration
//! - `RETRY_INITIAL_DELAY_MS` - Initial retry delay in milliseconds
//! - `RETRY_MAX_DELAY_SECS` - Maximum retry delay in seconds
//! - `RETRY_MAX_ATTEMPTS` - Maximum retry attempts
//! - `RETRY_BACKOFF_MULTIPLIER` - Backoff multiplier for exponential backoff
//!
//! ## Safety Configuration
//! - `SAFETY_CHECK_TIMEOUT_MS` - Safety check timeout in milliseconds
//! - `SAFETY_AUTO_RECOVERY_DELAY_SECS` - Auto-recovery delay in seconds
//! - `SAFETY_LOSS_CHECK_INTERVAL_SECS` - Loss check interval in seconds
//! - `SAFETY_POSITION_CHECK_INTERVAL_SECS` - Position check interval in seconds
//!
//! ## ML Configuration
//! - `ML_MAX_BATCH_SIZE` - Maximum batch size for ML inference
//! - `ML_INFERENCE_TIMEOUT_MS` - ML inference timeout in milliseconds
//! - `ML_MODEL_CACHE_CLEANUP_INTERVAL_SECS` - Model cache cleanup interval
//! - `ML_DRIFT_CHECK_INTERVAL_SECS` - Drift detection check interval
//!
//! ## Risk Configuration
//! - `RISK_VAR_LOOKBACK_DAYS` - VaR lookback period in trading days
//! - `RISK_VAR_CONFIDENCE` - VaR confidence level (0.0-1.0)
//! - `RISK_MAX_DRAWDOWN_WARNING_PCT` - Max drawdown warning threshold
//!
//! # Example
//!
//! ```rust,no_run
//! use config::runtime::{RuntimeConfig, Environment};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Auto-detect environment and load from env vars
//! let config = RuntimeConfig::from_env()?;
//!
//! // Or specify environment explicitly
//! let prod_config = RuntimeConfig::from_env_with_environment(Environment::Production)?;
//!
//! // Or use defaults for specific environment
//! let dev_config = RuntimeConfig::with_defaults(Environment::Development);
//!
//! println!("Database query timeout: {:?}", config.database.query_timeout);
//! println!("Position cache TTL: {:?}", config.cache.position_ttl);
//! # Ok(())
//! # }
//! ```

use crate::error::{ConfigError, ConfigResult};
use serde::{Deserialize, Serialize};
use std::time::Duration;

/// Deployment environment enumeration.
///
/// Determines default values for runtime configuration parameters.
///
/// Different environments have different performance vs safety trade-offs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Environment {
    /// Development environment - Relaxed timeouts, verbose logging
    Development,
    /// Staging environment - Production-like settings with some debug features
    Staging,
    /// Production environment - Optimized for performance and reliability
    Production,
}

impl Environment {
    /// Detects the environment from the ENVIRONMENT environment variable.
    ///
    /// Falls back to Development if not set or invalid.
    pub fn detect() -> Self {
        match std::env::var("ENVIRONMENT")
            .unwrap_or_else(|_| "development".to_owned())
            .to_lowercase()
            .as_str()
        {
            "production" | "prod" => Environment::Production,
            "staging" | "stage" => Environment::Staging,
            _ => Environment::Development,
        }
    }

    /// Returns true if this is a production environment.
    pub const fn is_production(&self) -> bool {
        matches!(self, Environment::Production)
    }

    /// Returns true if this is a development environment.
    pub const fn is_development(&self) -> bool {
        matches!(self, Environment::Development)
    }
}

/// Database runtime configuration.
///
/// Controls database connection pooling, timeouts, and query execution limits.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseRuntimeConfig {
    /// Query timeout for standard operations
    pub query_timeout: Duration,
    /// Connection establishment timeout
    pub connection_timeout: Duration,
    /// Pool acquire timeout
    pub acquire_timeout: Duration,
    /// Default pool size
    pub pool_size: u32,
    /// Maximum pool size
    pub max_pool_size: u32,
    /// Connection lifetime
    pub connection_lifetime: Duration,
    /// Idle timeout
    pub idle_timeout: Duration,
}

impl DatabaseRuntimeConfig {
    /// Creates configuration with environment-aware defaults.
    pub const fn with_defaults(env: Environment) -> Self {
        match env {
            Environment::Development => Self {
                query_timeout: Duration::from_millis(5000), // More relaxed for debugging
                connection_timeout: Duration::from_millis(500),
                acquire_timeout: Duration::from_millis(200),
                pool_size: 10,
                max_pool_size: 50,
                connection_lifetime: Duration::from_secs(1800), // 30 minutes
                idle_timeout: Duration::from_secs(600),         // 10 minutes
            },
            Environment::Staging => Self {
                query_timeout: Duration::from_millis(2000),
                connection_timeout: Duration::from_millis(200),
                acquire_timeout: Duration::from_millis(100),
                pool_size: 15,
                max_pool_size: 75,
                connection_lifetime: Duration::from_secs(3600), // 1 hour
                idle_timeout: Duration::from_secs(300),         // 5 minutes
            },
            Environment::Production => Self {
                query_timeout: Duration::from_millis(1000), // Tight timeout for HFT
                connection_timeout: Duration::from_millis(100),
                acquire_timeout: Duration::from_millis(50),
                pool_size: 20,
                max_pool_size: 100,
                connection_lifetime: Duration::from_secs(3600), // 1 hour
                idle_timeout: Duration::from_secs(300),         // 5 minutes
            },
        }
    }

    /// Loads from environment variables with fallback to defaults.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn from_env(env: Environment) -> ConfigResult<Self> {
        let defaults = Self::with_defaults(env);

        Ok(Self {
            query_timeout: parse_env_duration_ms(
                "DATABASE_QUERY_TIMEOUT_MS",
                defaults.query_timeout,
            )?,
            connection_timeout: parse_env_duration_ms(
                "DATABASE_CONNECTION_TIMEOUT_MS",
                defaults.connection_timeout,
            )?,
            acquire_timeout: parse_env_duration_ms(
                "DATABASE_ACQUIRE_TIMEOUT_MS",
                defaults.acquire_timeout,
            )?,
            pool_size: parse_env_u32("DATABASE_POOL_SIZE", defaults.pool_size)?,
            max_pool_size: parse_env_u32("DATABASE_MAX_POOL_SIZE", defaults.max_pool_size)?,
            connection_lifetime: parse_env_duration_secs(
                "DATABASE_CONNECTION_LIFETIME_SECS",
                defaults.connection_lifetime,
            )?,
            idle_timeout: parse_env_duration_secs(
                "DATABASE_IDLE_TIMEOUT_SECS",
                defaults.idle_timeout,
            )?,
        })
    }

    /// Validates the configuration.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn validate(&self) -> ConfigResult<()> {
        if self.query_timeout.as_millis() == 0 {
            return Err(ConfigError::Invalid(
                "Query timeout must be positive".into(),
            ));
        }
        if self.pool_size == 0 {
            return Err(ConfigError::Invalid("Pool size must be positive".into()));
        }
        if self.pool_size > self.max_pool_size {
            return Err(ConfigError::Invalid(
                "Pool size cannot exceed max pool size".into(),
            ));
        }
        Ok(())
    }
}

/// Cache TTL runtime configuration.
///
/// Controls time-to-live values for various cache types.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheRuntimeConfig {
    /// Position cache TTL
    pub position_ttl: Duration,
    /// VaR calculation cache TTL
    pub var_ttl: Duration,
    /// Compliance check cache TTL
    pub compliance_ttl: Duration,
    /// Market data cache TTL
    pub market_data_ttl: Duration,
    /// Model prediction cache TTL
    pub model_prediction_ttl: Duration,
}

impl CacheRuntimeConfig {
    /// Creates configuration with environment-aware defaults.
    pub const fn with_defaults(env: Environment) -> Self {
        match env {
            Environment::Development => Self {
                position_ttl: Duration::from_secs(120), // Longer TTL for debugging
                var_ttl: Duration::from_secs(7200),     // 2 hours
                compliance_ttl: Duration::from_secs(172_800), // 48 hours
                market_data_ttl: Duration::from_secs(600), // 10 minutes
                model_prediction_ttl: Duration::from_secs(120), // 2 minutes
            },
            Environment::Staging => Self {
                position_ttl: Duration::from_secs(90),
                var_ttl: Duration::from_secs(5400), // 1.5 hours
                compliance_ttl: Duration::from_secs(129_600), // 36 hours
                market_data_ttl: Duration::from_secs(450), // 7.5 minutes
                model_prediction_ttl: Duration::from_secs(90),
            },
            Environment::Production => Self {
                position_ttl: Duration::from_secs(60),      // 1 minute for HFT
                var_ttl: Duration::from_secs(3600),         // 1 hour
                compliance_ttl: Duration::from_secs(86400), // 24 hours
                market_data_ttl: Duration::from_secs(300),  // 5 minutes
                model_prediction_ttl: Duration::from_secs(60), // 1 minute
            },
        }
    }

    /// Loads from environment variables with fallback to defaults.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn from_env(env: Environment) -> ConfigResult<Self> {
        let defaults = Self::with_defaults(env);

        Ok(Self {
            position_ttl: parse_env_duration_secs(
                "CACHE_POSITION_TTL_SECS",
                defaults.position_ttl,
            )?,
            var_ttl: parse_env_duration_secs("CACHE_VAR_TTL_SECS", defaults.var_ttl)?,
            compliance_ttl: parse_env_duration_secs(
                "CACHE_COMPLIANCE_TTL_SECS",
                defaults.compliance_ttl,
            )?,
            market_data_ttl: parse_env_duration_secs(
                "CACHE_MARKET_DATA_TTL_SECS",
                defaults.market_data_ttl,
            )?,
            model_prediction_ttl: parse_env_duration_secs(
                "CACHE_MODEL_PREDICTION_TTL_SECS",
                defaults.model_prediction_ttl,
            )?,
        })
    }

    /// Validates the configuration.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn validate(&self) -> ConfigResult<()> {
        if self.position_ttl.as_secs() == 0 {
            return Err(ConfigError::Invalid("Position TTL must be positive".into()));
        }
        if self.var_ttl.as_secs() == 0 {
            return Err(ConfigError::Invalid("VaR TTL must be positive".into()));
        }
        Ok(())
    }
}

/// Network timeout runtime configuration.
///
/// Controls gRPC and network-related timeouts.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeoutConfig {
    /// gRPC connect timeout
    pub grpc_connect_timeout: Duration,
    /// gRPC request timeout
    pub grpc_request_timeout: Duration,
    /// Keep-alive interval
    pub keep_alive_interval: Duration,
    /// Keep-alive timeout
    pub keep_alive_timeout: Duration,
    /// Maximum concurrent connections
    pub max_concurrent_connections: u32,
}

impl TimeoutConfig {
    /// Creates configuration with environment-aware defaults.
    pub const fn with_defaults(env: Environment) -> Self {
        match env {
            Environment::Development => Self {
                grpc_connect_timeout: Duration::from_secs(10),
                grpc_request_timeout: Duration::from_secs(30),
                keep_alive_interval: Duration::from_secs(60),
                keep_alive_timeout: Duration::from_secs(10),
                max_concurrent_connections: 50,
            },
            Environment::Staging => Self {
                grpc_connect_timeout: Duration::from_secs(7),
                grpc_request_timeout: Duration::from_secs(20),
                keep_alive_interval: Duration::from_secs(45),
                keep_alive_timeout: Duration::from_secs(7),
                max_concurrent_connections: 75,
            },
            Environment::Production => Self {
                grpc_connect_timeout: Duration::from_secs(5),
                grpc_request_timeout: Duration::from_secs(10),
                keep_alive_interval: Duration::from_secs(30),
                keep_alive_timeout: Duration::from_secs(5),
                max_concurrent_connections: 100,
            },
        }
    }

    /// Loads from environment variables with fallback to defaults.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn from_env(env: Environment) -> ConfigResult<Self> {
        let defaults = Self::with_defaults(env);

        Ok(Self {
            grpc_connect_timeout: parse_env_duration_secs(
                "NETWORK_GRPC_CONNECT_TIMEOUT_SECS",
                defaults.grpc_connect_timeout,
            )?,
            grpc_request_timeout: parse_env_duration_secs(
                "NETWORK_GRPC_REQUEST_TIMEOUT_SECS",
                defaults.grpc_request_timeout,
            )?,
            keep_alive_interval: parse_env_duration_secs(
                "NETWORK_KEEP_ALIVE_INTERVAL_SECS",
                defaults.keep_alive_interval,
            )?,
            keep_alive_timeout: parse_env_duration_secs(
                "NETWORK_KEEP_ALIVE_TIMEOUT_SECS",
                defaults.keep_alive_timeout,
            )?,
            max_concurrent_connections: parse_env_u32(
                "NETWORK_MAX_CONCURRENT_CONNECTIONS",
                defaults.max_concurrent_connections,
            )?,
        })
    }

    /// Validates the configuration.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn validate(&self) -> ConfigResult<()> {
        if self.grpc_connect_timeout.as_secs() == 0 {
            return Err(ConfigError::Invalid(
                "gRPC connect timeout must be positive".into(),
            ));
        }
        if self.max_concurrent_connections == 0 {
            return Err(ConfigError::Invalid(
                "Max concurrent connections must be positive".into(),
            ));
        }
        Ok(())
    }
}

/// Operational limits runtime configuration.
///
/// Controls retry behavior, safety checks, ML parameters, and risk calculations.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LimitsConfig {
    // Retry configuration
    /// Initial retry delay
    pub retry_initial_delay: Duration,
    /// Maximum retry delay
    pub retry_max_delay: Duration,
    /// Maximum retry attempts
    pub retry_max_attempts: u32,
    /// Backoff multiplier
    pub retry_backoff_multiplier: f32,

    // Safety configuration
    /// Safety check timeout
    pub safety_check_timeout: Duration,
    /// Auto-recovery delay
    pub safety_auto_recovery_delay: Duration,
    /// Loss check interval
    pub safety_loss_check_interval: Duration,
    /// Position check interval
    pub safety_position_check_interval: Duration,

    // ML configuration
    /// Maximum batch size for ML inference
    pub ml_max_batch_size: usize,
    /// ML inference timeout
    pub ml_inference_timeout: Duration,
    /// Model cache cleanup interval
    pub ml_cache_cleanup_interval: Duration,
    /// Drift detection check interval
    pub ml_drift_check_interval: Duration,

    // Risk configuration
    /// VaR lookback period in trading days
    pub risk_var_lookback_days: usize,
    /// VaR confidence level
    pub risk_var_confidence: f64,
    /// Max drawdown warning threshold (percentage)
    pub risk_max_drawdown_warning_pct: u8,
}

impl LimitsConfig {
    /// Creates configuration with environment-aware defaults.
    pub const fn with_defaults(env: Environment) -> Self {
        match env {
            Environment::Development => Self {
                // Retry
                retry_initial_delay: Duration::from_millis(200),
                retry_max_delay: Duration::from_secs(60),
                retry_max_attempts: 5,
                retry_backoff_multiplier: 2.0,

                // Safety
                safety_check_timeout: Duration::from_millis(50),
                safety_auto_recovery_delay: Duration::from_secs(60),
                safety_loss_check_interval: Duration::from_secs(30),
                safety_position_check_interval: Duration::from_secs(15),

                // ML
                ml_max_batch_size: 1024,
                ml_inference_timeout: Duration::from_millis(200),
                ml_cache_cleanup_interval: Duration::from_secs(7200), // 2 hours
                ml_drift_check_interval: Duration::from_secs(600),    // 10 minutes

                // Risk
                risk_var_lookback_days: 252,
                risk_var_confidence: 0.95,
                risk_max_drawdown_warning_pct: 20,
            },
            Environment::Staging => Self {
                // Retry
                retry_initial_delay: Duration::from_millis(150),
                retry_max_delay: Duration::from_secs(45),
                retry_max_attempts: 4,
                retry_backoff_multiplier: 1.75,

                // Safety
                safety_check_timeout: Duration::from_millis(25),
                safety_auto_recovery_delay: Duration::from_secs(900), // 15 minutes
                safety_loss_check_interval: Duration::from_secs(15),
                safety_position_check_interval: Duration::from_secs(7),

                // ML
                ml_max_batch_size: 4096,
                ml_inference_timeout: Duration::from_millis(150),
                ml_cache_cleanup_interval: Duration::from_secs(5400), // 1.5 hours
                ml_drift_check_interval: Duration::from_secs(450),    // 7.5 minutes

                // Risk
                risk_var_lookback_days: 252,
                risk_var_confidence: 0.95,
                risk_max_drawdown_warning_pct: 17,
            },
            Environment::Production => Self {
                // Retry
                retry_initial_delay: Duration::from_millis(100),
                retry_max_delay: Duration::from_secs(30),
                retry_max_attempts: 3,
                retry_backoff_multiplier: 1.5,

                // Safety
                safety_check_timeout: Duration::from_millis(5),
                safety_auto_recovery_delay: Duration::from_secs(1800), // 30 minutes
                safety_loss_check_interval: Duration::from_secs(5),
                safety_position_check_interval: Duration::from_secs(2),

                // ML
                ml_max_batch_size: 8192,
                ml_inference_timeout: Duration::from_millis(100),
                ml_cache_cleanup_interval: Duration::from_secs(3600), // 1 hour
                ml_drift_check_interval: Duration::from_secs(300),    // 5 minutes

                // Risk
                risk_var_lookback_days: 252,
                risk_var_confidence: 0.95,
                risk_max_drawdown_warning_pct: 15,
            },
        }
    }

    /// Loads from environment variables with fallback to defaults.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn from_env(env: Environment) -> ConfigResult<Self> {
        let defaults = Self::with_defaults(env);

        Ok(Self {
            // Retry
            retry_initial_delay: parse_env_duration_ms(
                "RETRY_INITIAL_DELAY_MS",
                defaults.retry_initial_delay,
            )?,
            retry_max_delay: parse_env_duration_secs(
                "RETRY_MAX_DELAY_SECS",
                defaults.retry_max_delay,
            )?,
            retry_max_attempts: parse_env_u32("RETRY_MAX_ATTEMPTS", defaults.retry_max_attempts)?,
            retry_backoff_multiplier: parse_env_f32(
                "RETRY_BACKOFF_MULTIPLIER",
                defaults.retry_backoff_multiplier,
            )?,

            // Safety
            safety_check_timeout: parse_env_duration_ms(
                "SAFETY_CHECK_TIMEOUT_MS",
                defaults.safety_check_timeout,
            )?,
            safety_auto_recovery_delay: parse_env_duration_secs(
                "SAFETY_AUTO_RECOVERY_DELAY_SECS",
                defaults.safety_auto_recovery_delay,
            )?,
            safety_loss_check_interval: parse_env_duration_secs(
                "SAFETY_LOSS_CHECK_INTERVAL_SECS",
                defaults.safety_loss_check_interval,
            )?,
            safety_position_check_interval: parse_env_duration_secs(
                "SAFETY_POSITION_CHECK_INTERVAL_SECS",
                defaults.safety_position_check_interval,
            )?,

            // ML
            ml_max_batch_size: parse_env_usize("ML_MAX_BATCH_SIZE", defaults.ml_max_batch_size)?,
            ml_inference_timeout: parse_env_duration_ms(
                "ML_INFERENCE_TIMEOUT_MS",
                defaults.ml_inference_timeout,
            )?,
            ml_cache_cleanup_interval: parse_env_duration_secs(
                "ML_MODEL_CACHE_CLEANUP_INTERVAL_SECS",
                defaults.ml_cache_cleanup_interval,
            )?,
            ml_drift_check_interval: parse_env_duration_secs(
                "ML_DRIFT_CHECK_INTERVAL_SECS",
                defaults.ml_drift_check_interval,
            )?,

            // Risk
            risk_var_lookback_days: parse_env_usize(
                "RISK_VAR_LOOKBACK_DAYS",
                defaults.risk_var_lookback_days,
            )?,
            risk_var_confidence: parse_env_f64(
                "RISK_VAR_CONFIDENCE",
                defaults.risk_var_confidence,
            )?,
            risk_max_drawdown_warning_pct: parse_env_u8(
                "RISK_MAX_DRAWDOWN_WARNING_PCT",
                defaults.risk_max_drawdown_warning_pct,
            )?,
        })
    }

    /// Validates the configuration.
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn validate(&self) -> ConfigResult<()> {
        if self.retry_max_attempts == 0 {
            return Err(ConfigError::Invalid(
                "Retry max attempts must be positive".into(),
            ));
        }
        if self.retry_backoff_multiplier <= 1.0 {
            return Err(ConfigError::Invalid(
                "Backoff multiplier must be > 1.0".into(),
            ));
        }
        if self.ml_max_batch_size == 0 {
            return Err(ConfigError::Invalid(
                "ML max batch size must be positive".into(),
            ));
        }
        if self.risk_var_confidence < 0.0_f64 || self.risk_var_confidence > 1.0_f64 {
            return Err(ConfigError::Invalid(
                "VaR confidence must be between 0.0 and 1.0".into(),
            ));
        }
        if self.risk_var_lookback_days == 0 {
            return Err(ConfigError::Invalid(
                "VaR lookback days must be positive".into(),
            ));
        }
        Ok(())
    }
}

/// Complete runtime configuration for the Foxhunt trading system.
///
/// Aggregates all runtime configuration categories with environment-aware defaults
/// and environment variable overrides.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::module_name_repetitions)]
pub struct RuntimeConfig {
    /// Detected or specified environment
    pub environment: Environment,
    /// Database configuration
    pub database: DatabaseRuntimeConfig,
    /// Cache configuration
    pub cache: CacheRuntimeConfig,
    /// Timeout configuration
    pub timeouts: TimeoutConfig,
    /// Limits and operational parameters
    pub limits: LimitsConfig,
}

impl RuntimeConfig {
    /// Creates runtime configuration by auto-detecting environment and loading from env vars.
    ///
    /// # Errors
    ///
    /// Returns ConfigError if environment variables contain invalid values or
    /// if validation fails.
    pub fn from_env() -> ConfigResult<Self> {
        let environment = Environment::detect();
        Self::from_env_with_environment(environment)
    }

    /// Creates runtime configuration with specified environment and loads from env vars.
    ///
    /// # Arguments
    ///
    /// * `environment` - The deployment environment to use for defaults
    ///
    /// # Errors
    ///
    /// Returns ConfigError if environment variables contain invalid values or
    /// if validation fails.
    pub fn from_env_with_environment(environment: Environment) -> ConfigResult<Self> {
        let config = Self {
            environment,
            database: DatabaseRuntimeConfig::from_env(environment)?,
            cache: CacheRuntimeConfig::from_env(environment)?,
            timeouts: TimeoutConfig::from_env(environment)?,
            limits: LimitsConfig::from_env(environment)?,
        };

        config.validate()?;
        Ok(config)
    }

    /// Creates runtime configuration with environment-specific defaults.
    ///
    /// Does not read from environment variables. Useful for testing or
    /// when you want pure default values.
    ///
    /// # Arguments
    ///
    /// * `environment` - The deployment environment to use for defaults
    pub const fn with_defaults(environment: Environment) -> Self {
        Self {
            environment,
            database: DatabaseRuntimeConfig::with_defaults(environment),
            cache: CacheRuntimeConfig::with_defaults(environment),
            timeouts: TimeoutConfig::with_defaults(environment),
            limits: LimitsConfig::with_defaults(environment),
        }
    }

    /// Validates the entire runtime configuration.
    ///
    /// # Errors
    ///
    /// Returns ConfigError if any configuration values are invalid.
    pub fn validate(&self) -> ConfigResult<()> {
        self.database.validate()?;
        self.cache.validate()?;
        self.timeouts.validate()?;
        self.limits.validate()?;
        Ok(())
    }
}

// Helper functions for parsing environment variables

fn parse_env_duration_ms(key: &str, default: Duration) -> ConfigResult<Duration> {
    match std::env::var(key) {
        Ok(val) => {
            let ms = val.parse::<u64>().map_err(|e| {
                ConfigError::Invalid(format!("Invalid duration for {}: {}", key, e))
            })?;
            Ok(Duration::from_millis(ms))
        }
        Err(_) => Ok(default),
    }
}

fn parse_env_duration_secs(key: &str, default: Duration) -> ConfigResult<Duration> {
    match std::env::var(key) {
        Ok(val) => {
            let secs = val.parse::<u64>().map_err(|e| {
                ConfigError::Invalid(format!("Invalid duration for {}: {}", key, e))
            })?;
            Ok(Duration::from_secs(secs))
        }
        Err(_) => Ok(default),
    }
}

fn parse_env_u32(key: &str, default: u32) -> ConfigResult<u32> {
    match std::env::var(key) {
        Ok(val) => val
            .parse::<u32>()
            .map_err(|e| ConfigError::Invalid(format!("Invalid u32 for {}: {}", key, e))),
        Err(_) => Ok(default),
    }
}

fn parse_env_u8(key: &str, default: u8) -> ConfigResult<u8> {
    match std::env::var(key) {
        Ok(val) => val
            .parse::<u8>()
            .map_err(|e| ConfigError::Invalid(format!("Invalid u8 for {}: {}", key, e))),
        Err(_) => Ok(default),
    }
}

fn parse_env_usize(key: &str, default: usize) -> ConfigResult<usize> {
    match std::env::var(key) {
        Ok(val) => val
            .parse::<usize>()
            .map_err(|e| ConfigError::Invalid(format!("Invalid usize for {}: {}", key, e))),
        Err(_) => Ok(default),
    }
}

fn parse_env_f32(key: &str, default: f32) -> ConfigResult<f32> {
    match std::env::var(key) {
        Ok(val) => val
            .parse::<f32>()
            .map_err(|e| ConfigError::Invalid(format!("Invalid f32 for {}: {}", key, e))),
        Err(_) => Ok(default),
    }
}

fn parse_env_f64(key: &str, default: f64) -> ConfigResult<f64> {
    match std::env::var(key) {
        Ok(val) => val
            .parse::<f64>()
            .map_err(|e| ConfigError::Invalid(format!("Invalid f64 for {}: {}", key, e))),
        Err(_) => Ok(default),
    }
}

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

    #[test]
    fn test_environment_detection() {
        // Should default to Development
        let env = Environment::detect();
        assert!(matches!(
            env,
            Environment::Development | Environment::Production | Environment::Staging
        ));
    }

    #[test]
    fn test_environment_is_production() {
        assert!(Environment::Production.is_production());
        assert!(!Environment::Development.is_production());
        assert!(!Environment::Staging.is_production());
    }

    #[test]
    fn test_environment_is_development() {
        assert!(Environment::Development.is_development());
        assert!(!Environment::Production.is_development());
        assert!(!Environment::Staging.is_development());
    }

    #[test]
    fn test_runtime_config_with_defaults() {
        let config = RuntimeConfig::with_defaults(Environment::Production);
        assert_eq!(config.environment, Environment::Production);
        assert!(config.database.query_timeout.as_millis() > 0);
        assert!(config.cache.position_ttl.as_secs() > 0);
    }

    #[test]
    fn test_runtime_config_validation() {
        let config = RuntimeConfig::with_defaults(Environment::Development);
        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_database_config_defaults() {
        let dev_config = DatabaseRuntimeConfig::with_defaults(Environment::Development);
        let prod_config = DatabaseRuntimeConfig::with_defaults(Environment::Production);

        // Production should have tighter timeouts
        assert!(prod_config.query_timeout < dev_config.query_timeout);
        assert!(prod_config.connection_timeout < dev_config.connection_timeout);
    }

    #[test]
    fn test_cache_config_defaults() {
        let dev_config = CacheRuntimeConfig::with_defaults(Environment::Development);
        let prod_config = CacheRuntimeConfig::with_defaults(Environment::Production);

        // Production should have shorter TTLs for HFT
        assert!(prod_config.position_ttl < dev_config.position_ttl);
        assert!(prod_config.var_ttl < dev_config.var_ttl);
    }

    #[test]
    fn test_timeout_config_defaults() {
        let dev_config = TimeoutConfig::with_defaults(Environment::Development);
        let prod_config = TimeoutConfig::with_defaults(Environment::Production);

        // Production should have tighter timeouts
        assert!(prod_config.grpc_request_timeout < dev_config.grpc_request_timeout);
        assert!(prod_config.grpc_connect_timeout < dev_config.grpc_connect_timeout);
    }

    #[test]
    fn test_limits_config_defaults() {
        let dev_config = LimitsConfig::with_defaults(Environment::Development);
        let prod_config = LimitsConfig::with_defaults(Environment::Production);

        // Production should have more aggressive settings
        assert!(prod_config.safety_check_timeout < dev_config.safety_check_timeout);
        assert!(prod_config.ml_inference_timeout < dev_config.ml_inference_timeout);
    }

    #[test]
    fn test_database_config_validation() {
        let mut config = DatabaseRuntimeConfig::with_defaults(Environment::Production);
        assert!(config.validate().is_ok());

        config.query_timeout = Duration::from_millis(0);
        assert!(config.validate().is_err());

        config = DatabaseRuntimeConfig::with_defaults(Environment::Production);
        config.pool_size = 0;
        assert!(config.validate().is_err());

        config = DatabaseRuntimeConfig::with_defaults(Environment::Production);
        config.pool_size = 200;
        config.max_pool_size = 100;
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_cache_config_validation() {
        let mut config = CacheRuntimeConfig::with_defaults(Environment::Production);
        assert!(config.validate().is_ok());

        config.position_ttl = Duration::from_secs(0);
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_limits_config_validation() {
        let mut config = LimitsConfig::with_defaults(Environment::Production);
        assert!(config.validate().is_ok());

        config.retry_max_attempts = 0;
        assert!(config.validate().is_err());

        config = LimitsConfig::with_defaults(Environment::Production);
        config.retry_backoff_multiplier = 0.5;
        assert!(config.validate().is_err());

        config = LimitsConfig::with_defaults(Environment::Production);
        config.risk_var_confidence = 1.5;
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_staging_environment_defaults() {
        let config = RuntimeConfig::with_defaults(Environment::Staging);

        // Staging should be between dev and prod
        let dev_config = RuntimeConfig::with_defaults(Environment::Development);
        let prod_config = RuntimeConfig::with_defaults(Environment::Production);

        assert!(config.database.query_timeout > prod_config.database.query_timeout);
        assert!(config.database.query_timeout < dev_config.database.query_timeout);
    }
}
