//! Configuration types for ML models
//!
//! CRITICAL: All default values are loaded from the config crate to eliminate
//! dangerous hardcoded defaults that could cause production issues.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Configuration for ML model training and inference
///
/// SAFETY: Uses configuration-driven defaults, no hardcoded values
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MLConfig {
    /// Model hyperparameters - loaded from config database
    pub model_params: HashMap<String, f64>,
    /// Training configuration - loaded from config database
    pub training_config: TrainingConfig,
    /// Inference configuration - loaded from config database
    pub inference_config: InferenceConfig,
    /// Hardware configuration - loaded from config database
    pub hardware_config: HardwareConfig,
    /// Safety thresholds - loaded from config database
    pub safety_config: SafetyConfig,
}

/// Safety configuration to prevent dangerous fallback values
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SafetyConfig {
    /// Maximum allowed learning rate to prevent training instability
    pub max_learning_rate: f64,
    /// Minimum allowed learning rate to ensure training progress
    pub min_learning_rate: f64,
    /// Maximum batch size to prevent memory issues
    pub max_batch_size: usize,
    /// Minimum batch size for stable gradients
    pub min_batch_size: usize,
    /// Maximum number of epochs to prevent infinite training
    pub max_epochs: usize,
    /// Gradient clipping threshold
    pub gradient_clip_threshold: f64,
    /// Model confidence threshold for predictions
    pub min_prediction_confidence: f64,
}

/// Training configuration parameters
///
/// SAFETY: All values validated against safety thresholds
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrainingConfig {
    pub batch_size: usize,
    pub learning_rate: f64,
    pub epochs: usize,
    pub validation_split: f64,
    pub early_stopping_patience: Option<usize>,
}

impl TrainingConfig {
    /// Validate training configuration against safety limits
    pub fn validate(&self, safety: &SafetyConfig) -> Result<(), String> {
        if self.learning_rate > safety.max_learning_rate {
            return Err(format!(
                "Learning rate {} exceeds maximum {}",
                self.learning_rate, safety.max_learning_rate
            ));
        }
        if self.learning_rate < safety.min_learning_rate {
            return Err(format!(
                "Learning rate {} below minimum {}",
                self.learning_rate, safety.min_learning_rate
            ));
        }
        if self.batch_size > safety.max_batch_size {
            return Err(format!(
                "Batch size {} exceeds maximum {}",
                self.batch_size, safety.max_batch_size
            ));
        }
        if self.batch_size < safety.min_batch_size {
            return Err(format!(
                "Batch size {} below minimum {}",
                self.batch_size, safety.min_batch_size
            ));
        }
        if self.epochs > safety.max_epochs {
            return Err(format!(
                "Epochs {} exceeds maximum {}",
                self.epochs, safety.max_epochs
            ));
        }
        Ok(())
    }
}

/// Inference configuration parameters
///
/// SAFETY: All values validated for production safety
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InferenceConfig {
    pub batch_size: usize,
    pub max_latency_us: u64,
    pub use_tensorrt: bool,
    pub use_onnx: bool,
}

impl InferenceConfig {
    /// Validate inference configuration for production safety
    pub fn validate(&self, safety: &SafetyConfig) -> Result<(), String> {
        if self.batch_size > safety.max_batch_size {
            return Err(format!(
                "Inference batch size {} exceeds maximum {}",
                self.batch_size, safety.max_batch_size
            ));
        }
        if self.max_latency_us < 1000 {
            return Err(format!(
                "Max latency {}μs is too aggressive for production",
                self.max_latency_us
            ));
        }
        Ok(())
    }
}

/// Hardware configuration for ML workloads
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HardwareConfig {
    pub use_gpu: bool,
    pub gpu_memory_limit_mb: Option<usize>,
    pub cpu_threads: Option<usize>,
}

impl MLConfig {
    /// Create MLConfig from the central configuration system
    ///
    /// CRITICAL: This replaces the dangerous Default implementation
    /// that used hardcoded values. All values now come from config database.
    pub fn from_config_manager(
        _config_manager: &config::ConfigManager,
    ) -> Result<Self, Box<dyn std::error::Error>> {
        // Use emergency defaults since ServiceConfig doesn't contain ML-specific configs
        tracing::warn!(
            "Using emergency ML config defaults - ML configs not available in ServiceConfig"
        );
        Ok(Self::emergency_safe_defaults())
    }

