//! Supervisor API methods.

use serde::{Deserialize, Serialize};
use uuid::Uuid;

use super::client::{ApiClient, ApiError};

// Request/Response types

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SpawnTaskRequest {
    pub name: String,
    pub plan: String,
    pub contract_id: Uuid,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_task_id: Option<Uuid>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub checkpoint_sha: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WaitRequest {
    pub timeout_seconds: i32,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadFileRequest {
    pub file_path: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBranchRequest {
    pub branch_name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub from_ref: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MergeRequest {
    pub squash: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub target_branch: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreatePrRequest {
    pub task_id: Uuid,
    pub title: String,
    pub body: String,
    pub base_branch: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CheckpointRequest {
    pub message: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AskQuestionRequest {
    pub question: String,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub choices: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<String>,
    pub timeout_seconds: i32,
    /// When true, the request will block indefinitely until user responds (no timeout)
    pub phaseguard: bool,
    /// When true, allow selecting multiple choices (response will be comma-separated)
    #[serde(default)]
    pub multi_select: bool,
}

// Generic response type for JSON output
#[derive(Deserialize, Serialize)]
pub struct JsonValue(pub serde_json::Value);

impl ApiClient {
    /// Get all tasks in a contract.
    pub async fn supervisor_tasks(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/contracts/{}/tasks", contract_id))
            .await
    }

    /// Get task tree structure.
    pub async fn supervisor_tree(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/contracts/{}/tree", contract_id))
            .await
    }

    /// Spawn a new task.
    pub async fn supervisor_spawn(&self, req: SpawnTaskRequest) -> Result<JsonValue, ApiError> {
        self.post("/api/v1/mesh/supervisor/tasks", &req).await
    }

    /// Wait for a task to complete.
    pub async fn supervisor_wait(
        &self,
        task_id: Uuid,
        timeout_seconds: i32,
    ) -> Result<JsonValue, ApiError> {
        let req = WaitRequest { timeout_seconds };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/wait", task_id), &req)
            .await
    }

    /// Read a file from a task's worktree.
    pub async fn supervisor_read_file(
        &self,
        task_id: Uuid,
        file_path: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = ReadFileRequest {
            file_path: file_path.to_string(),
        };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/read-file", task_id), &req)
            .await
    }

    /// Create a new branch.
    pub async fn supervisor_branch(
        &self,
        branch_name: &str,
        from_ref: Option<String>,
    ) -> Result<JsonValue, ApiError> {
        let req = CreateBranchRequest {
            branch_name: branch_name.to_string(),
            from_ref,
        };
        self.post("/api/v1/mesh/supervisor/branches", &req).await
    }

    /// Merge a task's changes.
    pub async fn supervisor_merge(
        &self,
        task_id: Uuid,
        target_branch: Option<String>,
        squash: bool,
    ) -> Result<JsonValue, ApiError> {
        let req = MergeRequest {
            squash,
            target_branch,
        };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/merge", task_id), &req)
            .await
    }

    /// Create a pull request.
    pub async fn supervisor_pr(
        &self,
        task_id: Uuid,
        title: &str,
        body: &str,
        base_branch: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = CreatePrRequest {
            task_id,
            title: title.to_string(),
            body: body.to_string(),
            base_branch: base_branch.to_string(),
        };
        self.post("/api/v1/mesh/supervisor/pr", &req).await
    }

    /// Get task diff.
    pub async fn supervisor_diff(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/tasks/{}/diff", task_id))
            .await
    }

    /// Create a checkpoint.
    pub async fn supervisor_checkpoint(
        &self,
        task_id: Uuid,
        message: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = CheckpointRequest {
            message: message.to_string(),
        };
        self.post(&format!("/api/v1/mesh/tasks/{}/checkpoint", task_id), &req)
            .await
    }

    /// List checkpoints.
    pub async fn supervisor_checkpoints(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/tasks/{}/checkpoints", task_id))
            .await
    }

    /// Get contract status.
    pub async fn supervisor_status(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/contracts/{}/daemon/status", contract_id))
            .await
    }

    /// Ask a question and wait for user feedback.
    pub async fn supervisor_ask(
        &self,
        question: &str,
        choices: Vec<String>,
        context: Option<String>,
        timeout_seconds: i32,
        phaseguard: bool,
        multi_select: bool,
    ) -> Result<JsonValue, ApiError> {
        let req = AskQuestionRequest {
            question: question.to_string(),
            choices,
            context,
            timeout_seconds,
            phaseguard,
            multi_select,
        };
        self.post("/api/v1/mesh/supervisor/questions", &req).await
    }

    /// Advance contract to a new phase.
    pub async fn supervisor_advance_phase(
        &self,
        contract_id: Uuid,
        phase: &str,
    ) -> Result<JsonValue, ApiError> {
        #[derive(Serialize)]
        struct AdvancePhaseRequest {
            phase: String,
        }
        let req = AdvancePhaseRequest {
            phase: phase.to_string(),
        };
        self.post(&format!("/api/v1/contracts/{}/phase", contract_id), &req)
            .await
    }

    /// Get individual task details.
    pub async fn supervisor_get_task(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/tasks/{}", task_id)).await
    }

    /// Get task output/claude log.
    pub async fn supervisor_get_task_output(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/tasks/{}/output", task_id))
            .await
    }
}
