use std::collections::HashMap;

use super::provider::Provider;

/// Metadata for one preset template.
pub struct PresetTemplate {
    pub name: &'static str,
    pub description: &'static str,
}

pub static PRESETS: &[PresetTemplate] = &[
    PresetTemplate {
        name: "openai-compatible",
        description: "通用 OpenAI 兼容中继。设置 ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL。",
    },
    PresetTemplate {
        name: "anthropic-compatible",
        description: "通用 Anthropic 兼容中继。设置 ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL。",
    },
    PresetTemplate {
        name: "deepseek",
        description: "DeepSeek Platform Anthropic 兼容端点 (https://api.deepseek.com/anthropic)。只需提供 key。",
    },
];

/// Build a `Provider::ClaudeCode` from a preset template.
///
/// `overrides` — user-supplied flags (`--key`, `--url`, `--model`, `--env`) — are
/// merged on top of the template defaults.
pub fn resolve_preset(
    template_name: &str,
    provider_name: &str,
    model: Option<&str>,
    key: Option<&str>,
    url: Option<&str>,
    extra_env: &[(String, String)],
) -> Result<Provider, String> {
    match template_name {
        "openai-compatible" | "anthropic-compatible" => {
            let mut env = HashMap::new();
            if let Some(k) = key {
                env.insert("ANTHROPIC_AUTH_TOKEN".to_string(), k.to_string());
            }
            if let Some(u) = url {
                env.insert("ANTHROPIC_BASE_URL".to_string(), u.to_string());
            }
            if let Some(m) = model {
                env.insert("ANTHROPIC_DEFAULT_HAIKU_MODEL".to_string(), m.to_string());
                env.insert("ANTHROPIC_DEFAULT_SONNET_MODEL".to_string(), m.to_string());
                env.insert("ANTHROPIC_DEFAULT_OPUS_MODEL".to_string(), m.to_string());
            }
            for (k, v) in extra_env {
                env.insert(k.clone(), v.clone());
            }
            Ok(Provider::ClaudeCode {
                name: provider_name.to_string(),
                model: model.map(|m| m.to_string()),
                env,
            })
        }
        "deepseek" => {
            let mut env = HashMap::new();
            env.insert(
                "ANTHROPIC_BASE_URL".to_string(),
                "https://api.deepseek.com/anthropic".to_string(),
            );
            if let Some(k) = key {
                env.insert("ANTHROPIC_AUTH_TOKEN".to_string(), k.to_string());
            }
            if let Some(m) = model {
                env.insert("ANTHROPIC_DEFAULT_HAIKU_MODEL".to_string(), m.to_string());
                env.insert("ANTHROPIC_DEFAULT_SONNET_MODEL".to_string(), m.to_string());
                env.insert("ANTHROPIC_DEFAULT_OPUS_MODEL".to_string(), m.to_string());
            }
            for (k, v) in extra_env {
                env.insert(k.clone(), v.clone());
            }
            Ok(Provider::ClaudeCode {
                name: provider_name.to_string(),
                model: model.map(|m| m.to_string()),
                env,
            })
        }
        other => Err(format!(
            "未知预设模板 '{}'。使用 'closure cc p list-presets' 查看可用模板。",
            other
        )),
    }
}

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

    #[test]
    fn test_preset_deepseek() {
        let provider =
            resolve_preset("deepseek", "my-ds", None, Some("sk-xxx"), None, &[]).unwrap();
        match provider {
            Provider::ClaudeCode { name, model, env } => {
                assert_eq!(name, "my-ds");
                assert_eq!(
                    env.get("ANTHROPIC_BASE_URL").unwrap(),
                    "https://api.deepseek.com/anthropic"
                );
                assert_eq!(env.get("ANTHROPIC_AUTH_TOKEN").unwrap(), "sk-xxx");
                assert!(model.is_none());
            }
            _ => panic!("expected ClaudeCode variant"),
        }
    }

    #[test]
    fn test_preset_openai_compatible_with_all_overrides() {
        let provider = resolve_preset(
            "openai-compatible",
            "my-oa",
            Some("gpt-4"),
            Some("sk-key"),
            Some("https://my-proxy.example.com"),
            &[("EXTRA_VAR".into(), "val".into())],
        )
        .unwrap();
        match provider {
            Provider::ClaudeCode { env, model, .. } => {
                assert_eq!(model, Some("gpt-4".to_string()));
                assert_eq!(
                    env.get("ANTHROPIC_BASE_URL").unwrap(),
                    "https://my-proxy.example.com"
                );
                assert_eq!(env.get("ANTHROPIC_AUTH_TOKEN").unwrap(), "sk-key");
                assert_eq!(env.get("ANTHROPIC_DEFAULT_HAIKU_MODEL").unwrap(), "gpt-4");
                assert_eq!(env.get("EXTRA_VAR").unwrap(), "val");
            }
            _ => panic!("expected ClaudeCode variant"),
        }
    }

    #[test]
    fn test_preset_anthropic_compatible_minimal() {
        let provider =
            resolve_preset("anthropic-compatible", "ac", None, Some("sk"), Some("https://x.com"), &[])
                .unwrap();
        match provider {
            Provider::ClaudeCode { env, model, .. } => {
                assert_eq!(env.get("ANTHROPIC_BASE_URL").unwrap(), "https://x.com");
                assert_eq!(env.get("ANTHROPIC_AUTH_TOKEN").unwrap(), "sk");
                assert!(model.is_none());
                assert!(!env.contains_key("ANTHROPIC_DEFAULT_HAIKU_MODEL"));
            }
            _ => panic!("expected ClaudeCode variant"),
        }
    }

    #[test]
    fn test_preset_unknown_template() {
        let result = resolve_preset("nonexistent", "x", None, None, None, &[]);
        assert!(result.is_err());
        assert!(result.unwrap_err().contains("未知预设模板"));
    }

    #[test]
    fn test_presets_list_contains_all_three() {
        let names: Vec<&str> = PRESETS.iter().map(|p| p.name).collect();
        assert!(names.contains(&"openai-compatible"));
        assert!(names.contains(&"anthropic-compatible"));
        assert!(names.contains(&"deepseek"));
    }
}
