use std::path::{Path, PathBuf};
use std::time::Duration;

use platform_config::ConfigLoader;
use serde::{Deserialize, Serialize};
use tracing::info;

use crate::error::{infrastructure, ControlCenterError, Result};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlCenterConfig {
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub policies: PolicyConfig,
    pub auth: AuthConfig,
    pub compliance: ComplianceConfig,
    pub anomaly: AnomalyConfig,
    pub logging: LoggingConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    pub cors_origins: Vec<String>,
    pub request_timeout_ms: u64,
    pub max_request_size: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
    pub url: String,
    pub namespace: String,
    pub database: String,
    pub username: Option<String>,
    pub password: Option<String>,
    pub connection_timeout_ms: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyConfig {
    pub policy_dir: PathBuf,
    pub schema_dir: PathBuf,
    pub templates_dir: PathBuf,
    pub enable_versioning: bool,
    pub enable_caching: bool,
    pub cache_ttl_seconds: u64,
    pub validation_strict: bool,
    pub hooks: HooksConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HooksConfig {
    pub pre_execution: Vec<String>,
    pub post_execution: Vec<String>,
    pub on_policy_violation: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
    pub jwt_secret: String,
    pub jwt_expiry_hours: u64,
    pub require_mfa: bool,
    pub password_policy: PasswordPolicy,
    pub session_timeout_minutes: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PasswordPolicy {
    pub min_length: usize,
    pub require_uppercase: bool,
    pub require_lowercase: bool,
    pub require_numbers: bool,
    pub require_special_chars: bool,
    pub max_age_days: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComplianceConfig {
    pub soc2: Soc2Config,
    pub hipaa: HipaaConfig,
    pub reports: ReportsConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Soc2Config {
    pub enabled: bool,
    pub audit_log_retention_days: u64,
    pub require_approval_for_production: bool,
    pub sensitive_data_encryption: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HipaaConfig {
    pub enabled: bool,
    pub require_data_minimization: bool,
    pub audit_all_access: bool,
    pub encrypt_at_rest: bool,
    pub encrypt_in_transit: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportsConfig {
    pub output_dir: PathBuf,
    pub formats: Vec<String>,
    pub schedule_cron: Option<String>,
    pub email_notifications: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyConfig {
    pub enabled: bool,
    pub baseline_window_hours: u64,
    pub detection_threshold: f64,
    pub statistical_methods: Vec<String>,
    pub alert_channels: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub level: String,
    pub file_path: Option<PathBuf>,
    pub structured: bool,
    pub include_spans: bool,
}

impl Default for ControlCenterConfig {
    fn default() -> Self {
        Self {
            server: ServerConfig {
                host: "127.0.0.1".to_string(),
                port: 8080,
                cors_origins: vec!["*".to_string()],
                request_timeout_ms: 30000,
                max_request_size: 10 * 1024 * 1024, // 10MB
            },
            database: DatabaseConfig {
                url: "memory".to_string(),
                namespace: "control_center".to_string(),
                database: "policies".to_string(),
                username: None,
                password: None,
                connection_timeout_ms: 5000,
            },
            policies: PolicyConfig {
                policy_dir: "policies".into(),
                schema_dir: "schemas".into(),
                templates_dir: "templates".into(),
                enable_versioning: true,
                enable_caching: true,
                cache_ttl_seconds: 300,
                validation_strict: true,
                hooks: HooksConfig {
                    pre_execution: vec![],
                    post_execution: vec![],
                    on_policy_violation: vec![],
                },
            },
            auth: AuthConfig {
                jwt_secret: "change_me_in_production".to_string(),
                jwt_expiry_hours: 24,
                require_mfa: false,
                password_policy: PasswordPolicy {
                    min_length: 8,
                    require_uppercase: true,
                    require_lowercase: true,
                    require_numbers: true,
                    require_special_chars: true,
                    max_age_days: 90,
                },
                session_timeout_minutes: 60,
            },
            compliance: ComplianceConfig {
                soc2: Soc2Config {
                    enabled: false,
                    audit_log_retention_days: 365,
                    require_approval_for_production: true,
                    sensitive_data_encryption: true,
                },
                hipaa: HipaaConfig {
                    enabled: false,
                    require_data_minimization: true,
                    audit_all_access: true,
                    encrypt_at_rest: true,
                    encrypt_in_transit: true,
                },
                reports: ReportsConfig {
                    output_dir: "reports".into(),
                    formats: vec!["json".to_string(), "html".to_string()],
                    schedule_cron: None,
                    email_notifications: vec![],
                },
            },
            anomaly: AnomalyConfig {
                enabled: true,
                baseline_window_hours: 24,
                detection_threshold: 2.0,
                statistical_methods: vec![
                    "zscore".to_string(),
                    "iqr".to_string(),
                    "isolation_forest".to_string(),
                ],
                alert_channels: vec![],
            },
            logging: LoggingConfig {
                level: "info".to_string(),
                file_path: None,
                structured: true,
                include_spans: true,
            },
        }
    }
}

impl ControlCenterConfig {
    /// Load configuration with hierarchical fallback logic:
    /// 1. Environment variable CONTROL_CENTER_CONFIG (explicit config path)
    /// 2. CLI config resolution via platform_config::ConfigResolver
    /// 3. Built-in defaults
    ///
    /// Supports both .ncl (Nickel) and .toml formats.
    /// Then environment variables (CONTROL_CENTER_*) override specific fields.
    pub fn load() -> Result<Self> {
        let mut config = Self::load_from_hierarchy()?;
        Self::apply_env_overrides(&mut config)?;
        Ok(config)
    }

    /// Internal: Load configuration from hierarchy without env var overrides
    fn load_from_hierarchy() -> Result<Self> {
        // Priority 1: Explicit config path from environment variable
        if let Ok(config_path) = std::env::var("CONTROL_CENTER_CONFIG") {
            return Self::from_file(&config_path);
        }

        // Priority 2: Use platform_config resolver (supports NCL and TOML)
        let resolver = platform_config::ConfigResolver::new()
            .with_cli_config_dir(
                std::env::var("PROVISIONING_CONFIG_DIR")
                    .ok()
                    .map(PathBuf::from),
            )
            .with_cli_mode(std::env::var("CONTROL_CENTER_MODE").ok());

        if let Some(path) = resolver.resolve("control-center") {
            return Self::from_file(&path);
        }

        // Priority 3: Built-in defaults if file doesn't exist
        Ok(Self::default())
    }

    /// Apply environment variable overrides to configuration
    /// Environment variables use format: CONTROL_CENTER_{SECTION}_{KEY}=value
    /// Example: CONTROL_CENTER_SERVER_PORT=8888
    fn apply_env_overrides(config: &mut Self) -> Result<()> {
        // Server overrides
        if let Ok(host) = std::env::var("CONTROL_CENTER_SERVER_HOST") {
            config.server.host = host;
        }
        if let Ok(port) = std::env::var("CONTROL_CENTER_SERVER_PORT") {
            config.server.port = port.parse().map_err(|_| {
                ControlCenterError::Infrastructure(
                    infrastructure::InfrastructureError::Configuration(
                        "CONTROL_CENTER_SERVER_PORT must be a valid port number".to_string(),
                    ),
                )
            })?;
        }

        // Auth overrides
        if let Ok(jwt_secret) = std::env::var("CONTROL_CENTER_JWT_SECRET") {
            config.auth.jwt_secret = jwt_secret;
        }
        if let Ok(require_mfa) = std::env::var("CONTROL_CENTER_REQUIRE_MFA") {
            config.auth.require_mfa = require_mfa.to_lowercase() == "true";
        }
        if let Ok(session_timeout) = std::env::var("CONTROL_CENTER_SESSION_TIMEOUT_MINUTES") {
            config.auth.session_timeout_minutes = session_timeout.parse().map_err(|_| {
                ControlCenterError::Infrastructure(
                    infrastructure::InfrastructureError::Configuration(
                        "CONTROL_CENTER_SESSION_TIMEOUT_MINUTES must be a valid number".to_string(),
                    ),
                )
            })?;
        }

        // Database overrides
        if let Ok(url) = std::env::var("CONTROL_CENTER_DATABASE_URL") {
            config.database.url = url;
        }
        if let Ok(username) = std::env::var("CONTROL_CENTER_DATABASE_USERNAME") {
            config.database.username = Some(username);
        }
        if let Ok(password) = std::env::var("CONTROL_CENTER_DATABASE_PASSWORD") {
            config.database.password = Some(password);
        }

        // Logging overrides
        if let Ok(level) = std::env::var("CONTROL_CENTER_LOG_LEVEL") {
            config.logging.level = level;
        }

        // Compliance overrides
        if let Ok(soc2_enabled) = std::env::var("CONTROL_CENTER_SOC2_ENABLED") {
            config.compliance.soc2.enabled = soc2_enabled.to_lowercase() == "true";
        }
        if let Ok(hipaa_enabled) = std::env::var("CONTROL_CENTER_HIPAA_ENABLED") {
            config.compliance.hipaa.enabled = hipaa_enabled.to_lowercase() == "true";
        }

        Ok(())
    }

    /// Load configuration from file (.ncl or .toml) with environment variable
    /// interpolation
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        let path_ref = path.as_ref();

        // Use platform_config to load NCL or TOML
        let json_value = platform_config::format::load_config(path_ref).map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Failed to load config from {:?}: {}", path_ref, e),
            ))
        })?;

        // Deserialize from JSON value
        let config: Self = serde_json::from_value(json_value).map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Failed to deserialize config: {}", e),
            ))
        })?;

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

    /// Interpolate environment variables in configuration
    fn interpolate_env_vars(content: &str) -> Result<String> {
        let mut result = content.to_string();

        // Replace ${VAR_NAME} with environment variable values
        let re = regex::Regex::new(r"\$\{([^}]+)\}").map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Invalid regex pattern: {}", e),
            ))
        })?;

        for captures in re.captures_iter(content) {
            let var_name = &captures[1];
            if let Ok(var_value) = std::env::var(var_name) {
                let placeholder = format!("${{{}}}", var_name);
                result = result.replace(&placeholder, &var_value);
            }
        }

        Ok(result)
    }

    /// Validate configuration values
    pub fn validate(&self) -> Result<()> {
        // Validate server config
        if self.server.port == 0 {
            return Err(ControlCenterError::Infrastructure(
                infrastructure::InfrastructureError::Configuration(
                    "Server port cannot be 0".to_string(),
                ),
            ));
        }

        // Validate policy directories exist
        if !self.policies.policy_dir.exists() {
            return Err(ControlCenterError::Infrastructure(
                infrastructure::InfrastructureError::Configuration(format!(
                    "Policy directory does not exist: {:?}",
                    self.policies.policy_dir
                )),
            ));
        }

        // Validate auth config
        if self.auth.jwt_secret == "change_me_in_production" {
            tracing::warn!("Using default JWT secret - change in production!");
        }

        if self.auth.jwt_secret.len() < 32 {
            return Err(ControlCenterError::Infrastructure(
                infrastructure::InfrastructureError::Configuration(
                    "JWT secret must be at least 32 characters".to_string(),
                ),
            ));
        }

        // Validate password policy
        if self.auth.password_policy.min_length < 8 {
            return Err(ControlCenterError::Infrastructure(
                infrastructure::InfrastructureError::Configuration(
                    "Password minimum length must be at least 8 characters".to_string(),
                ),
            ));
        }

        Ok(())
    }

    /// Get configuration as JSON string
    pub fn to_json(&self) -> Result<String> {
        serde_json::to_string_pretty(self).map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Failed to serialize config to JSON: {}", e),
            ))
        })
    }

    /// Create a default configuration file
    pub fn create_default_config<P: AsRef<Path>>(path: P) -> Result<()> {
        let config = Self::default();
        let toml_content = toml::to_string_pretty(&config).map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Failed to serialize default config: {}", e),
            ))
        })?;

        std::fs::write(path.as_ref(), toml_content).map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
                format!("Failed to write config file {:?}: {}", path.as_ref(), e),
            ))
        })?;

        Ok(())
    }
}

