use crate::{db, db::log_event};
use serde_json::{json, Value};
use std::path::PathBuf;

const MCP_KEY_PREFIX: &str = "lian-jing:group-";

// ── 路径解析 ──────────────────────────────────────────────────────────────────

/// 解析项目根目录路径（WSL 项目自动转为 Windows UNC 路径）
fn project_root(project_id: &str) -> Result<PathBuf, String> {
    let conn = db::pool().get().map_err(|e| e.to_string())?;

    let row: rusqlite::Result<(Option<String>, Option<String>, Option<String>)> = conn.query_row(
        "SELECT win_path, wsl_path, platform FROM project_workspaces WHERE id = ?1",
        [project_id],
        |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?)),
    );

    let (win_path, wsl_path, platform) =
        row.map_err(|_| format!("项目 {} 不存在", project_id))?;

    if platform.as_deref() == Some("wsl") {
        let wsl = wsl_path.ok_or_else(|| "WSL 项目未配置 wsl_path".to_string())?;
        let distro: String = conn
            .query_row(
                "SELECT value FROM settings WHERE key = 'wsl_distro'",
                [],
                |r| r.get(0),
            )
            .unwrap_or_else(|_| "Ubuntu".to_string());
        let inner = wsl.trim_start_matches('/').replace('/', "\\");
        Ok(PathBuf::from(format!(
            "\\\\wsl.localhost\\{}\\{}",
            distro, inner
        )))
    } else {
        let win = win_path.ok_or_else(|| "Windows 项目未配置 win_path".to_string())?;
        Ok(PathBuf::from(win))
    }
}

fn settings_path(project_id: &str) -> Result<PathBuf, String> {
    Ok(project_root(project_id)?.join(".claude").join("settings.json"))
}

// ── JSON 读写 ─────────────────────────────────────────────────────────────────

fn read_json(path: &PathBuf) -> Result<Value, String> {
    if !path.exists() {
        return Ok(json!({}));
    }
    let content = std::fs::read_to_string(path)
        .map_err(|e| format!("读取 settings.json 失败: {}", e))?;
    if content.trim().is_empty() {
        return Ok(json!({}));
    }
    serde_json::from_str(&content).map_err(|e| {
        format!(
            "settings.json 格式错误，请手动修复后重试（{}）: {}",
            path.display(),
            e
        )
    })
}

fn write_json(path: &PathBuf, value: &Value) -> Result<(), String> {
    if let Some(parent) = path.parent() {
        std::fs::create_dir_all(parent)
            .map_err(|e| format!("创建 .claude 目录失败: {}", e))?;
    }
    let content = serde_json::to_string_pretty(value).map_err(|e| e.to_string())?;
    std::fs::write(path, content).map_err(|e| format!("写入 settings.json 失败: {}", e))
}

// ── 公开接口 ──────────────────────────────────────────────────────────────────

/// 向项目的 .claude/settings.json 注入产品组 MCP 配置
pub fn inject_project_mcp(project_id: &str, group_id: &str) -> Result<(), String> {
    let port = crate::mcp_server::read_port();
    let path = settings_path(project_id)?;
    let mut settings = read_json(&path)?;

    let servers = settings
        .as_object_mut()
        .ok_or("settings.json 顶层必须是 JSON 对象")?
        .entry("mcpServers")
        .or_insert(json!({}));

    let key = format!("{}{}", MCP_KEY_PREFIX, group_id);
    servers[&key] = json!({
        "type": "sse",
        "url": format!("http://127.0.0.1:{}/mcp/group/{}", port, group_id)
    });

    write_json(&path, &settings).inspect(|_| {
        let ctx = serde_json::json!({"project_id": project_id, "group_id": group_id}).to_string();
        log_event("mcp_inject", "info", "MCP 配置注入成功", Some(&ctx));
    })
}

/// 从项目的 .claude/settings.json 移除产品组 MCP 配置
pub fn remove_project_mcp(project_id: &str, group_id: &str) -> Result<(), String> {
    let path = settings_path(project_id)?;
    if !path.exists() {
        return Ok(());
    }
    let mut settings = read_json(&path)?;

    let key = format!("{}{}", MCP_KEY_PREFIX, group_id);
    if let Some(servers) = settings
        .get_mut("mcpServers")
        .and_then(|v| v.as_object_mut())
    {
        servers.remove(&key);
    }

    write_json(&path, &settings)
}

/// 端口变更后重新注入所有产品组成员的 MCP 配置
/// 返回注入失败的错误列表（部分失败不影响其他项目）
pub fn reinject_all_mcp() -> Vec<String> {
    let conn = match db::pool().get() {
        Ok(c) => c,
        Err(e) => return vec![e.to_string()],
    };

    let mappings: Vec<(String, String)> = {
        let mut stmt = match conn.prepare("SELECT project_id, group_id FROM project_group_map") {
            Ok(s) => s,
            Err(e) => return vec![e.to_string()],
        };
        stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))
            .map(|iter| iter.filter_map(|r| r.ok()).collect())
            .unwrap_or_default()
    };

    let mut errors = Vec::new();
    for (project_id, group_id) in mappings {
        if let Err(e) = inject_project_mcp(&project_id, &group_id) {
            errors.push(format!("项目 {}: {}", project_id, e));
        }
    }
    errors
}
