//! Configuration management for the Provisioning MCP Server

use std::collections::HashMap;
use std::path::Path;

use anyhow::{Context, Result};
use platform_config::ConfigLoader;
use serde::{Deserialize, Serialize};

/// MCP Server configuration
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Config {
    pub mcp_server: MCPServerSettings,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MCPServerSettings {
    pub workspace: WorkspaceConfig,
    pub server: ServerConfig,
    pub protocol: ProtocolConfig,
    #[serde(default)]
    pub tools: Option<ToolsConfig>,
    #[serde(default)]
    pub prompts: Option<PromptsConfig>,
    #[serde(default)]
    pub resources: Option<ResourcesConfig>,
    #[serde(default)]
    pub sampling: Option<SamplingConfig>,
    #[serde(default)]
    pub capabilities: Option<CapabilitiesConfig>,
    #[serde(default)]
    pub orchestrator_integration: Option<OrchestratorIntegrationConfig>,
    #[serde(default)]
    pub control_center_integration: Option<ControlCenterIntegrationConfig>,
    #[serde(default)]
    pub security: Option<SecurityConfig>,
    #[serde(default)]
    pub monitoring: Option<MonitoringConfig>,
    #[serde(default)]
    pub logging: Option<LoggingConfig>,
    #[serde(default)]
    pub performance: Option<PerformanceConfig>,
    #[serde(default)]
    pub build: Option<DockerBuildConfig>,
}

/// Workspace configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkspaceConfig {
    pub name: String,
    pub path: String,
    #[serde(default)]
    pub metadata: HashMap<String, serde_json::Value>,
}

/// Server configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    #[serde(default)]
    pub workers: usize,
}

impl Default for ServerConfig {
    fn default() -> Self {
        Self {
            host: "127.0.0.1".to_string(),
            port: 3000,
            workers: 4,
        }
    }
}

/// Protocol configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProtocolConfig {
    #[serde(default = "default_version")]
    pub version: String,
    #[serde(default)]
    pub transport: Option<TransportConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransportConfig {
    pub endpoint: Option<String>,
    pub ws_path: Option<String>,
    pub timeout: Option<u64>,
}

/// Tools configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolsConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default = "default_max_concurrent_tools")]
    pub max_concurrent: usize,
    #[serde(default = "default_tool_timeout")]
    pub timeout: u64,
    pub categories: Option<Vec<String>>,
    #[serde(default)]
    pub validation: Option<ValidationConfig>,
    #[serde(default)]
    pub cache: Option<CacheConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default)]
    pub strict_mode: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheConfig {
    #[serde(default)]
    pub enabled: bool,
    pub ttl: Option<u64>,
}

/// Prompts configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptsConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default = "default_max_templates")]
    pub max_templates: usize,
    #[serde(default)]
    pub cache: Option<CacheConfig>,
    #[serde(default)]
    pub versioning: Option<VersioningConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersioningConfig {
    #[serde(default)]
    pub enabled: bool,
    pub max_versions: Option<usize>,
}

/// Resources configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourcesConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default = "default_max_resource_size")]
    pub max_size: u64,
    pub types: Option<Vec<String>>,
    #[serde(default)]
    pub cache: Option<ResourceCacheConfig>,
    #[serde(default)]
    pub validation: Option<ResourceValidationConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceCacheConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    pub max_size_mb: Option<u64>,
    pub ttl: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceValidationConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    pub max_depth: Option<usize>,
}

/// Sampling configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SamplingConfig {
    #[serde(default)]
    pub enabled: bool,
    pub max_tokens: Option<u64>,
    pub model: Option<String>,
    pub temperature: Option<f32>,
    #[serde(default)]
    pub cache: Option<CacheConfig>,
}

/// Capabilities configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilitiesConfig {
    #[serde(default)]
    pub tools: Option<CapabilityConfig>,
    #[serde(default)]
    pub prompts: Option<CapabilityConfig>,
    #[serde(default)]
    pub resources: Option<ResourcesCapabilityConfig>,
    #[serde(default)]
    pub sampling: Option<SamplingCapabilityConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilityConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default)]
    pub list_changed_callback: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourcesCapabilityConfig {
    #[serde(default = "default_true")]
    pub enabled: bool,
    #[serde(default)]
    pub list_changed_callback: bool,
    #[serde(default)]
    pub subscribe: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SamplingCapabilityConfig {
    #[serde(default)]
    pub enabled: bool,
}

/// Orchestrator integration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrchestratorIntegrationConfig {
    #[serde(default)]
    pub enabled: bool,
    pub endpoint: Option<String>,
    pub token: Option<String>,
    pub workspace: Option<String>,
}

/// Control Center integration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlCenterIntegrationConfig {
    #[serde(default)]
    pub enabled: bool,
    pub endpoint: Option<String>,
    #[serde(default = "default_true")]
    pub enforce_rbac: bool,
}

/// Security configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
    #[serde(default)]
    pub tls: Option<TlsConfig>,
    #[serde(default)]
    pub rbac: Option<RbacConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
    pub enabled: bool,
    pub cert_path: Option<String>,
    pub key_path: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RbacConfig {
    pub enabled: bool,
    pub policy_file: Option<String>,
}

