//! API key operations.

use crate::zeroid::{
    client::{parse_api_error, ZeroIDClient},
    error::ZeroIDError,
    types::{
        ApiKey, ApiKeyCreated, ApiKeyList, ApiKeyRevoked, CreateApiKeyRequest, RevokeApiKeyRequest,
    },
};

/// API keys resource — create, list, and revoke on `/api/v1/api-keys`.
pub struct ApiKeysResource<'a> {
    pub(crate) client: &'a ZeroIDClient,
}

impl<'a> ApiKeysResource<'a> {
    /// Create a new API key.
    ///
    /// `POST /api/v1/api-keys`
    pub async fn create(
        &self,
        request: &CreateApiKeyRequest,
    ) -> Result<ApiKeyCreated, ZeroIDError> {
        let body = serde_json::to_value(request)?;
        let headers = self.client.admin_headers();
        let resp = self
            .client
            .send_with_retry(
                reqwest::Method::POST,
                "/api/v1/api-keys",
                headers,
                Some(&body),
            )
            .await?;
        if !resp.status().is_success() {
            return Err(parse_api_error(resp).await);
        }
        Ok(resp.json().await?)
    }

    /// Get an API key by ID.
    ///
    /// `GET /api/v1/api-keys/{id}`
    pub async fn get(&self, id: &str) -> Result<ApiKey, ZeroIDError> {
        let path = format!("/api/v1/api-keys/{id}");
        let headers = self.client.admin_headers();
        let resp = self
            .client
            .send_with_retry(reqwest::Method::GET, &path, headers, None)
            .await?;
        if !resp.status().is_success() {
            return Err(parse_api_error(resp).await);
        }
        Ok(resp.json().await?)
    }

    /// List API keys for the current tenant.
    ///
    /// `GET /api/v1/api-keys`
    pub async fn list(&self) -> Result<ApiKeyList, ZeroIDError> {
        let headers = self.client.admin_headers();
        let resp = self
            .client
            .send_with_retry(reqwest::Method::GET, "/api/v1/api-keys", headers, None)
            .await?;
        if !resp.status().is_success() {
            return Err(parse_api_error(resp).await);
        }
        Ok(resp.json().await?)
    }

    /// Revoke an API key.
    ///
    /// `POST /api/v1/api-keys/{id}/revoke`
    pub async fn revoke(
        &self,
        id: &str,
        request: &RevokeApiKeyRequest,
    ) -> Result<ApiKeyRevoked, ZeroIDError> {
        let path = format!("/api/v1/api-keys/{id}/revoke");
        let body = serde_json::to_value(request)?;
        let headers = self.client.admin_headers();
        let resp = self
            .client
            .send_with_retry(reqwest::Method::POST, &path, headers, Some(&body))
            .await?;
        if !resp.status().is_success() {
            return Err(parse_api_error(resp).await);
        }
        Ok(resp.json().await?)
    }
}
