use serde::Serialize;
use serde_json::{json, Map, Value};
use std::fs;
use std::path::PathBuf;

/// MCP 服务器管理：
/// - 全局：~/.claude.json 顶层的 mcpServers（保留文件中其他全部字段）
/// - 项目：<项目>/.mcp.json 的 mcpServers（可随仓库提交共享）
/// 改动对新开的会话生效。

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct McpServers {
    pub global: Value,
    pub project: Value,
}

fn user_config_path() -> PathBuf {
    dirs::home_dir()
        .unwrap_or_else(|| PathBuf::from("."))
        .join(".claude.json")
}

fn project_config_path(project: &str) -> PathBuf {
    PathBuf::from(project).join(".mcp.json")
}

fn project_settings_local_path(project: &str) -> PathBuf {
    PathBuf::from(project)
        .join(".claude")
        .join("settings.local.json")
}

fn read_servers(path: &PathBuf) -> Value {
    fs::read_to_string(path)
        .ok()
        .and_then(|raw| serde_json::from_str::<Value>(&raw).ok())
        .and_then(|root| root.get("mcpServers").cloned())
        .filter(Value::is_object)
        .unwrap_or_else(|| json!({}))
}

pub fn list(project: Option<&str>) -> McpServers {
    McpServers {
        global: read_servers(&user_config_path()),
        project: project
            .map(|p| read_servers(&project_config_path(p)))
            .unwrap_or_else(|| json!({})),
    }
}

/// 读改写：只动 mcpServers 键，文件中其余内容原样保留
fn modify_servers(
    path: &PathBuf,
    apply: impl FnOnce(&mut Map<String, Value>),
) -> Result<(), String> {
    let mut root: Value = match fs::read_to_string(path) {
        Ok(raw) => serde_json::from_str(&raw).map_err(|e| format!("配置文件解析失败: {e}"))?,
        Err(_) => json!({}),
    };
    if !root.is_object() {
        return Err("配置文件顶层不是 JSON 对象".into());
    }
    let servers = root
        .as_object_mut()
        .unwrap()
        .entry("mcpServers")
        .or_insert_with(|| json!({}));
    let Some(map) = servers.as_object_mut() else {
        return Err("mcpServers 字段不是对象".into());
    };
    apply(map);
    // 原子写：~/.claude.json 被运行中的 claude.exe 高频读写，截断式覆盖会让它读到半截文件
    let pretty = serde_json::to_string_pretty(&root).map_err(|e| e.to_string())?;
    crate::fsx::write_atomic(path, pretty.as_bytes())
}

fn scope_path(scope: &str, project: Option<&str>) -> Result<PathBuf, String> {
    match scope {
        "global" => Ok(user_config_path()),
        "project" => project
            .map(project_config_path)
            .ok_or_else(|| "未指定项目".into()),
        _ => Err(format!("未知作用域: {scope}")),
    }
}

pub fn save(
    scope: &str,
    project: Option<&str>,
    name: &str,
    server_json: &str,
) -> Result<(), String> {
    let name = name.trim();
    if name.is_empty() {
        return Err("服务器名称不能为空".into());
    }
    let value: Value =
        serde_json::from_str(server_json).map_err(|e| format!("服务器配置 JSON 不合法: {e}"))?;
    if !value.is_object() {
        return Err("服务器配置必须是 JSON 对象".into());
    }
    modify_servers(&scope_path(scope, project)?, |map| {
        map.insert(name.to_string(), value);
    })
}

pub fn delete(scope: &str, project: Option<&str>, name: &str) -> Result<(), String> {
    modify_servers(&scope_path(scope, project)?, |map| {
        map.remove(name);
    })
}

/// 在项目 .claude/settings.local.json 中增/删对某 MCP 服务器的批准（enabledMcpjsonServers）。
/// enable=true：确保 name 在 enabledMcpjsonServers 且不在 disabledMcpjsonServers（批准生效）；
/// enable=false：从 enabledMcpjsonServers 移除。文件其余字段原样保留；无实际变化则不写盘
/// （register_server 每次启动都会调用，避免反复改动 mtime 触发重读或 git 噪声）。
pub fn set_project_mcp_enabled(project: &str, name: &str, enable: bool) -> Result<(), String> {
    let path = project_settings_local_path(project);
    // 注销且文件本就不存在：无需为移除而凭空创建配置文件
    if !enable && !path.exists() {
        return Ok(());
    }
    let mut root: Value = match fs::read_to_string(&path) {
        Ok(raw) => serde_json::from_str(&raw)
            .map_err(|e| format!("settings.local.json 解析失败: {e}"))?,
        Err(_) => json!({}),
    };
    if !root.is_object() {
        return Err("settings.local.json 顶层不是 JSON 对象".into());
    }

    let mut changed = false;
    {
        let obj = root.as_object_mut().unwrap();

        // enabledMcpjsonServers：enable 确保含 name，disable 确保不含
        let mut enabled_list: Vec<Value> = obj
            .get("enabledMcpjsonServers")
            .and_then(Value::as_array)
            .cloned()
            .unwrap_or_default();
        let listed = enabled_list.iter().any(|v| v.as_str() == Some(name));
        if enable && !listed {
            enabled_list.push(Value::String(name.to_string()));
            obj.insert("enabledMcpjsonServers".into(), Value::Array(enabled_list));
            changed = true;
        } else if !enable && listed {
            enabled_list.retain(|v| v.as_str() != Some(name));
            obj.insert("enabledMcpjsonServers".into(), Value::Array(enabled_list));
            changed = true;
        }

        // enable 时确保 name 不在 disabledMcpjsonServers，否则批准不生效（disable 优先级更高）
        if enable {
            let disabled = obj
                .get("disabledMcpjsonServers")
                .and_then(Value::as_array)
                .cloned(); // 立即 clone 释放对 obj 的借用，下面才能再可变借用
            if let Some(disabled) = disabled {
                if disabled.iter().any(|v| v.as_str() == Some(name)) {
                    let kept: Vec<Value> = disabled
                        .into_iter()
                        .filter(|v| v.as_str() != Some(name))
                        .collect();
                    obj.insert("disabledMcpjsonServers".into(), Value::Array(kept));
                    changed = true;
                }
            }
        }
    }

    if !changed {
        return Ok(());
    }
    let pretty = serde_json::to_string_pretty(&root).map_err(|e| e.to_string())?;
    crate::fsx::write_atomic(&path, pretty.as_bytes())
}
