use serde_json::{json, Value};

use crate::client::Client;
use crate::error::{Error, Result};
use crate::types::BrowserSession;

/// Browser-session management. Saved sessions can be replayed via the
/// /v1/browser-connect CDP endpoint to skip re-login flows.
pub struct Sessions<'a> {
    client: &'a Client,
}

impl<'a> Sessions<'a> {
    pub(crate) fn new(client: &'a Client) -> Self {
        Self { client }
    }

    /// List all saved sessions for the API key.
    pub async fn list(&self) -> Result<Vec<BrowserSession>> {
        let v: Value = self.client.send_json(reqwest::Method::GET, "/browser-sessions", None).await?;
        let arr = v.get("sessions").cloned().unwrap_or(v);
        serde_json::from_value(arr).map_err(|e| Error::Other(format!("decode response: {e}")))
    }

    /// Create an empty named session.
    pub async fn create(&self, name: &str, description: Option<&str>) -> Result<BrowserSession> {
        let mut body = json!({ "name": name });
        if let Some(d) = description {
            body["description"] = Value::String(d.to_string());
        }
        let v: Value = self.client.send_json(reqwest::Method::POST, "/browser-sessions", Some(body)).await?;
        serde_json::from_value(v).map_err(|e| Error::Other(format!("decode response: {e}")))
    }

    /// Save the current state of a CDP session by ID.
    pub async fn save(&self, session_id: &str, name: Option<&str>, description: Option<&str>) -> Result<BrowserSession> {
        let mut body = serde_json::Map::new();
        if let Some(n) = name { body.insert("name".into(), Value::String(n.to_string())); }
        if let Some(d) = description { body.insert("description".into(), Value::String(d.to_string())); }
        let path = format!("/browser-sessions/{session_id}/save");
        let v: Value = self.client.send_json(reqwest::Method::POST, &path, Some(Value::Object(body))).await?;
        serde_json::from_value(v).map_err(|e| Error::Other(format!("decode response: {e}")))
    }

    /// Update a saved session's metadata.
    pub async fn update(&self, session_id: &str, name: Option<&str>, description: Option<&str>) -> Result<BrowserSession> {
        let mut body = serde_json::Map::new();
        if let Some(n) = name { body.insert("name".into(), Value::String(n.to_string())); }
        if let Some(d) = description { body.insert("description".into(), Value::String(d.to_string())); }
        let path = format!("/browser-sessions/{session_id}");
        let v: Value = self.client.send_json(reqwest::Method::PUT, &path, Some(Value::Object(body))).await?;
        serde_json::from_value(v).map_err(|e| Error::Other(format!("decode response: {e}")))
    }

    /// Delete a saved session.
    pub async fn delete(&self, session_id: &str) -> Result<()> {
        let path = format!("/browser-sessions/{session_id}");
        let _: Value = self.client.send_json(reqwest::Method::DELETE, &path, None).await?;
        Ok(())
    }
}
