// US-012: Listen key management endpoints

use crate::futures::models::trading::{EmptyResponse, ListenKeyResponse};
use crate::rest::client::RestClient;
use crate::rest::error::AsterDexError;
use crate::rest::response::ApiResponse;

impl RestClient {
    /// Create a new user data stream listen key.
    ///
    /// The returned listen key is valid for ~60 minutes. Renew with `renew_listen_key`
    /// every ~30 minutes to prevent expiry. The caller is responsible for scheduling renewal.
    ///
    /// # Errors
    /// - `ConfigError` — credentials not set
    /// - `RateLimited` — HTTP 429
    /// - `IpBanned` — HTTP 418
    pub async fn create_listen_key(
        &self,
    ) -> Result<ApiResponse<ListenKeyResponse>, AsterDexError> {
        self.signed_post("/fapi/v3/listenKey", &[]).await
    }

    /// Extend the validity of an existing listen key by ~60 minutes.
    ///
    /// Call every ~30 minutes to prevent expiry. The caller is responsible for
    /// scheduling this renewal — the SDK does not auto-renew (ADR-010).
    ///
    /// # Errors
    /// - `ConfigError` — credentials not set
    /// - `ApiError { code: -1125 }` — listen key not found or already expired
    pub async fn renew_listen_key(
        &self,
        listen_key: &str,
    ) -> Result<ApiResponse<EmptyResponse>, AsterDexError> {
        self.signed_put("/fapi/v3/listenKey", &[("listenKey", listen_key)])
            .await
    }

    /// Delete/invalidate a listen key.
    ///
    /// After deletion, the WebSocket user data stream using this key will be closed
    /// by the server.
    ///
    /// # Errors
    /// - `ConfigError` — credentials not set
    /// - `ApiError { code: -1125 }` — listen key not found
    pub async fn delete_listen_key(
        &self,
        listen_key: &str,
    ) -> Result<ApiResponse<EmptyResponse>, AsterDexError> {
        self.signed_delete("/fapi/v3/listenKey", &[("listenKey", listen_key)])
            .await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::auth::Credentials;

    // US-012: create_listen_key without credentials returns ConfigError
    #[tokio::test]
    async fn create_listen_key_without_credentials_returns_config_error() {
        let server = mockito::Server::new_async().await;
        // No mock needed — error is returned before any HTTP call
        let client = RestClient::new_public(&server.url()).unwrap();
        let result = client.create_listen_key().await;
        assert!(
            matches!(result, Err(AsterDexError::ConfigError { .. })),
            "expected ConfigError, got: {:?}",
            result
        );
        drop(server);
    }

    // US-012: renew_listen_key without credentials returns ConfigError
    #[tokio::test]
    async fn renew_listen_key_without_credentials_returns_config_error() {
        let server = mockito::Server::new_async().await;
        let client = RestClient::new_public(&server.url()).unwrap();
        let result = client.renew_listen_key("abc123").await;
        assert!(
            matches!(result, Err(AsterDexError::ConfigError { .. })),
            "expected ConfigError, got: {:?}",
            result
        );
        drop(server);
    }

    // US-012: delete_listen_key without credentials returns ConfigError
    #[tokio::test]
    async fn delete_listen_key_without_credentials_returns_config_error() {
        let server = mockito::Server::new_async().await;
        let client = RestClient::new_public(&server.url()).unwrap();
        let result = client.delete_listen_key("abc123").await;
        assert!(
            matches!(result, Err(AsterDexError::ConfigError { .. })),
            "expected ConfigError, got: {:?}",
            result
        );
        drop(server);
    }

    // US-012: create_listen_key with mock server returns listen_key == "abc123"
    #[tokio::test]
    async fn create_listen_key_mock() {
        let mut server = mockito::Server::new_async().await;
        let _mock = server
            .mock("POST", "/fapi/v3/listenKey")
            .match_query(mockito::Matcher::Any)
            .with_status(200)
            .with_header("content-type", "application/json")
            .with_body(r#"{"listenKey":"abc123"}"#)
            .create_async()
            .await;

        let creds = Credentials::new(
            "0x0000000000000000000000000000000000000001",
            "0x0000000000000000000000000000000000000002",
            "0000000000000000000000000000000000000000000000000000000000000001",
            714,
        )
        .unwrap();
        let client = RestClient::new(&server.url(), creds).unwrap();
        let resp = client.create_listen_key().await.unwrap();
        assert_eq!(resp.data.listen_key, "abc123");
    }
}
