use std::time::Duration;

use reqwest::Client;
use serde_json::{json, Value};

use crate::error::{McpError, Result};

pub struct BackendClient {
    client: Client,
    base_url: String,
    auth_token: Option<String>,
}

impl BackendClient {
    pub fn new(base_url: String, auth_token: Option<String>) -> Self {
        Self {
            client: Client::new(),
            base_url,
            auth_token,
        }
    }

    async fn request(&self, method: &str, path: &str, body: Option<Value>) -> Result<Value> {
        let url = format!("{}{}", self.base_url, path);
        let mut request = match method {
            "GET" => self.client.get(&url),
            "POST" => self.client.post(&url),
            "PATCH" => self.client.patch(&url),
            _ => return Err(McpError::ToolError(format!("Unknown method: {}", method))),
        };

        if let Some(token) = &self.auth_token {
            request = request.bearer_auth(token);
        }

        if let Some(body) = body {
            request = request.json(&body);
        }

        let response = request.timeout(Duration::from_secs(30)).send().await?;

        let status = response.status();
        let text = response.text().await?;

        if !status.is_success() {
            return Err(McpError::BackendError {
                status: status.as_u16(),
                message: text,
            });
        }

        serde_json::from_str(&text).map_err(McpError::SerdeError)
    }

    pub async fn create_task(&self, project_id: &str, title: String) -> Result<Value> {
        self.request(
            "POST",
            "/api/tasks",
            Some(json!({
                "project_id": project_id,
                "title": title,
            })),
        )
        .await
    }

    pub async fn update_task(&self, task_id: &str, status: &str) -> Result<Value> {
        self.request(
            "PATCH",
            &format!("/api/tasks/{}", task_id),
            Some(json!({"status": status})),
        )
        .await
    }

    pub async fn get_project_summary(&self, project_id: &str) -> Result<Value> {
        self.request(
            "GET",
            &format!("/api/projects/{}/summary", project_id),
            None,
        )
        .await
    }

    pub async fn list_agents(&self) -> Result<Value> {
        self.request("GET", "/api/agents", None).await
    }

    pub async fn get_agent_capabilities(&self, agent_id: &str) -> Result<Value> {
        self.request(
            "GET",
            &format!("/api/agents/{}/capabilities", agent_id),
            None,
        )
        .await
    }

    pub async fn assign_task_to_agent(
        &self,
        role: &str,
        task_title: String,
        task_description: String,
    ) -> Result<Value> {
        self.request(
            "POST",
            "/api/agents/assign",
            Some(json!({
                "role": role,
                "title": task_title,
                "description": task_description,
            })),
        )
        .await
    }
}
