/*
 * Binance Gift Card REST API
 *
 * OpenAPI Specification for the Binance Gift Card REST API
 *
 * The version of the OpenAPI document: 1.0.0
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

#![allow(unused_imports)]
use async_trait::async_trait;
use derive_builder::Builder;
use reqwest;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::collections::BTreeMap;

use crate::common::{
    config::ConfigurationRestApi,
    models::{ParamBuildError, RestApiResponse},
    utils::send_request,
};
use crate::gift_card::rest_api::models;

const HAS_TIME_UNIT: bool = false;

#[async_trait]
pub trait MarketDataApi: Send + Sync {
    async fn create_a_dual_token_gift_card(
        &self,
        params: CreateADualTokenGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::CreateADualTokenGiftCardResponse>>;
    async fn create_a_single_token_gift_card(
        &self,
        params: CreateASingleTokenGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::CreateASingleTokenGiftCardResponse>>;
    async fn fetch_rsa_public_key(
        &self,
        params: FetchRsaPublicKeyParams,
    ) -> anyhow::Result<RestApiResponse<models::FetchRsaPublicKeyResponse>>;
    async fn fetch_token_limit(
        &self,
        params: FetchTokenLimitParams,
    ) -> anyhow::Result<RestApiResponse<models::FetchTokenLimitResponse>>;
    async fn redeem_a_binance_gift_card(
        &self,
        params: RedeemABinanceGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::RedeemABinanceGiftCardResponse>>;
    async fn verify_binance_gift_card_by_gift_card_number(
        &self,
        params: VerifyBinanceGiftCardByGiftCardNumberParams,
    ) -> anyhow::Result<RestApiResponse<models::VerifyBinanceGiftCardByGiftCardNumberResponse>>;
}

#[derive(Debug, Clone)]
pub struct MarketDataApiClient {
    configuration: ConfigurationRestApi,
}

impl MarketDataApiClient {
    pub fn new(configuration: ConfigurationRestApi) -> Self {
        Self { configuration }
    }
}

/// Request parameters for the [`create_a_dual_token_gift_card`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`create_a_dual_token_gift_card`](#method.create_a_dual_token_gift_card).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CreateADualTokenGiftCardParams {
    /// The token you want to pay, example: BUSD
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub base_token: String,
    /// The token you want to buy, example: BNB. If faceToken = baseToken, it's the same as createCode endpoint.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub face_token: String,
    /// The base token asset quantity, example : 1.002
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub base_token_amount: rust_decimal::Decimal,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CreateADualTokenGiftCardParams {
    /// Create a builder for [`create_a_dual_token_gift_card`].
    ///
    /// Required parameters:
    ///
    /// * `base_token` — The token you want to pay, example: BUSD
    /// * `face_token` — The token you want to buy, example: BNB. If faceToken = baseToken, it's the same as createCode endpoint.
    /// * `base_token_amount` — The base token asset quantity, example : 1.002
    ///
    #[must_use]
    pub fn builder(
        base_token: String,
        face_token: String,
        base_token_amount: rust_decimal::Decimal,
    ) -> CreateADualTokenGiftCardParamsBuilder {
        CreateADualTokenGiftCardParamsBuilder::default()
            .base_token(base_token)
            .face_token(face_token)
            .base_token_amount(base_token_amount)
    }
}
/// Request parameters for the [`create_a_single_token_gift_card`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`create_a_single_token_gift_card`](#method.create_a_single_token_gift_card).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CreateASingleTokenGiftCardParams {
    /// The token type contained in the Binance Gift Card
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub token: String,
    /// The amount of the token contained in the Binance Gift Card
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub amount: rust_decimal::Decimal,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CreateASingleTokenGiftCardParams {
    /// Create a builder for [`create_a_single_token_gift_card`].
    ///
    /// Required parameters:
    ///
    /// * `token` — The token type contained in the Binance Gift Card
    /// * `amount` — The amount of the token contained in the Binance Gift Card
    ///
    #[must_use]
    pub fn builder(
        token: String,
        amount: rust_decimal::Decimal,
    ) -> CreateASingleTokenGiftCardParamsBuilder {
        CreateASingleTokenGiftCardParamsBuilder::default()
            .token(token)
            .amount(amount)
    }
}
/// Request parameters for the [`fetch_rsa_public_key`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`fetch_rsa_public_key`](#method.fetch_rsa_public_key).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct FetchRsaPublicKeyParams {
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl FetchRsaPublicKeyParams {
    /// Create a builder for [`fetch_rsa_public_key`].
    ///
    #[must_use]
    pub fn builder() -> FetchRsaPublicKeyParamsBuilder {
        FetchRsaPublicKeyParamsBuilder::default()
    }
}
/// Request parameters for the [`fetch_token_limit`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`fetch_token_limit`](#method.fetch_token_limit).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct FetchTokenLimitParams {
    /// The token you want to pay, example: BUSD
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub base_token: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl FetchTokenLimitParams {
    /// Create a builder for [`fetch_token_limit`].
    ///
    /// Required parameters:
    ///
    /// * `base_token` — The token you want to pay, example: BUSD
    ///
    #[must_use]
    pub fn builder(base_token: String) -> FetchTokenLimitParamsBuilder {
        FetchTokenLimitParamsBuilder::default().base_token(base_token)
    }
}
/// Request parameters for the [`redeem_a_binance_gift_card`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`redeem_a_binance_gift_card`](#method.redeem_a_binance_gift_card).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct RedeemABinanceGiftCardParams {
    /// Redemption code of Binance Gift Card to be redeemed, supports both Plaintext & Encrypted code.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub code: String,
    /// Each external unique ID represents a unique user on the partner platform. The function helps you to identify the redemption behavior of different users, such as redemption frequency and amount. It also helps risk and limit control of a single account, such as daily limit on redemption volume, frequency, and incorrect number of entries. This will also prevent a single user account reach the partner's daily redemption limits. We strongly recommend you to use this feature and transfer us the User ID of your users if you have different users redeeming Binance Gift Cards on your platform. To protect user data privacy, you may choose to transfer the user id in any desired format (max. 400 characters).
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub external_uid: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl RedeemABinanceGiftCardParams {
    /// Create a builder for [`redeem_a_binance_gift_card`].
    ///
    /// Required parameters:
    ///
    /// * `code` — Redemption code of Binance Gift Card to be redeemed, supports both Plaintext & Encrypted code.
    ///
    #[must_use]
    pub fn builder(code: String) -> RedeemABinanceGiftCardParamsBuilder {
        RedeemABinanceGiftCardParamsBuilder::default().code(code)
    }
}
/// Request parameters for the [`verify_binance_gift_card_by_gift_card_number`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`verify_binance_gift_card_by_gift_card_number`](#method.verify_binance_gift_card_by_gift_card_number).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct VerifyBinanceGiftCardByGiftCardNumberParams {
    /// Enter the Gift Card Number
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub reference_no: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl VerifyBinanceGiftCardByGiftCardNumberParams {
    /// Create a builder for [`verify_binance_gift_card_by_gift_card_number`].
    ///
    /// Required parameters:
    ///
    /// * `reference_no` — Enter the Gift Card Number
    ///
    #[must_use]
    pub fn builder(reference_no: String) -> VerifyBinanceGiftCardByGiftCardNumberParamsBuilder {
        VerifyBinanceGiftCardByGiftCardNumberParamsBuilder::default().reference_no(reference_no)
    }
}

#[async_trait]
impl MarketDataApi for MarketDataApiClient {
    async fn create_a_dual_token_gift_card(
        &self,
        params: CreateADualTokenGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::CreateADualTokenGiftCardResponse>> {
        let CreateADualTokenGiftCardParams {
            base_token,
            face_token,
            base_token_amount,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("baseToken".to_string(), json!(base_token));

        query_params.insert("faceToken".to_string(), json!(face_token));

        query_params.insert("baseTokenAmount".to_string(), json!(base_token_amount));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::CreateADualTokenGiftCardResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/buyCode",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn create_a_single_token_gift_card(
        &self,
        params: CreateASingleTokenGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::CreateASingleTokenGiftCardResponse>> {
        let CreateASingleTokenGiftCardParams {
            token,
            amount,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("token".to_string(), json!(token));

        query_params.insert("amount".to_string(), json!(amount));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::CreateASingleTokenGiftCardResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/createCode",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn fetch_rsa_public_key(
        &self,
        params: FetchRsaPublicKeyParams,
    ) -> anyhow::Result<RestApiResponse<models::FetchRsaPublicKeyResponse>> {
        let FetchRsaPublicKeyParams { recv_window } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::FetchRsaPublicKeyResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/cryptography/rsa-public-key",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn fetch_token_limit(
        &self,
        params: FetchTokenLimitParams,
    ) -> anyhow::Result<RestApiResponse<models::FetchTokenLimitResponse>> {
        let FetchTokenLimitParams {
            base_token,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("baseToken".to_string(), json!(base_token));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::FetchTokenLimitResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/buyCode/token-limit",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn redeem_a_binance_gift_card(
        &self,
        params: RedeemABinanceGiftCardParams,
    ) -> anyhow::Result<RestApiResponse<models::RedeemABinanceGiftCardResponse>> {
        let RedeemABinanceGiftCardParams {
            code,
            external_uid,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("code".to_string(), json!(code));

        if let Some(rw) = external_uid {
            query_params.insert("externalUid".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::RedeemABinanceGiftCardResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/redeemCode",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn verify_binance_gift_card_by_gift_card_number(
        &self,
        params: VerifyBinanceGiftCardByGiftCardNumberParams,
    ) -> anyhow::Result<RestApiResponse<models::VerifyBinanceGiftCardByGiftCardNumberResponse>>
    {
        let VerifyBinanceGiftCardByGiftCardNumberParams {
            reference_no,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("referenceNo".to_string(), json!(reference_no));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::VerifyBinanceGiftCardByGiftCardNumberResponse>(
            &self.configuration,
            "/sapi/v1/giftcard/verify",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }
}

#[cfg(all(test, feature = "gift_card"))]
mod tests {
    use super::*;
    use crate::TOKIO_SHARED_RT;
    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
    use async_trait::async_trait;
    use std::collections::HashMap;

    struct DummyRestApiResponse<T> {
        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
        status: u16,
        headers: HashMap<String, String>,
        rate_limits: Option<Vec<RestApiRateLimit>>,
    }

    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
        fn from(dummy: DummyRestApiResponse<T>) -> Self {
            Self {
                data_fn: dummy.inner,
                status: dummy.status,
                headers: dummy.headers,
                rate_limits: dummy.rate_limits,
            }
        }
    }

    struct MockMarketDataApiClient {
        force_error: bool,
    }

    #[async_trait]
    impl MarketDataApi for MockMarketDataApiClient {
        async fn create_a_dual_token_gift_card(
            &self,
            _params: CreateADualTokenGiftCardParams,
        ) -> anyhow::Result<RestApiResponse<models::CreateADualTokenGiftCardResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let dummy_response: models::CreateADualTokenGiftCardResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CreateADualTokenGiftCardResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn create_a_single_token_gift_card(
            &self,
            _params: CreateASingleTokenGiftCardParams,
        ) -> anyhow::Result<RestApiResponse<models::CreateASingleTokenGiftCardResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let dummy_response: models::CreateASingleTokenGiftCardResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CreateASingleTokenGiftCardResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn fetch_rsa_public_key(
            &self,
            _params: FetchRsaPublicKeyParams,
        ) -> anyhow::Result<RestApiResponse<models::FetchRsaPublicKeyResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXBBVKLAc1GQ5FsIFFqOHrPTox5noBONIKr+IAedTR9FkVxq6e65updEbfdhRNkMOeYIO2i0UylrjGC0X8YSoIszmrVHeV0l06Zh1oJuZos1+7N+WLuz9JvlPaawof3GUakTxYWWCa9+8KIbLKsoKMdfS96VT+8iOXO3quMGKUmQIDAQAB","success":true}"#).unwrap();
            let dummy_response: models::FetchRsaPublicKeyResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::FetchRsaPublicKeyResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn fetch_token_limit(
            &self,
            _params: FetchTokenLimitParams,
        ) -> anyhow::Result<RestApiResponse<models::FetchTokenLimitResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"coin":"BNB","fromMin":"0.01","fromMax":"1"}],"success":true}"#).unwrap();
            let dummy_response: models::FetchTokenLimitResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::FetchTokenLimitResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn redeem_a_binance_gift_card(
            &self,
            _params: RedeemABinanceGiftCardParams,
        ) -> anyhow::Result<RestApiResponse<models::RedeemABinanceGiftCardResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002328060227","identityNo":"10317392647411060736","token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let dummy_response: models::RedeemABinanceGiftCardResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::RedeemABinanceGiftCardResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn verify_binance_gift_card_by_gift_card_number(
            &self,
            _params: VerifyBinanceGiftCardByGiftCardNumberParams,
        ) -> anyhow::Result<RestApiResponse<models::VerifyBinanceGiftCardByGiftCardNumberResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"valid":true,"token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let dummy_response: models::VerifyBinanceGiftCardByGiftCardNumberResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::VerifyBinanceGiftCardByGiftCardNumberResponse",
                );

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }
    }

    #[test]
    fn create_a_dual_token_gift_card_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = CreateADualTokenGiftCardParams::builder("base_token_example".to_string(),"face_token_example".to_string(),dec!(1.0),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let expected_response : models::CreateADualTokenGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CreateADualTokenGiftCardResponse");

            let resp = client.create_a_dual_token_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn create_a_dual_token_gift_card_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = CreateADualTokenGiftCardParams::builder("base_token_example".to_string(),"face_token_example".to_string(),dec!(1.0),).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let expected_response : models::CreateADualTokenGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CreateADualTokenGiftCardResponse");

            let resp = client.create_a_dual_token_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn create_a_dual_token_gift_card_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params = CreateADualTokenGiftCardParams::builder(
                "base_token_example".to_string(),
                "face_token_example".to_string(),
                dec!(1.0),
            )
            .build()
            .unwrap();

            match client.create_a_dual_token_gift_card(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn create_a_single_token_gift_card_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = CreateASingleTokenGiftCardParams::builder("token_example".to_string(),dec!(1.0),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let expected_response : models::CreateASingleTokenGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CreateASingleTokenGiftCardResponse");

            let resp = client.create_a_single_token_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn create_a_single_token_gift_card_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = CreateASingleTokenGiftCardParams::builder("token_example".to_string(),dec!(1.0),).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002144060553","code":"6H9EKF5ECCWFBHGE","expiredTime":1727417154000},"success":true}"#).unwrap();
            let expected_response : models::CreateASingleTokenGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CreateASingleTokenGiftCardResponse");

            let resp = client.create_a_single_token_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn create_a_single_token_gift_card_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params =
                CreateASingleTokenGiftCardParams::builder("token_example".to_string(), dec!(1.0))
                    .build()
                    .unwrap();

            match client.create_a_single_token_gift_card(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn fetch_rsa_public_key_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = FetchRsaPublicKeyParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXBBVKLAc1GQ5FsIFFqOHrPTox5noBONIKr+IAedTR9FkVxq6e65updEbfdhRNkMOeYIO2i0UylrjGC0X8YSoIszmrVHeV0l06Zh1oJuZos1+7N+WLuz9JvlPaawof3GUakTxYWWCa9+8KIbLKsoKMdfS96VT+8iOXO3quMGKUmQIDAQAB","success":true}"#).unwrap();
            let expected_response : models::FetchRsaPublicKeyResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FetchRsaPublicKeyResponse");

            let resp = client.fetch_rsa_public_key(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn fetch_rsa_public_key_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = FetchRsaPublicKeyParams::builder().recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXBBVKLAc1GQ5FsIFFqOHrPTox5noBONIKr+IAedTR9FkVxq6e65updEbfdhRNkMOeYIO2i0UylrjGC0X8YSoIszmrVHeV0l06Zh1oJuZos1+7N+WLuz9JvlPaawof3GUakTxYWWCa9+8KIbLKsoKMdfS96VT+8iOXO3quMGKUmQIDAQAB","success":true}"#).unwrap();
            let expected_response : models::FetchRsaPublicKeyResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FetchRsaPublicKeyResponse");

            let resp = client.fetch_rsa_public_key(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn fetch_rsa_public_key_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params = FetchRsaPublicKeyParams::builder().build().unwrap();

            match client.fetch_rsa_public_key(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn fetch_token_limit_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = FetchTokenLimitParams::builder("base_token_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"coin":"BNB","fromMin":"0.01","fromMax":"1"}],"success":true}"#).unwrap();
            let expected_response : models::FetchTokenLimitResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FetchTokenLimitResponse");

            let resp = client.fetch_token_limit(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn fetch_token_limit_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = FetchTokenLimitParams::builder("base_token_example".to_string(),).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"coin":"BNB","fromMin":"0.01","fromMax":"1"}],"success":true}"#).unwrap();
            let expected_response : models::FetchTokenLimitResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FetchTokenLimitResponse");

            let resp = client.fetch_token_limit(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn fetch_token_limit_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params = FetchTokenLimitParams::builder("base_token_example".to_string())
                .build()
                .unwrap();

            match client.fetch_token_limit(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn redeem_a_binance_gift_card_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = RedeemABinanceGiftCardParams::builder("code_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002328060227","identityNo":"10317392647411060736","token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let expected_response : models::RedeemABinanceGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemABinanceGiftCardResponse");

            let resp = client.redeem_a_binance_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn redeem_a_binance_gift_card_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = RedeemABinanceGiftCardParams::builder("code_example".to_string(),).external_uid("external_uid_example".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"referenceNo":"0033002328060227","identityNo":"10317392647411060736","token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let expected_response : models::RedeemABinanceGiftCardResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemABinanceGiftCardResponse");

            let resp = client.redeem_a_binance_gift_card(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn redeem_a_binance_gift_card_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params = RedeemABinanceGiftCardParams::builder("code_example".to_string())
                .build()
                .unwrap();

            match client.redeem_a_binance_gift_card(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn verify_binance_gift_card_by_gift_card_number_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = VerifyBinanceGiftCardByGiftCardNumberParams::builder("reference_no_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"valid":true,"token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let expected_response : models::VerifyBinanceGiftCardByGiftCardNumberResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::VerifyBinanceGiftCardByGiftCardNumberResponse");

            let resp = client.verify_binance_gift_card_by_gift_card_number(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn verify_binance_gift_card_by_gift_card_number_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: false };

            let params = VerifyBinanceGiftCardByGiftCardNumberParams::builder("reference_no_example".to_string(),).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"valid":true,"token":"BNB","amount":"0.00000001"},"success":true}"#).unwrap();
            let expected_response : models::VerifyBinanceGiftCardByGiftCardNumberResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::VerifyBinanceGiftCardByGiftCardNumberResponse");

            let resp = client.verify_binance_gift_card_by_gift_card_number(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn verify_binance_gift_card_by_gift_card_number_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockMarketDataApiClient { force_error: true };

            let params = VerifyBinanceGiftCardByGiftCardNumberParams::builder(
                "reference_no_example".to_string(),
            )
            .build()
            .unwrap();

            match client
                .verify_binance_gift_card_by_gift_card_number(params)
                .await
            {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }
}