impl ConfigLoader for ControlCenterConfig {
    fn service_name() -> &'static str {
        "control-center"
    }

    fn load_from_hierarchy() -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>>
    {
        let service = Self::service_name();

        if let Some(path) = platform_config::resolve_config_path(service) {
            return Self::from_path(&path).map_err(|e| {
                Box::new(std::io::Error::other(e.to_string()))
                    as Box<dyn std::error::Error + Send + Sync>
            });
        }

        Ok(Self::default())
    }

    fn apply_env_overrides(
        &mut self,
    ) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
        Self::apply_env_overrides(self).map_err(|e| {
            Box::new(std::io::Error::other(e.to_string()))
                as Box<dyn std::error::Error + Send + Sync>
        })
    }

    fn from_path<P: AsRef<Path>>(
        path: P,
    ) -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>> {
        let path = path.as_ref();
        let json_value = platform_config::format::load_config(path).map_err(|e| {
            let err: Box<dyn std::error::Error + Send + Sync> = Box::new(e);
            err
        })?;

        serde_json::from_value(json_value).map_err(|e| {
            let err_msg = format!(
                "Failed to deserialize control-center config from {:?}: {}",
                path, e
            );
            Box::new(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                err_msg,
            )) as Box<dyn std::error::Error + Send + Sync>
        })
    }
}