/// Monitoring configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonitoringConfig {
    pub enabled: bool,
    pub metrics_interval_seconds: u64,
    pub health_check_interval_seconds: u64,
    pub min_memory_mb: u64,
    pub max_cpu_percent: f64,
}

impl Default for MonitoringConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            metrics_interval_seconds: 60,
            health_check_interval_seconds: 30,
            min_memory_mb: 512,
            max_cpu_percent: 80.0,
        }
    }
}

/// Logging configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub level: String,
    pub format: String,
    #[serde(default)]
    pub outputs: Option<Vec<String>>,
    #[serde(default)]
    pub file: Option<FileLoggingConfig>,
    #[serde(default)]
    pub syslog: Option<SyslogConfig>,
    #[serde(default)]
    pub fields: Option<FieldsConfig>,
    #[serde(default)]
    pub sampling: Option<LogSamplingConfig>,
    #[serde(default)]
    pub modules: Option<serde_json::Value>,
    #[serde(default)]
    pub performance: Option<PerformanceLoggingConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileLoggingConfig {
    pub path: Option<String>,
    pub max_size: Option<u64>,
    pub max_backups: Option<usize>,
    pub max_age: Option<u64>,
    #[serde(default)]
    pub compress: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyslogConfig {
    pub address: Option<String>,
    pub facility: Option<String>,
    pub protocol: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldsConfig {
    #[serde(default = "default_true")]
    pub service_name: bool,
    #[serde(default = "default_true")]
    pub hostname: bool,
    #[serde(default = "default_true")]
    pub pid: bool,
    #[serde(default = "default_true")]
    pub timestamp: bool,
    #[serde(default)]
    pub caller: bool,
    #[serde(default)]
    pub stack_trace: bool,
    pub custom: Option<Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogSamplingConfig {
    #[serde(default)]
    pub enabled: bool,
    pub initial: Option<u64>,
    pub thereafter: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceLoggingConfig {
    #[serde(default)]
    pub enabled: bool,
    pub slow_threshold: Option<u64>,
    #[serde(default)]
    pub memory_info: bool,
}

impl Default for LoggingConfig {
    fn default() -> Self {
        Self {
            level: "info".to_string(),
            format: "text".to_string(),
            outputs: None,
            file: None,
            syslog: None,
            fields: None,
            sampling: None,
            modules: None,
            performance: None,
        }
    }
}

/// Performance configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
    pub pool_size: Option<usize>,
    pub buffer_size: Option<usize>,
    #[serde(default)]
    pub compression: bool,
    pub compression_level: Option<String>,
}

/// Docker build configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DockerBuildConfig {
    pub base_image: String,
    #[serde(default)]
    pub build_args: HashMap<String, String>,
}

// Serde defaults
fn default_version() -> String {
    "1.0".to_string()
}
fn default_true() -> bool {
    true
}
fn default_max_concurrent_tools() -> usize {
    5
}
fn default_tool_timeout() -> u64 {
    30000
}
fn default_max_templates() -> usize {
    100
}
fn default_max_resource_size() -> u64 {
    104857600
}

impl Default for MCPServerSettings {
    fn default() -> Self {
        Self {
            workspace: WorkspaceConfig {
                name: "mcp-server".to_string(),
                path: "/tmp/mcp-server".to_string(),
                metadata: HashMap::new(),
            },
            server: ServerConfig::default(),
            protocol: ProtocolConfig {
                version: "1.0".to_string(),
                transport: None,
            },
            tools: None,
            prompts: None,
            resources: None,
            sampling: None,
            capabilities: None,
            orchestrator_integration: None,
            control_center_integration: None,
            security: None,
            monitoring: Some(MonitoringConfig::default()),
            logging: Some(LoggingConfig::default()),
            performance: None,
            build: None,
        }
    }
}

impl Config {
    /// Load configuration from Nickel mcp-server.ncl
    pub fn load() -> Result<Self> {
        let config_json = platform_config::load_service_config_from_ncl("mcp-server")
            .context("Failed to load mcp-server configuration from Nickel")?;

        let config: Config = serde_json::from_value(config_json)
            .context("Failed to deserialize mcp-server configuration")?;

        Ok(config)
    }
}

impl ConfigLoader for Config {
    fn service_name() -> &'static str {
        "mcp-server"
    }

    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);
        }

        Ok(Self::default())
    }

    fn apply_env_overrides(
        &mut self,
    ) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
        if let Ok(host) = std::env::var("MCP_SERVER_HOST") {
            self.mcp_server.server.host = host;
        }
        if let Ok(port) = std::env::var("MCP_SERVER_PORT") {
            if let Ok(p) = port.parse() {
                self.mcp_server.server.port = p;
            }
        }
        Ok(())
    }

    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 mcp-server config from {:?}: {}",
                path, e
            );
            Box::new(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                err_msg,
            )) as Box<dyn std::error::Error + Send + Sync>
        })
    }
}

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

    #[test]
    fn test_default_config() {
        let config = Config::default();
        assert_eq!(config.mcp_server.server.port, 3000);
        assert_eq!(config.mcp_server.protocol.version, "1.0");
    }
}
