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

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

/// AI Service configuration
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AiServiceConfig {
    pub ai_service: AiServiceSettings,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AiServiceSettings {
    pub server: ServerConfig,
    pub rag: RagConfig,
    pub mcp: McpConfig,
    pub dag: DagConfig,
    #[serde(default)]
    pub monitoring: Option<MonitoringConfig>,
    #[serde(default)]
    pub logging: Option<LoggingConfig>,
    #[serde(default)]
    pub build: Option<DockerBuildConfig>,
}

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

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

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RagConfig {
    pub enabled: bool,
    pub rag_service_url: Option<String>,
    pub timeout: Option<u64>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct McpConfig {
    pub enabled: bool,
    pub mcp_service_url: Option<String>,
    pub timeout: Option<u64>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DagConfig {
    pub max_concurrent_tasks: Option<usize>,
    pub task_timeout: Option<u64>,
    pub retry_attempts: Option<u32>,
}

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub level: String,
}

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

impl AiServiceConfig {
    pub fn load() -> anyhow::Result<Self> {
        let config_json = platform_config::load_service_config_from_ncl("ai-service")
            .context("Failed to load ai-service configuration from Nickel")?;

        serde_json::from_value(config_json)
            .context("Failed to deserialize ai-service configuration")
    }
}

impl ConfigLoader for AiServiceConfig {
    fn service_name() -> &'static str {
        "ai-service"
    }

    fn load_from_hierarchy() -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>>
    {
        if let Some(path) = platform_config::resolve_config_path(Self::service_name()) {
            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("AI_SERVICE_SERVER_HOST") {
            self.ai_service.server.host = host;
        }
        if let Ok(port) = std::env::var("AI_SERVICE_SERVER_PORT") {
            if let Ok(p) = port.parse() {
                self.ai_service.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| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;

        serde_json::from_value(json_value).map_err(|e| {
            let err_msg = format!("Failed to deserialize ai-service config: {}", 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 = AiServiceConfig::default();
        assert_eq!(config.ai_service.server.port, 8082);
        assert!(!config.ai_service.rag.enabled);
        assert!(!config.ai_service.mcp.enabled);
    }
}