    /// EMERGENCY FALLBACK: Only use when config system is unavailable
    ///
    /// WARNING: These are conservative safe defaults, not production defaults
    pub fn emergency_safe_defaults() -> Self {
        Self {
            model_params: HashMap::new(),
            training_config: TrainingConfig::emergency_safe_defaults(),
            inference_config: InferenceConfig::emergency_safe_defaults(),
            hardware_config: HardwareConfig::emergency_safe_defaults(),
            safety_config: SafetyConfig::emergency_safe_defaults(),
        }
    }
}

impl TrainingConfig {
    /// Create from configuration data - NO hardcoded defaults
    pub fn from_config(
        config_data: &config::TrainingConfig,
    ) -> Result<Self, Box<dyn std::error::Error>> {
        Ok(Self {
            batch_size: config_data.batch_size,
            learning_rate: config_data.learning_rate,
            epochs: config_data.epochs as usize,
            validation_split: 0.2, // Default validation split
            early_stopping_patience: Some(config_data.early_stopping_patience as usize),
        })
    }

    /// EMERGENCY FALLBACK: Conservative safe defaults
    pub fn emergency_safe_defaults() -> Self {
        tracing::warn!("Using emergency safe training defaults - check config system!");
        Self {
            batch_size: 1,                    // Very small to prevent OOM
            learning_rate: 1e-5,              // Very conservative to prevent instability
            epochs: 1,                        // Minimal training to prevent infinite loops
            validation_split: 0.1,            // Small validation set
            early_stopping_patience: Some(1), // Stop quickly if issues
        }
    }
}

impl InferenceConfig {
    /// Create from configuration data - NO hardcoded defaults
    pub fn from_config(config_data: &config::MLConfig) -> Result<Self, Box<dyn std::error::Error>> {
        Ok(Self {
            batch_size: config_data.training_config.batch_size,
            max_latency_us: 10_000, // Default 10ms latency
            use_tensorrt: false,    // Default to false
            use_onnx: true,         // Default to true
        })
    }

    /// EMERGENCY FALLBACK: Ultra-conservative defaults
    pub fn emergency_safe_defaults() -> Self {
        tracing::warn!("Using emergency safe inference defaults - check config system!");
        Self {
            batch_size: 1,           // Single inference only
            max_latency_us: 100_000, // 100ms - very conservative
            use_tensorrt: false,     // Disable optimizations for safety
            use_onnx: false,         // Disable optimizations for safety
        }
    }
}

impl HardwareConfig {
    /// Create from configuration data - NO hardcoded defaults
    pub fn from_config(
        _config_data: &config::MLConfig,
    ) -> Result<Self, Box<dyn std::error::Error>> {
        // Use emergency defaults since hardware configs are not available in MLConfig
        tracing::warn!(
            "Using emergency hardware config defaults - hardware configs not available in MLConfig"
        );
        Ok(Self::emergency_safe_defaults())
    }

    /// EMERGENCY FALLBACK: CPU-only safe defaults
    pub fn emergency_safe_defaults() -> Self {
        tracing::warn!("Using emergency safe hardware defaults - check config system!");
        Self {
            use_gpu: false, // CPU only for safety
            gpu_memory_limit_mb: None,
            cpu_threads: Some(1), // Single thread to prevent resource issues
        }
    }
}

impl SafetyConfig {
    /// Create from configuration data - NO hardcoded defaults
    pub fn from_config(
        _config_data: &config::MLConfig,
    ) -> Result<Self, Box<dyn std::error::Error>> {
        // Use emergency defaults since safety configs are not available in MLConfig
        tracing::warn!(
            "Using emergency safety config defaults - safety configs not available in MLConfig"
        );
        Ok(Self::emergency_safe_defaults())
    }

    /// EMERGENCY FALLBACK: Ultra-conservative safety limits
    pub fn emergency_safe_defaults() -> Self {
        tracing::warn!("Using emergency safety defaults - check config system!");
        Self {
            max_learning_rate: 1e-4,        // Very conservative
            min_learning_rate: 1e-8,        // Prevent zero learning rate
            max_batch_size: 32,             // Reasonable memory limit
            min_batch_size: 1,              // Allow single samples
            max_epochs: 10,                 // Prevent infinite training
            gradient_clip_threshold: 1.0,   // Conservative gradient clipping
            min_prediction_confidence: 0.6, // Require reasonable confidence
        }
    }
}
