use futures_util::StreamExt;
use paddler_types::agent_controller_pool_snapshot::AgentControllerPoolSnapshot;
use paddler_types::agent_desired_state::AgentDesiredState;
use paddler_types::balancer_desired_state::BalancerDesiredState;
use paddler_types::buffered_request_manager_snapshot::BufferedRequestManagerSnapshot;
use paddler_types::chat_template::ChatTemplate;
use paddler_types::model_metadata::ModelMetadata;
use reqwest::Client;
use serde_json::from_str;
use url::Url;

use crate::Result;
use crate::agents_stream::AgentsStream;
use crate::buffered_requests_stream::BufferedRequestsStream;
use crate::format_api_url::format_api_url;
use crate::stream::sse::Sse;

pub struct ClientManagement<'client> {
    url: &'client Url,
    http_client: &'client Client,
}

impl<'client> ClientManagement<'client> {
    #[must_use]
    pub const fn new(url: &'client Url, http_client: &'client Client) -> Self {
        Self { url, http_client }
    }

    pub async fn get_health(&self) -> Result<String> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/health")?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.text().await?)
    }

    pub async fn get_agents(&self) -> Result<AgentControllerPoolSnapshot> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/api/v1/agents")?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn get_balancer_desired_state(&self) -> Result<BalancerDesiredState> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/api/v1/balancer_desired_state")?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn get_balancer_applicable_state(&self) -> Result<Option<AgentDesiredState>> {
        let response = self
            .http_client
            .get(format_api_url(
                self.url,
                "/api/v1/balancer_applicable_state",
            )?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn put_balancer_desired_state(&self, state: &BalancerDesiredState) -> Result<()> {
        self.http_client
            .put(format_api_url(self.url, "/api/v1/balancer_desired_state")?)
            .json(state)
            .send()
            .await?
            .error_for_status()?;

        Ok(())
    }

    pub async fn get_buffered_requests(&self) -> Result<BufferedRequestManagerSnapshot> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/api/v1/buffered_requests")?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn get_agents_stream(&self) -> Result<AgentsStream> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/api/v1/agents/stream")?)
            .send()
            .await?
            .error_for_status()?;

        let stream = Sse::from_response(response)
            .map(|result| result.and_then(|data| from_str(&data).map_err(Into::into)));

        Ok(Box::pin(stream))
    }

    pub async fn get_buffered_requests_stream(&self) -> Result<BufferedRequestsStream> {
        let response = self
            .http_client
            .get(format_api_url(
                self.url,
                "/api/v1/buffered_requests/stream",
            )?)
            .send()
            .await?
            .error_for_status()?;

        let stream = Sse::from_response(response)
            .map(|result| result.and_then(|data| from_str(&data).map_err(Into::into)));

        Ok(Box::pin(stream))
    }

    pub async fn get_chat_template_override(&self, agent_id: &str) -> Result<Option<ChatTemplate>> {
        let response = self
            .http_client
            .get(format_api_url(
                self.url,
                &format!("/api/v1/agent/{agent_id}/chat_template_override"),
            )?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn get_model_metadata(&self, agent_id: &str) -> Result<Option<ModelMetadata>> {
        let response = self
            .http_client
            .get(format_api_url(
                self.url,
                &format!("/api/v1/agent/{agent_id}/model_metadata"),
            )?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.json().await?)
    }

    pub async fn get_metrics(&self) -> Result<String> {
        let response = self
            .http_client
            .get(format_api_url(self.url, "/metrics")?)
            .send()
            .await?
            .error_for_status()?;

        Ok(response.text().await?)
    }
}
