use crate::{KondutoClient, KondutoResult};
use reqwest::Method;
use serde::Serialize;
use serde::de::DeserializeOwned;

impl KondutoClient {
    /// Realiza uma requisição HTTP genérica à API
    pub(crate) async fn request<T: DeserializeOwned>(
        &self,
        method: Method,
        endpoint: &str,
        body: Option<&impl Serialize>,
    ) -> KondutoResult<T> {
        let url = format!("{}{}", self.base_url(), endpoint);

        let mut request_builder = self
            .client()
            .request(method, &url)
            .header("Authorization", self.auth_header())
            .header("Content-Type", "application/json")
            .header(
                "User-Agent",
                crate::sdk::client::konduto_client::user_agent(),
            );

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

        let response = request_builder.send().await?;

        self.handle_response(response).await
    }

    /// Realiza uma requisição GET
    pub(crate) async fn get<T: DeserializeOwned>(&self, endpoint: &str) -> KondutoResult<T> {
        self.request::<T>(Method::GET, endpoint, None::<&()>).await
    }

    /// Realiza uma requisição POST
    pub(crate) async fn post<T: DeserializeOwned, B: Serialize>(
        &self,
        endpoint: &str,
        body: &B,
    ) -> KondutoResult<T> {
        self.request(Method::POST, endpoint, Some(body)).await
    }

    /// Realiza uma requisição PUT
    pub(crate) async fn put<T: DeserializeOwned, B: Serialize>(
        &self,
        endpoint: &str,
        body: &B,
    ) -> KondutoResult<T> {
        self.request(Method::PUT, endpoint, Some(body)).await
    }

    /// Realiza uma requisição DELETE
    pub(crate) async fn delete<T: DeserializeOwned>(&self, endpoint: &str) -> KondutoResult<T> {
        self.request::<T>(Method::DELETE, endpoint, None::<&()>)
            .await
    }
}
