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

use crate::agent::AgentManifest;
use crate::error::SwarmResult;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SwarmConfig {
    pub name: String,
    pub gateway: GatewayConfig,
    pub providers: HashMap<String, ProviderConfig>,
    pub agents: Vec<AgentManifest>,
    pub memory: MemoryConfig,
}

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderConfig {
    pub kind: ProviderKind,
    pub api_key: Option<String>,
    pub base_url: Option<String>,
    pub default_model: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ProviderKind {
    Anthropic,
    Gemini,
    Ollama,
    OpenAiCompatible,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryConfig {
    pub db_path: PathBuf,
    pub max_context_messages: usize,
}

impl Default for SwarmConfig {
    fn default() -> Self {
        Self {
            name: "swarm".to_string(),
            gateway: GatewayConfig {
                host: "127.0.0.1".to_string(),
                port: 18800,
                cors_origins: vec!["*".to_string()],
            },
            providers: HashMap::from([
                (
                    "anthropic".to_string(),
                    ProviderConfig {
                        kind: ProviderKind::Anthropic,
                        api_key: None, // read from ANTHROPIC_API_KEY
                        base_url: None,
                        default_model: "claude-sonnet-4-20250514".to_string(),
                    },
                ),
                (
                    "ollama".to_string(),
                    ProviderConfig {
                        kind: ProviderKind::Ollama,
                        api_key: None,
                        base_url: Some("http://localhost:11434".to_string()),
                        default_model: "purple-squirrel-tools".to_string(),
                    },
                ),
            ]),
            agents: vec![],
            memory: MemoryConfig {
                db_path: PathBuf::from("swarm.db"),
                max_context_messages: 50,
            },
        }
    }
}

impl SwarmConfig {
    pub fn load(path: &Path) -> SwarmResult<Self> {
        let content = std::fs::read_to_string(path)?;
        let mut config: SwarmConfig =
            toml::from_str(&content).map_err(|e| crate::error::SwarmError::ConfigError(e.to_string()))?;

        // Resolve env vars for API keys
        for provider in config.providers.values_mut() {
            if provider.api_key.is_none() {
                let env_key = match provider.kind {
                    ProviderKind::Anthropic => "ANTHROPIC_API_KEY",
                    ProviderKind::Gemini => "GEMINI_API_KEY",
                    ProviderKind::Ollama => continue,
                    ProviderKind::OpenAiCompatible => "OPENAI_API_KEY",
                };
                provider.api_key = std::env::var(env_key).ok();
            }
        }

        Ok(config)
    }

    pub fn save(&self, path: &Path) -> SwarmResult<()> {
        let content =
            toml::to_string_pretty(self).map_err(|e| crate::error::SwarmError::ConfigError(e.to_string()))?;
        std::fs::write(path, content)?;
        Ok(())
    }
}
