use rusqlite::{params, Connection};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct UserTodo {
    pub id: i64,
    pub project_id: String,
    pub content: String,
    pub done: bool,
    pub sort_order: i64,
    pub created_at: String,
}

// ── 业务函数（依赖注入，可单元测试）────────────────────────────────────────────

pub fn get_todos(conn: &Connection, project_id: &str) -> Vec<UserTodo> {
    let mut stmt = match conn.prepare(
        "SELECT id, project_id, content, done, sort_order, created_at
         FROM user_project_todos
         WHERE project_id = ?1
         ORDER BY sort_order ASC, id ASC",
    ) {
        Ok(s) => s,
        Err(_) => return vec![],
    };
    stmt.query_map(params![project_id], |row| {
        Ok(UserTodo {
            id:         row.get(0)?,
            project_id: row.get(1)?,
            content:    row.get(2)?,
            done:       row.get::<_, i64>(3)? != 0,
            sort_order: row.get(4)?,
            created_at: row.get(5)?,
        })
    })
    .map(|iter| iter.filter_map(|r| r.ok()).collect())
    .unwrap_or_default()
}

pub fn add_todo(conn: &Connection, project_id: &str, content: &str) -> Result<UserTodo, String> {
    let content = content.trim();
    if content.is_empty() {
        return Err("内容不能为空".to_string());
    }
    // sort_order = 当前最大值 + 1
    let max_order: i64 = conn
        .query_row(
            "SELECT COALESCE(MAX(sort_order), -1) FROM user_project_todos WHERE project_id = ?1",
            params![project_id],
            |row| row.get(0),
        )
        .unwrap_or(-1);

    conn.execute(
        "INSERT INTO user_project_todos (project_id, content, sort_order) VALUES (?1, ?2, ?3)",
        params![project_id, content, max_order + 1],
    )
    .map_err(|e| e.to_string())?;

    let id = conn.last_insert_rowid();
    conn.query_row(
        "SELECT id, project_id, content, done, sort_order, created_at
         FROM user_project_todos WHERE id = ?1",
        params![id],
        |row| {
            Ok(UserTodo {
                id:         row.get(0)?,
                project_id: row.get(1)?,
                content:    row.get(2)?,
                done:       row.get::<_, i64>(3)? != 0,
                sort_order: row.get(4)?,
                created_at: row.get(5)?,
            })
        },
    )
    .map_err(|e| e.to_string())
}

pub fn toggle_todo(conn: &Connection, id: i64) -> Result<(), String> {
    let rows = conn
        .execute(
            "UPDATE user_project_todos SET done = CASE WHEN done = 0 THEN 1 ELSE 0 END WHERE id = ?1",
            params![id],
        )
        .map_err(|e| e.to_string())?;
    if rows == 0 {
        return Err(format!("todo {} 不存在", id));
    }
    Ok(())
}

pub fn delete_todo(conn: &Connection, id: i64) -> Result<(), String> {
    conn.execute("DELETE FROM user_project_todos WHERE id = ?1", params![id])
        .map_err(|e| e.to_string())?;
    Ok(())
}

// ── Tauri command 薄包装层（仅负责获取连接）────────────────────────────────────

#[tauri::command]
pub fn get_user_todos(project_id: String) -> Result<Vec<UserTodo>, String> {
    let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
    Ok(get_todos(&conn, &project_id))
}

#[tauri::command]
pub fn add_user_todo(project_id: String, content: String) -> Result<UserTodo, String> {
    let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
    add_todo(&conn, &project_id, &content)
}

#[tauri::command]
pub fn toggle_user_todo(id: i64) -> Result<(), String> {
    let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
    toggle_todo(&conn, id)
}

#[tauri::command]
pub fn delete_user_todo(id: i64) -> Result<(), String> {
    let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
    delete_todo(&conn, id)
}

// ── 单元测试 ───────────────────────────────────────────────────────────────────

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

    fn setup() -> Connection {
        let conn = Connection::open_in_memory().unwrap();
        conn.execute_batch(
            "CREATE TABLE user_project_todos (
                id         INTEGER PRIMARY KEY AUTOINCREMENT,
                project_id TEXT NOT NULL,
                content    TEXT NOT NULL,
                done       INTEGER NOT NULL DEFAULT 0,
                sort_order INTEGER NOT NULL DEFAULT 0,
                created_at TEXT DEFAULT (datetime('now', 'localtime'))
            );",
        )
        .unwrap();
        conn
    }

    #[test]
    fn test_add_and_get() {
        let conn = setup();
        add_todo(&conn, "proj-1", "买牛奶").unwrap();
        add_todo(&conn, "proj-1", "写测试").unwrap();
        let todos = get_todos(&conn, "proj-1");
        assert_eq!(todos.len(), 2);
        assert_eq!(todos[0].content, "买牛奶");
        assert!(!todos[0].done);
    }

    #[test]
    fn test_empty_content_rejected() {
        let conn = setup();
        assert!(add_todo(&conn, "proj-1", "  ").is_err());
    }

    #[test]
    fn test_toggle() {
        let conn = setup();
        let todo = add_todo(&conn, "proj-1", "测试条目").unwrap();
        toggle_todo(&conn, todo.id).unwrap();
        let todos = get_todos(&conn, "proj-1");
        assert!(todos[0].done);
        toggle_todo(&conn, todo.id).unwrap();
        let todos = get_todos(&conn, "proj-1");
        assert!(!todos[0].done);
    }

    #[test]
    fn test_delete() {
        let conn = setup();
        let todo = add_todo(&conn, "proj-1", "待删除").unwrap();
        delete_todo(&conn, todo.id).unwrap();
        assert!(get_todos(&conn, "proj-1").is_empty());
    }

    #[test]
    fn test_get_empty_returns_empty() {
        let conn = setup();
        assert!(get_todos(&conn, "不存在的项目").is_empty());
    }

    #[test]
    fn test_sort_order_increments() {
        let conn = setup();
        add_todo(&conn, "proj-1", "第一").unwrap();
        add_todo(&conn, "proj-1", "第二").unwrap();
        let todos = get_todos(&conn, "proj-1");
        assert!(todos[0].sort_order < todos[1].sort_order);
    }
}
