use crate::db::{log_event, pool};
use crate::mcp_inject;
use crate::models::{ProductGroup, ProjectGroupMap};
use rusqlite::params;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub struct GroupInput {
    pub id: Option<String>,
    pub name: String,
    pub description: Option<String>,
    pub space_id: Option<String>,
}

#[tauri::command]
pub fn get_groups(space_id: Option<String>) -> Result<Vec<ProductGroup>, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let result = match &space_id {
        Some(sid) => {
            let mut stmt = conn.prepare(
                "SELECT * FROM product_groups WHERE space_id = ?1 ORDER BY sort_order ASC, id"
            ).map_err(|e| e.to_string())?;
            let x = stmt.query_map(params![sid], ProductGroup::from_row)
                .map_err(|e| e.to_string())?
                .collect::<Result<Vec<_>, _>>()
                .map_err(|e| e.to_string())?; x
        }
        None => {
            let mut stmt = conn.prepare("SELECT * FROM product_groups ORDER BY sort_order ASC, id").map_err(|e| e.to_string())?;
            let x = stmt.query_map([], ProductGroup::from_row)
                .map_err(|e| e.to_string())?
                .collect::<Result<Vec<_>, _>>()
                .map_err(|e| e.to_string())?; x
        }
    };
    Ok(result)
}

#[tauri::command]
pub fn create_group(input: GroupInput) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let id = input.id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
    conn.execute(
        "INSERT INTO product_groups (id, name, description, space_id) VALUES (?1, ?2, ?3, ?4)",
        params![id, input.name, input.description, input.space_id],
    )
    .map_err(|e| {
        if e.to_string().contains("UNIQUE") { "Group id already exists".into() }
        else { e.to_string() }
    })?;
    Ok(())
}

#[tauri::command]
pub fn update_group(id: String, input: GroupInput) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    conn.execute(
        "UPDATE product_groups SET name = COALESCE(?1, name), description = COALESCE(?2, description) WHERE id = ?3",
        params![input.name, input.description, id],
    )
    .map_err(|e| e.to_string())?;
    Ok(())
}

#[tauri::command]
pub fn delete_group(id: String) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    // 先清除所有成员的 MCP 配置（DB cascade 删除之前）
    let member_ids: Vec<String> = conn
        .prepare("SELECT project_id FROM project_group_map WHERE group_id = ?1")
        .map_err(|e| e.to_string())?
        .query_map(params![id], |row| row.get::<_, String>(0))
        .map_err(|e| e.to_string())?
        .filter_map(|r| r.ok())
        .collect();
    for project_id in &member_ids {
        if let Err(e) = mcp_inject::remove_project_mcp(project_id, &id) {
            let ctx = serde_json::json!({"project_id": project_id, "group_id": id}).to_string();
            log_event("mcp_inject", "warn", &format!("删除组时清除 MCP 配置失败: {e}"), Some(&ctx));
        }
    }
    conn.execute("DELETE FROM product_groups WHERE id = ?1", params![id])
        .map_err(|e| e.to_string())?;
    Ok(())
}

/// 按传入的 id 顺序批量更新 sort_order（index 即为新顺序）
#[tauri::command]
pub fn reorder_groups(ids: Vec<String>) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    for (i, id) in ids.iter().enumerate() {
        conn.execute(
            "UPDATE product_groups SET sort_order = ?1 WHERE id = ?2",
            params![i as i32, id],
        )
        .map_err(|e| e.to_string())?;
    }
    Ok(())
}

#[tauri::command]
pub fn get_group_maps() -> Result<Vec<ProjectGroupMap>, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    let mut stmt = conn.prepare("SELECT * FROM project_group_map").map_err(|e| e.to_string())?;
    let result = stmt.query_map([], ProjectGroupMap::from_row)
        .map_err(|e| e.to_string())?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|e| e.to_string());
    result
}

/// 确保独立项目有默认产品组。
/// 若项目已属于某产品组，直接返回；否则创建 "{project_name} (独立项目)" 组，加入成员并注入 MCP。
pub fn ensure_standalone_group(project_id: &str) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;

    // 已在某个组内，跳过
    let already_in_group: bool = conn
        .query_row(
            "SELECT COUNT(*) FROM project_group_map WHERE project_id = ?1",
            params![project_id],
            |row| row.get::<_, i64>(0),
        )
        .unwrap_or(0)
        > 0;
    if already_in_group {
        return Ok(());
    }

    // 查项目显示名和所属空间
    let (project_name, space_id): (String, Option<String>) = conn
        .query_row(
            "SELECT pp.name, pw.space_id FROM project_workspaces pw
             JOIN project_profiles pp ON pp.id = pw.profile_id
             WHERE pw.id = ?1",
            params![project_id],
            |row| Ok((row.get(0)?, row.get(1)?)),
        )
        .map_err(|_| format!("项目 {project_id} 不存在或未关联 profile"))?;

    let group_id = uuid::Uuid::new_v4().to_string();
    let group_name = format!("{project_name} (独立项目)");

    conn.execute(
        "INSERT INTO product_groups (id, name, space_id) VALUES (?1, ?2, ?3)",
        params![group_id, group_name, space_id],
    )
    .map_err(|e| e.to_string())?;

    conn.execute(
        "INSERT OR REPLACE INTO project_group_map (project_id, group_id) VALUES (?1, ?2)",
        params![project_id, group_id],
    )
    .map_err(|e| e.to_string())?;

    if let Err(e) = mcp_inject::inject_project_mcp(project_id, &group_id) {
        let ctx = serde_json::json!({"project_id": project_id, "group_id": &group_id}).to_string();
        log_event("mcp_inject", "warn", &format!("独立项目 MCP 注入失败: {e}"), Some(&ctx));
    }

    Ok(())
}

#[tauri::command]
pub fn add_group_member(project_id: String, group_id: String, role: Option<String>) -> Result<Option<String>, String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    conn.execute(
        "INSERT OR REPLACE INTO project_group_map (project_id, group_id, role) VALUES (?1, ?2, ?3)",
        params![project_id, group_id, role],
    )
    .map_err(|e| e.to_string())?;
    // DB 写入成功后注入 MCP 配置（非致命，注入失败不影响成员关系）
    let inject_warning = match mcp_inject::inject_project_mcp(&project_id, &group_id) {
        Ok(()) => None,
        Err(e) => {
            let ctx = serde_json::json!({"project_id": &project_id, "group_id": &group_id}).to_string();
            log_event("mcp_inject", "error", &format!("注入失败: {e}"), Some(&ctx));
            Some(e)
        }
    };
    Ok(inject_warning)
}

#[tauri::command]
pub fn remove_group_member(project_id: String, group_id: String) -> Result<(), String> {
    let conn = pool().get().map_err(|e| e.to_string())?;
    // 先清除 MCP 配置（需要在 DB 记录删除前查询项目路径）
    if let Err(e) = mcp_inject::remove_project_mcp(&project_id, &group_id) {
        let ctx = serde_json::json!({"project_id": &project_id, "group_id": &group_id}).to_string();
        log_event("mcp_inject", "warn", &format!("清除 MCP 配置失败: {e}"), Some(&ctx));
    }
    conn.execute(
        "DELETE FROM project_group_map WHERE project_id = ?1 AND group_id = ?2",
        params![project_id, group_id],
    )
    .map_err(|e| e.to_string())?;
    Ok(())
}
