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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentTask {
    pub id: String,
    pub project_id: String,
    pub agent_id: String,
    pub title: String,
    pub description: String,
    pub status: String,
    pub result: Option<String>,
    pub error: Option<String>,
    pub created_at: String,
    pub started_at: Option<String>,
    pub finished_at: Option<String>,
}

fn from_row(row: &rusqlite::Row) -> rusqlite::Result<AgentTask> {
    Ok(AgentTask {
        id: row.get(0)?,
        project_id: row.get(1)?,
        agent_id: row.get(2)?,
        title: row.get(3)?,
        description: row.get(4)?,
        status: row.get(5)?,
        result: row.get(6)?,
        error: row.get(7)?,
        created_at: row.get(8)?,
        started_at: row.get(9)?,
        finished_at: row.get(10)?,
    })
}

impl AgentTask {
    pub fn insert(
        conn: &Connection,
        project_id: &str,
        agent_id: &str,
        title: &str,
        description: &str,
    ) -> Result<AgentTask> {
        let id = Uuid::new_v4().to_string();
        let now = chrono::Utc::now().to_rfc3339();

        conn.execute(
            "INSERT INTO project_agent_tasks \
             (id, project_id, agent_id, title, description, status, created_at) \
             VALUES (?1, ?2, ?3, ?4, ?5, 'pending', ?6)",
            params![id, project_id, agent_id, title, description, now],
        )?;

        Ok(AgentTask {
            id,
            project_id: project_id.to_string(),
            agent_id: agent_id.to_string(),
            title: title.to_string(),
            description: description.to_string(),
            status: "pending".to_string(),
            result: None,
            error: None,
            created_at: now,
            started_at: None,
            finished_at: None,
        })
    }

    pub fn list_by_project(conn: &Connection, project_id: &str) -> Result<Vec<AgentTask>> {
        let mut stmt = conn.prepare(
            "SELECT id, project_id, agent_id, title, description, status, result, error, created_at, started_at, finished_at \
             FROM project_agent_tasks \
             WHERE project_id = ?1 \
             ORDER BY created_at DESC",
        )?;
        let rows = stmt.query_map(params![project_id], from_row)?;
        rows.collect()
    }

    pub fn get_by_id(conn: &Connection, id: &str) -> Result<AgentTask> {
        conn.query_row(
            "SELECT id, project_id, agent_id, title, description, status, result, error, created_at, started_at, finished_at \
             FROM project_agent_tasks \
             WHERE id = ?1",
            params![id],
            from_row,
        )
    }

    pub fn list_pending(conn: &Connection) -> Result<Vec<AgentTask>> {
        let mut stmt = conn.prepare(
            "SELECT id, project_id, agent_id, title, description, status, result, error, created_at, started_at, finished_at \
             FROM project_agent_tasks \
             WHERE status = 'pending' \
             ORDER BY created_at ASC",
        )?;
        let rows = stmt.query_map([], from_row)?;
        rows.collect()
    }

    pub fn mark_running(conn: &Connection, id: &str) -> Result<()> {
        let now = chrono::Utc::now().to_rfc3339();
        conn.execute(
            "UPDATE project_agent_tasks
             SET status = 'running',
                 started_at = ?1,
                 finished_at = NULL,
                 error = NULL
             WHERE id = ?2",
            params![now, id],
        )?;
        Ok(())
    }

    pub fn mark_done(conn: &Connection, id: &str, result: &str) -> Result<()> {
        let now = chrono::Utc::now().to_rfc3339();
        conn.execute(
            "UPDATE project_agent_tasks
             SET status = 'done',
                 result = ?1,
                 error = NULL,
                 finished_at = ?2
             WHERE id = ?3",
            params![result, now, id],
        )?;
        Ok(())
    }

    pub fn mark_error(conn: &Connection, id: &str, error: &str) -> Result<()> {
        let now = chrono::Utc::now().to_rfc3339();
        conn.execute(
            "UPDATE project_agent_tasks
             SET status = 'error',
                 error = ?1,
                 finished_at = ?2
             WHERE id = ?3",
            params![error, now, id],
        )?;
        Ok(())
    }

    pub fn mark_pending(conn: &Connection, id: &str, note: Option<&str>) -> Result<()> {
        conn.execute(
            "UPDATE project_agent_tasks
             SET status = 'pending',
                 result = NULL,
                 error = ?1,
                 started_at = NULL,
                 finished_at = NULL
             WHERE id = ?2",
            params![note, id],
        )?;
        Ok(())
    }

    pub fn retry(conn: &Connection, id: &str) -> Result<()> {
        Self::mark_pending(conn, id, None)
    }

    pub fn cancel(conn: &Connection, id: &str) -> Result<()> {
        let now = chrono::Utc::now().to_rfc3339();
        conn.execute(
            "UPDATE project_agent_tasks
             SET status = 'cancelled',
                 finished_at = ?1
             WHERE id = ?2",
            params![now, id],
        )?;
        Ok(())
    }
}
