// File: crates/common_utils/src/pii.rs

//! Personal Identifiable Information protection.

use std::{convert::AsRef, fmt, ops, str::FromStr};

use diesel::{
    backend::Backend,
    deserialize,
    deserialize::FromSql,
    prelude::*,
    serialize::{Output, ToSql},
    sql_types, AsExpression,
};
use error_stack::ResultExt;
use masking::{ExposeInterface, Secret, Strategy, WithType};
#[cfg(feature = "logs")]
use router_env::logger;
use serde::Deserialize;

use crate::{
    crypto::Encryptable,
    errors::{self, ValidationError},
    validation::{validate_email, validate_phone_number},
};

/// A string constant representing a redacted or masked value.
pub const REDACTED: &str = "Redacted";

/// Type alias for serde_json value which has Secret Information
pub type SecretSerdeValue = Secret<serde_json::Value>;

/// Strategy for masking a PhoneNumber
#[derive(Debug)]
pub enum PhoneNumberStrategy {}

/// Phone Number
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(try_from = "String")]
pub struct PhoneNumber(Secret<String, PhoneNumberStrategy>);

impl<T> Strategy<T> for PhoneNumberStrategy
where
    T: AsRef<str> + fmt::Debug,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let val_str: &str = val.as_ref();

        if let Some(val_str) = val_str.get(val_str.len() - 4..) {
            // masks everything but the last 4 digits
            write!(f, "{}{}", "*".repeat(val_str.len() - 4), val_str)
        } else {
            #[cfg(feature = "logs")]
            logger::error!("Invalid phone number: {val_str}");
            WithType::fmt(val, f)
        }
    }
}

impl FromStr for PhoneNumber {
    type Err = error_stack::Report<ValidationError>;
    fn from_str(phone_number: &str) -> Result<Self, Self::Err> {
        validate_phone_number(phone_number)?;
        let secret = Secret::<String, PhoneNumberStrategy>::new(phone_number.to_string());
        Ok(Self(secret))
    }
}

impl TryFrom<String> for PhoneNumber {
    type Error = error_stack::Report<errors::ParsingError>;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        Self::from_str(&value).change_context(errors::ParsingError::PhoneNumberParsingError)
    }
}

impl ops::Deref for PhoneNumber {
    type Target = Secret<String, PhoneNumberStrategy>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl ops::DerefMut for PhoneNumber {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<DB> Queryable<sql_types::Text, DB> for PhoneNumber
where
    DB: Backend,
    Self: FromSql<sql_types::Text, DB>,
{
    type Row = Self;

    fn build(row: Self::Row) -> deserialize::Result<Self> {
        Ok(row)
    }
}

impl<DB> FromSql<sql_types::Text, DB> for PhoneNumber
where
    DB: Backend,
    String: FromSql<sql_types::Text, DB>,
{
    fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
        let val = String::from_sql(bytes)?;
        Ok(Self::from_str(val.as_str())?)
    }
}

impl<DB> ToSql<sql_types::Text, DB> for PhoneNumber
where
    DB: Backend,
    String: ToSql<sql_types::Text, DB>,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result {
        self.0.to_sql(out)
    }
}

/*
/// Phone number
#[derive(Debug)]
pub struct PhoneNumber;

impl<T> Strategy<T> for PhoneNumber
where
    T: AsRef<str>,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let val_str: &str = val.as_ref();

        if val_str.len() < 10 || val_str.len() > 12 {
            return WithType::fmt(val, f);
        }

        write!(
            f,
            "{}{}{}",
            &val_str[..2],
            "*".repeat(val_str.len() - 5),
            &val_str[(val_str.len() - 3)..]
        )
    }
}
*/

/// Strategy for Encryption
#[derive(Debug)]
pub enum EncryptionStrategy {}

impl<T> Strategy<T> for EncryptionStrategy
where
    T: AsRef<[u8]>,
{
    fn fmt(value: &T, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(
            fmt,
            "*** Encrypted data of length {} bytes ***",
            value.as_ref().len()
        )
    }
}

/// Client secret
#[derive(Debug)]
pub enum ClientSecret {}

impl<T> Strategy<T> for ClientSecret
where
    T: AsRef<str>,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let val_str: &str = val.as_ref();

        let client_secret_segments: Vec<&str> = val_str.split('_').collect();

        if client_secret_segments.len() != 4
            || !client_secret_segments.contains(&"pay")
            || !client_secret_segments.contains(&"secret")
        {
            return WithType::fmt(val, f);
        }

        if let Some((client_secret_segments_0, client_secret_segments_1)) = client_secret_segments
            .first()
            .zip(client_secret_segments.get(1))
        {
            write!(
                f,
                "{}_{}_{}",
                client_secret_segments_0,
                client_secret_segments_1,
                "*".repeat(
                    val_str.len()
                        - (client_secret_segments_0.len() + client_secret_segments_1.len() + 2)
                )
            )
        } else {
            #[cfg(feature = "logs")]
            logger::error!("Invalid client secret: {val_str}");
            WithType::fmt(val, f)
        }
    }
}

/// Strategy for masking Email
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum EmailStrategy {}

impl<T> Strategy<T> for EmailStrategy
where
    T: AsRef<str> + fmt::Debug,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let val_str: &str = val.as_ref();
        match val_str.split_once('@') {
            Some((a, b)) => write!(f, "{}@{}", "*".repeat(a.len()), b),
            None => WithType::fmt(val, f),
        }
    }
}
/// Email address
#[derive(
    serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, Default, AsExpression,
)]
#[diesel(sql_type = sql_types::Text)]
#[serde(try_from = "String")]
pub struct Email(Secret<String, EmailStrategy>);

impl From<Encryptable<Secret<String, EmailStrategy>>> for Email {
    fn from(item: Encryptable<Secret<String, EmailStrategy>>) -> Self {
        Self(item.into_inner())
    }
}

impl ExposeInterface<Secret<String, EmailStrategy>> for Email {
    fn expose(self) -> Secret<String, EmailStrategy> {
        self.0
    }
}

impl TryFrom<String> for Email {
    type Error = error_stack::Report<errors::ParsingError>;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        Self::from_str(&value).change_context(errors::ParsingError::EmailParsingError)
    }
}

impl ops::Deref for Email {
    type Target = Secret<String, EmailStrategy>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl ops::DerefMut for Email {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<DB> Queryable<sql_types::Text, DB> for Email
where
    DB: Backend,
    Self: FromSql<sql_types::Text, DB>,
{
    type Row = Self;

    fn build(row: Self::Row) -> deserialize::Result<Self> {
        Ok(row)
    }
}

impl<DB> FromSql<sql_types::Text, DB> for Email
where
    DB: Backend,
    String: FromSql<sql_types::Text, DB>,
{
    fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
        let val = String::from_sql(bytes)?;
        Ok(Self::from_str(val.as_str())?)
    }
}

impl<DB> ToSql<sql_types::Text, DB> for Email
where
    DB: Backend,
    String: ToSql<sql_types::Text, DB>,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result {
        self.0.to_sql(out)
    }
}

impl FromStr for Email {
    type Err = error_stack::Report<ValidationError>;
    fn from_str(email: &str) -> Result<Self, Self::Err> {
        if email.eq(REDACTED) {
            return Ok(Self(Secret::new(email.to_string())));
        }
        match validate_email(email) {
            Ok(_) => {
                let secret = Secret::<String, EmailStrategy>::new(email.to_string());
                Ok(Self(secret))
            }
            Err(_) => Err(ValidationError::InvalidValue {
                message: "Invalid email address format".into(),
            }
            .into()),
        }
    }
}

/// IP address
#[derive(Debug)]
pub enum IpAddress {}

impl<T> Strategy<T> for IpAddress
where
    T: AsRef<str>,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let val_str: &str = val.as_ref();
        let segments: Vec<&str> = val_str.split('.').collect();

        if segments.len() != 4 {
            return WithType::fmt(val, f);
        }

        for seg in segments.iter() {
            if seg.is_empty() || seg.len() > 3 {
                return WithType::fmt(val, f);
            }
        }

        if let Some(segments) = segments.first() {
            write!(f, "{segments}.**.**.**")
        } else {
            #[cfg(feature = "logs")]
            logger::error!("Invalid IP address: {val_str}");
            WithType::fmt(val, f)
        }
    }
}

/// Strategy for masking UPI VPA's
#[derive(Debug)]
pub enum UpiVpaMaskingStrategy {}

impl<T> Strategy<T> for UpiVpaMaskingStrategy
where
    T: AsRef<str> + fmt::Debug,
{
    fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vpa_str: &str = val.as_ref();
        if let Some((user_identifier, bank_or_psp)) = vpa_str.split_once('@') {
            let masked_user_identifier = "*".repeat(user_identifier.len());
            write!(f, "{masked_user_identifier}@{bank_or_psp}")
        } else {
            WithType::fmt(val, f)
        }
    }
}

#[cfg(test)]
mod pii_masking_strategy_tests {
    use std::str::FromStr;

    use masking::{ExposeInterface, Secret};

    use super::{ClientSecret, Email, IpAddress, UpiVpaMaskingStrategy};
    use crate::pii::{EmailStrategy, REDACTED};

    /*
    #[test]
    fn test_valid_phone_number_masking() {
        let secret: Secret<String, PhoneNumber> = Secret::new("9123456789".to_string());
        assert_eq!("99*****299", format!("{}", secret));
    }

    #[test]
    fn test_invalid_phone_number_masking() {
        let secret: Secret<String, PhoneNumber> = Secret::new("99229922".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{}", secret));

        let secret: Secret<String, PhoneNumber> = Secret::new("9922992299229922".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{}", secret));
    }
    */

    #[test]
    fn test_valid_email_masking() {
        let secret: Secret<String, EmailStrategy> = Secret::new("example@test.com".to_string());
        assert_eq!("*******@test.com", format!("{secret:?}"));

        let secret: Secret<String, EmailStrategy> = Secret::new("username@gmail.com".to_string());
        assert_eq!("********@gmail.com", format!("{secret:?}"));
    }

    #[test]
    fn test_invalid_email_masking() {
        let secret: Secret<String, EmailStrategy> = Secret::new("myemailgmail.com".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));

        let secret: Secret<String, EmailStrategy> = Secret::new("myemail$gmail.com".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));
    }

    #[test]
    fn test_valid_newtype_email() {
        let email_check = Email::from_str("example@abc.com");
        assert!(email_check.is_ok());
    }

    #[test]
    fn test_invalid_newtype_email() {
        let email_check = Email::from_str("example@abc@com");
        assert!(email_check.is_err());
    }

    #[test]
    fn test_redacted_email() {
        let email_result = Email::from_str(REDACTED);
        assert!(email_result.is_ok());
        if let Ok(email) = email_result {
            let secret_value = email.0.expose();
            assert_eq!(secret_value.as_str(), REDACTED);
        }
    }

    #[test]
    fn test_valid_ip_addr_masking() {
        let secret: Secret<String, IpAddress> = Secret::new("123.23.1.78".to_string());
        assert_eq!("123.**.**.**", format!("{secret:?}"));
    }

    #[test]
    fn test_invalid_ip_addr_masking() {
        let secret: Secret<String, IpAddress> = Secret::new("123.4.56".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));

        let secret: Secret<String, IpAddress> = Secret::new("123.4567.12.4".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));

        let secret: Secret<String, IpAddress> = Secret::new("123..4.56".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));
    }

    #[test]
    fn test_valid_client_secret_masking() {
        let secret: Secret<String, ClientSecret> =
            Secret::new("pay_uszFB2QGe9MmLY65ojhT_secret_tLjTz9tAQxUVEFqfmOIP".to_string());
        assert_eq!(
            "pay_uszFB2QGe9MmLY65ojhT_***************************",
            format!("{secret:?}")
        );
    }

    #[test]
    fn test_invalid_client_secret_masking() {
        let secret: Secret<String, IpAddress> =
            Secret::new("pay_uszFB2QGe9MmLY65ojhT_secret".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));
    }

    #[test]
    fn test_valid_phone_number_default_masking() {
        let secret: Secret<String> = Secret::new("+40712345678".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));
    }

    #[test]
    fn test_valid_upi_vpa_masking() {
        let secret: Secret<String, UpiVpaMaskingStrategy> = Secret::new("my_name@upi".to_string());
        assert_eq!("*******@upi", format!("{secret:?}"));
    }

    #[test]
    fn test_invalid_upi_vpa_masking() {
        let secret: Secret<String, UpiVpaMaskingStrategy> = Secret::new("my_name_upi".to_string());
        assert_eq!("*** alloc::string::String ***", format!("{secret:?}"));
    }
}


// File: crates/common_utils/src/errors.rs

//! Errors and error specific types for universal use

use serde::Serialize;

use crate::types::MinorUnit;

/// Custom Result
/// A custom datatype that wraps the error variant <E> into a report, allowing
/// error_stack::Report<E> specific extendability
///
/// Effectively, equivalent to `Result<T, error_stack::Report<E>>`
pub type CustomResult<T, E> = error_stack::Result<T, E>;

/// Parsing Errors
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
#[derive(Debug, thiserror::Error)]
pub enum ParsingError {
    ///Failed to parse enum
    #[error("Failed to parse enum: {0}")]
    EnumParseFailure(&'static str),
    ///Failed to parse struct
    #[error("Failed to parse struct: {0}")]
    StructParseFailure(&'static str),
    /// Failed to encode data to given format
    #[error("Failed to serialize to {0} format")]
    EncodeError(&'static str),
    /// Failed to parse data
    #[error("Unknown error while parsing")]
    UnknownError,
    /// Failed to parse datetime
    #[error("Failed to parse datetime")]
    DateTimeParsingError,
    /// Failed to parse email
    #[error("Failed to parse email")]
    EmailParsingError,
    /// Failed to parse phone number
    #[error("Failed to parse phone number")]
    PhoneNumberParsingError,
    /// Failed to parse Float value for converting to decimal points
    #[error("Failed to parse Float value for converting to decimal points")]
    FloatToDecimalConversionFailure,
    /// Failed to parse Decimal value for i64 value conversion
    #[error("Failed to parse Decimal value for i64 value conversion")]
    DecimalToI64ConversionFailure,
    /// Failed to parse string value for f64 value conversion
    #[error("Failed to parse string value for f64 value conversion")]
    StringToFloatConversionFailure,
    /// Failed to parse i64 value for f64 value conversion
    #[error("Failed to parse i64 value for f64 value conversion")]
    I64ToDecimalConversionFailure,
    /// Failed to parse i64 value for String value conversion
    #[error("Failed to parse i64 value for String value conversion")]
    I64ToStringConversionFailure,
    /// Failed to parse String value to Decimal value conversion because `error`
    #[error("Failed to parse String value to Decimal value conversion because {error}")]
    StringToDecimalConversionFailure { error: String },
    /// Failed to convert the given integer because of integer overflow error
    #[error("Integer Overflow error")]
    IntegerOverflow,
    /// Failed to parse url
    #[error("Failed to parse url")]
    UrlParsingError,
}

/// Validation errors.
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
#[derive(Debug, thiserror::Error, Clone, PartialEq)]
pub enum ValidationError {
    /// The provided input is missing a required field.
    #[error("Missing required field: {field_name}")]
    MissingRequiredField { field_name: String },

    /// An incorrect value was provided for the field specified by `field_name`.
    #[error("Incorrect value provided for field: {field_name}")]
    IncorrectValueProvided { field_name: &'static str },

    /// An invalid input was provided.
    #[error("{message}")]
    InvalidValue { message: String },
}

/// Integrity check errors.
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
pub struct IntegrityCheckError {
    /// Field names for which integrity check failed!
    pub field_names: String,
    /// Connector transaction reference id
    pub connector_transaction_id: Option<String>,
}

/// Cryptographic algorithm errors
#[derive(Debug, thiserror::Error)]
pub enum CryptoError {
    /// The cryptographic algorithm was unable to encode the message
    #[error("Failed to encode given message")]
    EncodingFailed,
    /// The cryptographic algorithm was unable to decode the message
    #[error("Failed to decode given message")]
    DecodingFailed,
    /// The cryptographic algorithm was unable to sign the message
    #[error("Failed to sign message")]
    MessageSigningFailed,
    /// The cryptographic algorithm was unable to verify the given signature
    #[error("Failed to verify signature")]
    SignatureVerificationFailed,
    /// The provided key length is invalid for the cryptographic algorithm
    #[error("Invalid key length")]
    InvalidKeyLength,
    /// The provided IV length is invalid for the cryptographic algorithm
    #[error("Invalid IV length")]
    InvalidIvLength,
    /// The provided authentication tag length is invalid for the cryptographic algorithm
    #[error("Invalid authentication tag length")]
    InvalidTagLength,
}

/// Errors for Qr code handling
#[derive(Debug, thiserror::Error)]
pub enum QrCodeError {
    /// Failed to encode data into Qr code
    #[error("Failed to create Qr code")]
    FailedToCreateQrCode,
    /// Failed to parse hex color
    #[error("Invalid hex color code supplied")]
    InvalidHexColor,
}

/// Api Models construction error
#[derive(Debug, Clone, thiserror::Error, PartialEq)]
pub enum PercentageError {
    /// Percentage Value provided was invalid
    #[error("Invalid Percentage value")]
    InvalidPercentageValue,

    /// Error occurred while calculating percentage
    #[error("Failed apply percentage of {percentage} on {amount}")]
    UnableToApplyPercentage {
        /// percentage value
        percentage: f32,
        /// amount value
        amount: MinorUnit,
    },
}

/// Allows [error_stack::Report] to change between error contexts
/// using the dependent [ErrorSwitch] trait to define relations & mappings between traits
pub trait ReportSwitchExt<T, U> {
    /// Switch to the intended report by calling switch
    /// requires error switch to be already implemented on the error type
    fn switch(self) -> Result<T, error_stack::Report<U>>;
}

impl<T, U, V> ReportSwitchExt<T, U> for Result<T, error_stack::Report<V>>
where
    V: ErrorSwitch<U> + error_stack::Context,
    U: error_stack::Context,
{
    #[track_caller]
    fn switch(self) -> Result<T, error_stack::Report<U>> {
        match self {
            Ok(i) => Ok(i),
            Err(er) => {
                let new_c = er.current_context().switch();
                Err(er.change_context(new_c))
            }
        }
    }
}

#[allow(missing_docs)]
#[derive(Debug, thiserror::Error)]
pub enum KeyManagerClientError {
    #[error("Failed to construct header from the given value")]
    FailedtoConstructHeader,
    #[error("Failed to send request to Keymanager")]
    RequestNotSent(String),
    #[error("URL encoding of request failed")]
    UrlEncodingFailed,
    #[error("Failed to build the reqwest client ")]
    ClientConstructionFailed,
    #[error("Failed to send the request to Keymanager")]
    RequestSendFailed,
    #[error("Internal Server Error Received {0:?}")]
    InternalServerError(bytes::Bytes),
    #[error("Bad request received {0:?}")]
    BadRequest(bytes::Bytes),
    #[error("Unexpected Error occurred while calling the KeyManager")]
    Unexpected(bytes::Bytes),
    #[error("Response Decoding failed")]
    ResponseDecodingFailed,
}

#[allow(missing_docs)]
#[derive(Debug, thiserror::Error)]
pub enum KeyManagerError {
    #[error("Failed to add key to the KeyManager")]
    KeyAddFailed,
    #[error("Failed to transfer the key to the KeyManager")]
    KeyTransferFailed,
    #[error("Failed to Encrypt the data in the KeyManager")]
    EncryptionFailed,
    #[error("Failed to Decrypt the data in the KeyManager")]
    DecryptionFailed,
}

/// Allow [error_stack::Report] to convert between error types
/// This auto-implements [ReportSwitchExt] for the corresponding errors
pub trait ErrorSwitch<T> {
    /// Get the next error type that the source error can be escalated into
    /// This does not consume the source error since we need to keep it in context
    fn switch(&self) -> T;
}

/// Allow [error_stack::Report] to convert between error types
/// This serves as an alternative to [ErrorSwitch]
pub trait ErrorSwitchFrom<T> {
    /// Convert to an error type that the source can be escalated into
    /// This does not consume the source error since we need to keep it in context
    fn switch_from(error: &T) -> Self;
}

impl<T, S> ErrorSwitch<T> for S
where
    T: ErrorSwitchFrom<Self>,
{
    fn switch(&self) -> T {
        T::switch_from(self)
    }
}


// File: crates/common_utils/src/keymanager.rs

//! Consists of all the common functions to use the Keymanager.

use core::fmt::Debug;
use std::str::FromStr;

use base64::Engine;
use error_stack::ResultExt;
use http::{HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
use masking::{PeekInterface, StrongSecret};
use once_cell::sync::OnceCell;
use router_env::{instrument, logger, tracing};

use crate::{
    consts::{BASE64_ENGINE, TENANT_HEADER},
    errors,
    types::keymanager::{
        BatchDecryptDataRequest, DataKeyCreateResponse, DecryptDataRequest,
        EncryptionCreateRequest, EncryptionTransferRequest, GetKeymanagerTenant, KeyManagerState,
        TransientBatchDecryptDataRequest, TransientDecryptDataRequest,
    },
};

const CONTENT_TYPE: &str = "Content-Type";
static ENCRYPTION_API_CLIENT: OnceCell<reqwest::Client> = OnceCell::new();
static DEFAULT_ENCRYPTION_VERSION: &str = "v1";
#[cfg(feature = "km_forward_x_request_id")]
const X_REQUEST_ID: &str = "X-Request-Id";

/// Get keymanager client constructed from the url and state
#[instrument(skip_all)]
#[allow(unused_mut)]
fn get_api_encryption_client(
    state: &KeyManagerState,
) -> errors::CustomResult<reqwest::Client, errors::KeyManagerClientError> {
    let get_client = || {
        let mut client = reqwest::Client::builder()
            .redirect(reqwest::redirect::Policy::none())
            .pool_idle_timeout(std::time::Duration::from_secs(
                state.client_idle_timeout.unwrap_or_default(),
            ));

        #[cfg(feature = "keymanager_mtls")]
        {
            let cert = state.cert.clone();
            let ca = state.ca.clone();

            let identity = reqwest::Identity::from_pem(cert.peek().as_ref())
                .change_context(errors::KeyManagerClientError::ClientConstructionFailed)?;
            let ca_cert = reqwest::Certificate::from_pem(ca.peek().as_ref())
                .change_context(errors::KeyManagerClientError::ClientConstructionFailed)?;

            client = client
                .use_rustls_tls()
                .identity(identity)
                .add_root_certificate(ca_cert)
                .https_only(true);
        }

        client
            .build()
            .change_context(errors::KeyManagerClientError::ClientConstructionFailed)
    };

    Ok(ENCRYPTION_API_CLIENT.get_or_try_init(get_client)?.clone())
}

/// Generic function to send the request to keymanager
#[instrument(skip_all)]
pub async fn send_encryption_request<T>(
    state: &KeyManagerState,
    headers: HeaderMap,
    url: String,
    method: Method,
    request_body: T,
) -> errors::CustomResult<reqwest::Response, errors::KeyManagerClientError>
where
    T: ConvertRaw,
{
    let client = get_api_encryption_client(state)?;
    let url = reqwest::Url::parse(&url)
        .change_context(errors::KeyManagerClientError::UrlEncodingFailed)?;

    client
        .request(method, url)
        .json(&ConvertRaw::convert_raw(request_body)?)
        .headers(headers)
        .send()
        .await
        .change_context(errors::KeyManagerClientError::RequestNotSent(
            "Unable to send request to encryption service".to_string(),
        ))
}

/// Generic function to call the Keymanager and parse the response back
#[instrument(skip_all)]
pub async fn call_encryption_service<T, R>(
    state: &KeyManagerState,
    method: Method,
    endpoint: &str,
    request_body: T,
) -> errors::CustomResult<R, errors::KeyManagerClientError>
where
    T: GetKeymanagerTenant + ConvertRaw + Send + Sync + 'static + Debug,
    R: serde::de::DeserializeOwned,
{
    let url = format!("{}/{endpoint}", &state.url);

    logger::info!(key_manager_request=?request_body);
    let mut header = vec![];
    header.push((
        HeaderName::from_str(CONTENT_TYPE)
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        HeaderValue::from_str("application/json")
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
    ));
    #[cfg(feature = "km_forward_x_request_id")]
    if let Some(ref request_id) = state.request_id {
        header.push((
            HeaderName::from_str(X_REQUEST_ID)
                .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
            HeaderValue::from_str(request_id.as_str())
                .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        ))
    }

    //Add Tenant ID
    header.push((
        HeaderName::from_str(TENANT_HEADER)
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        HeaderValue::from_str(request_body.get_tenant_id(state).get_string_repr())
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
    ));

    let response = send_encryption_request(
        state,
        HeaderMap::from_iter(header.into_iter()),
        url,
        method,
        request_body,
    )
    .await
    .map_err(|err| err.change_context(errors::KeyManagerClientError::RequestSendFailed))?;

    logger::info!(key_manager_response=?response);

    match response.status() {
        StatusCode::OK => response
            .json::<R>()
            .await
            .change_context(errors::KeyManagerClientError::ResponseDecodingFailed),
        StatusCode::INTERNAL_SERVER_ERROR => {
            Err(errors::KeyManagerClientError::InternalServerError(
                response
                    .bytes()
                    .await
                    .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
            )
            .into())
        }
        StatusCode::BAD_REQUEST => Err(errors::KeyManagerClientError::BadRequest(
            response
                .bytes()
                .await
                .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
        )
        .into()),
        _ => Err(errors::KeyManagerClientError::Unexpected(
            response
                .bytes()
                .await
                .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
        )
        .into()),
    }
}

/// Trait to convert the raw data to the required format for encryption service request
pub trait ConvertRaw {
    /// Return type of the convert_raw function
    type Output: serde::Serialize;
    /// Function to convert the raw data to the required format for encryption service request
    fn convert_raw(self) -> Result<Self::Output, errors::KeyManagerClientError>;
}

impl<T: serde::Serialize> ConvertRaw for T {
    type Output = T;
    fn convert_raw(self) -> Result<Self::Output, errors::KeyManagerClientError> {
        Ok(self)
    }
}

impl ConvertRaw for TransientDecryptDataRequest {
    type Output = DecryptDataRequest;
    fn convert_raw(self) -> Result<Self::Output, errors::KeyManagerClientError> {
        let data = match String::from_utf8(self.data.peek().clone()) {
            Ok(data) => data,
            Err(_) => {
                let data = BASE64_ENGINE.encode(self.data.peek().clone());
                format!("{DEFAULT_ENCRYPTION_VERSION}:{data}")
            }
        };
        Ok(DecryptDataRequest {
            identifier: self.identifier,
            data: StrongSecret::new(data),
        })
    }
}

impl ConvertRaw for TransientBatchDecryptDataRequest {
    type Output = BatchDecryptDataRequest;
    fn convert_raw(self) -> Result<Self::Output, errors::KeyManagerClientError> {
        let data = self
            .data
            .iter()
            .map(|(k, v)| {
                let value = match String::from_utf8(v.peek().clone()) {
                    Ok(data) => data,
                    Err(_) => {
                        let data = BASE64_ENGINE.encode(v.peek().clone());
                        format!("{DEFAULT_ENCRYPTION_VERSION}:{data}")
                    }
                };
                (k.to_owned(), StrongSecret::new(value))
            })
            .collect();
        Ok(BatchDecryptDataRequest {
            data,
            identifier: self.identifier,
        })
    }
}

/// A function to create the key in keymanager
#[instrument(skip_all)]
pub async fn create_key_in_key_manager(
    state: &KeyManagerState,
    request_body: EncryptionCreateRequest,
) -> errors::CustomResult<DataKeyCreateResponse, errors::KeyManagerError> {
    call_encryption_service(state, Method::POST, "key/create", request_body)
        .await
        .change_context(errors::KeyManagerError::KeyAddFailed)
}

/// A function to transfer the key in keymanager
#[instrument(skip_all)]
pub async fn transfer_key_to_key_manager(
    state: &KeyManagerState,
    request_body: EncryptionTransferRequest,
) -> errors::CustomResult<DataKeyCreateResponse, errors::KeyManagerError> {
    call_encryption_service(state, Method::POST, "key/transfer", request_body)
        .await
        .change_context(errors::KeyManagerError::KeyTransferFailed)
}


// File: crates/common_utils/src/ucs_types.rs

use crate::id_type;

/// Represents a reference ID for the Unified Connector Service (UCS).
///
/// This enum can hold either a payment reference ID or a refund reference ID,
/// allowing for a unified way to handle different types of transaction references
/// when interacting with the UCS.
#[derive(Debug)]
pub enum UcsReferenceId {
    /// A payment reference ID.
    ///
    /// This variant wraps a [`PaymentReferenceId`](id_type::PaymentReferenceId)
    /// and is used to identify a payment transaction within the UCS.
    Payment(id_type::PaymentReferenceId),
    /// A refund reference ID.
    ///
    /// This variant wraps a [`RefundReferenceId`](id_type::RefundReferenceId)
    /// and is used to identify a refund transaction within the UCS.
    Refund(id_type::RefundReferenceId),
}

impl UcsReferenceId {
    /// Returns the string representation of the reference ID.
    ///
    /// This method matches the enum variant and calls the `get_string_repr`
    /// method of the underlying ID type (either `PaymentReferenceId` or `RefundReferenceId`)
    /// to get its string representation.
    ///
    /// # Returns
    ///
    /// A string slice (`&str`) representing the reference ID.
    pub fn get_string_repr(&self) -> &str {
        match self {
            Self::Payment(id) => id.get_string_repr(),
            Self::Refund(id) => id.get_string_repr(),
        }
    }
}


// File: crates/common_utils/src/id_type.rs

//! Common ID types
//! The id type can be used to create specific id types with custom behaviour

mod api_key;
mod authentication;
mod client_secret;
mod customer;
#[cfg(feature = "v2")]
mod global_id;
mod invoice;
mod merchant;
mod merchant_connector_account;
mod organization;
mod payment;
mod payout;
mod profile;
mod profile_acquirer;
mod refunds;
mod relay;
mod routing;
mod subscription;
mod tenant;
mod webhook_endpoint;

use std::{borrow::Cow, fmt::Debug};

use diesel::{
    backend::Backend,
    deserialize::FromSql,
    expression::AsExpression,
    serialize::{Output, ToSql},
    sql_types,
};
pub use payout::PayoutId;
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[cfg(feature = "v2")]
pub use self::global_id::{
    customer::GlobalCustomerId,
    payment::{GlobalAttemptGroupId, GlobalAttemptId, GlobalPaymentId},
    payment_methods::{GlobalPaymentMethodId, GlobalPaymentMethodSessionId},
    refunds::GlobalRefundId,
    token::GlobalTokenId,
    CellId,
};
pub use self::{
    api_key::ApiKeyId,
    authentication::AuthenticationId,
    client_secret::ClientSecretId,
    customer::CustomerId,
    invoice::InvoiceId,
    merchant::MerchantId,
    merchant_connector_account::MerchantConnectorAccountId,
    organization::OrganizationId,
    payment::{PaymentId, PaymentReferenceId},
    profile::ProfileId,
    profile_acquirer::ProfileAcquirerId,
    refunds::RefundReferenceId,
    relay::RelayId,
    routing::RoutingId,
    subscription::SubscriptionId,
    tenant::TenantId,
    webhook_endpoint::WebhookEndpointId,
};
use crate::{fp_utils::when, generate_id_with_default_len};

#[inline]
fn is_valid_id_character(input_char: char) -> bool {
    input_char.is_ascii_alphanumeric() || matches!(input_char, '_' | '-')
}

/// This functions checks for the input string to contain valid characters
/// Returns Some(char) if there are any invalid characters, else None
fn get_invalid_input_character(input_string: Cow<'static, str>) -> Option<char> {
    input_string
        .trim()
        .chars()
        .find(|&char| !is_valid_id_character(char))
}

#[derive(Debug, PartialEq, Hash, Serialize, Clone, Eq)]
/// A type for alphanumeric ids
pub(crate) struct AlphaNumericId(String);

#[derive(Debug, Deserialize, Hash, Serialize, Error, Eq, PartialEq)]
#[error("value `{0}` contains invalid character `{1}`")]
/// The error type for alphanumeric id
pub(crate) struct AlphaNumericIdError(String, char);

impl<'de> Deserialize<'de> for AlphaNumericId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized_string = String::deserialize(deserializer)?;
        Self::from(deserialized_string.into()).map_err(serde::de::Error::custom)
    }
}

impl AlphaNumericId {
    /// Creates a new alphanumeric id from string by applying validation checks
    pub fn from(input_string: Cow<'static, str>) -> Result<Self, AlphaNumericIdError> {
        let invalid_character = get_invalid_input_character(input_string.clone());

        if let Some(invalid_character) = invalid_character {
            Err(AlphaNumericIdError(
                input_string.to_string(),
                invalid_character,
            ))?
        }

        Ok(Self(input_string.to_string()))
    }

    /// Create a new alphanumeric id without any validations
    pub(crate) fn new_unchecked(input_string: String) -> Self {
        Self(input_string)
    }

    /// Generate a new alphanumeric id of default length
    pub(crate) fn new(prefix: &str) -> Self {
        Self(generate_id_with_default_len(prefix))
    }
}

/// A common type of id that can be used for reference ids with length constraint
#[derive(Debug, Clone, Serialize, Hash, PartialEq, Eq, AsExpression)]
#[diesel(sql_type = sql_types::Text)]
pub(crate) struct LengthId<const MAX_LENGTH: u8, const MIN_LENGTH: u8>(AlphaNumericId);

/// Error generated from violation of constraints for MerchantReferenceId
#[derive(Debug, Error, PartialEq, Eq)]
pub(crate) enum LengthIdError {
    #[error("the maximum allowed length for this field is {0}")]
    /// Maximum length of string violated
    MaxLengthViolated(u8),

    #[error("the minimum required length for this field is {0}")]
    /// Minimum length of string violated
    MinLengthViolated(u8),

    #[error("{0}")]
    /// Input contains invalid characters
    AlphanumericIdError(AlphaNumericIdError),
}

impl From<AlphaNumericIdError> for LengthIdError {
    fn from(alphanumeric_id_error: AlphaNumericIdError) -> Self {
        Self::AlphanumericIdError(alphanumeric_id_error)
    }
}

impl<const MAX_LENGTH: u8, const MIN_LENGTH: u8> LengthId<MAX_LENGTH, MIN_LENGTH> {
    /// Generates new [MerchantReferenceId] from the given input string
    pub fn from(input_string: Cow<'static, str>) -> Result<Self, LengthIdError> {
        let trimmed_input_string = input_string.trim().to_string();
        let length_of_input_string = u8::try_from(trimmed_input_string.len())
            .map_err(|_| LengthIdError::MaxLengthViolated(MAX_LENGTH))?;

        when(length_of_input_string > MAX_LENGTH, || {
            Err(LengthIdError::MaxLengthViolated(MAX_LENGTH))
        })?;

        when(length_of_input_string < MIN_LENGTH, || {
            Err(LengthIdError::MinLengthViolated(MIN_LENGTH))
        })?;

        let alphanumeric_id = match AlphaNumericId::from(trimmed_input_string.into()) {
            Ok(valid_alphanumeric_id) => valid_alphanumeric_id,
            Err(error) => Err(LengthIdError::AlphanumericIdError(error))?,
        };

        Ok(Self(alphanumeric_id))
    }

    /// Generate a new MerchantRefId of default length with the given prefix
    pub fn new(prefix: &str) -> Self {
        Self(AlphaNumericId::new(prefix))
    }

    /// Use this function only if you are sure that the length is within the range
    pub(crate) fn new_unchecked(alphanumeric_id: AlphaNumericId) -> Self {
        Self(alphanumeric_id)
    }

    #[cfg(feature = "v2")]
    /// Create a new LengthId from aplhanumeric id
    pub(crate) fn from_alphanumeric_id(
        alphanumeric_id: AlphaNumericId,
    ) -> Result<Self, LengthIdError> {
        let length_of_input_string = alphanumeric_id.0.len();
        let length_of_input_string = u8::try_from(length_of_input_string)
            .map_err(|_| LengthIdError::MaxLengthViolated(MAX_LENGTH))?;

        when(length_of_input_string > MAX_LENGTH, || {
            Err(LengthIdError::MaxLengthViolated(MAX_LENGTH))
        })?;

        when(length_of_input_string < MIN_LENGTH, || {
            Err(LengthIdError::MinLengthViolated(MIN_LENGTH))
        })?;

        Ok(Self(alphanumeric_id))
    }
}

impl<'de, const MAX_LENGTH: u8, const MIN_LENGTH: u8> Deserialize<'de>
    for LengthId<MAX_LENGTH, MIN_LENGTH>
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized_string = String::deserialize(deserializer)?;
        Self::from(deserialized_string.into()).map_err(serde::de::Error::custom)
    }
}

impl<DB, const MAX_LENGTH: u8, const MIN_LENGTH: u8> ToSql<sql_types::Text, DB>
    for LengthId<MAX_LENGTH, MIN_LENGTH>
where
    DB: Backend,
    String: ToSql<sql_types::Text, DB>,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result {
        self.0 .0.to_sql(out)
    }
}

impl<DB, const MAX_LENGTH: u8, const MIN_LENGTH: u8> FromSql<sql_types::Text, DB>
    for LengthId<MAX_LENGTH, MIN_LENGTH>
where
    DB: Backend,
    String: FromSql<sql_types::Text, DB>,
{
    fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
        let string_val = String::from_sql(value)?;
        Ok(Self(AlphaNumericId::new_unchecked(string_val)))
    }
}

/// An interface to generate object identifiers.
pub trait GenerateId {
    /// Generates a random object identifier.
    fn generate() -> Self;
}

#[cfg(test)]
mod alphanumeric_id_tests {
    use super::*;

    const VALID_UNDERSCORE_ID_JSON: &str = r#""cus_abcdefghijklmnopqrstuv""#;
    const EXPECTED_VALID_UNDERSCORE_ID: &str = "cus_abcdefghijklmnopqrstuv";

    const VALID_HYPHEN_ID_JSON: &str = r#""cus-abcdefghijklmnopqrstuv""#;
    const VALID_HYPHEN_ID_STRING: &str = "cus-abcdefghijklmnopqrstuv";

    const INVALID_ID_WITH_SPACES: &str = r#""cus abcdefghijklmnopqrstuv""#;
    const INVALID_ID_WITH_EMOJIS: &str = r#""cus_abc🦀""#;

    #[test]
    fn test_id_deserialize_underscore() {
        let parsed_alphanumeric_id =
            serde_json::from_str::<AlphaNumericId>(VALID_UNDERSCORE_ID_JSON);
        let alphanumeric_id = AlphaNumericId::from(EXPECTED_VALID_UNDERSCORE_ID.into()).unwrap();

        assert_eq!(parsed_alphanumeric_id.unwrap(), alphanumeric_id);
    }

    #[test]
    fn test_id_deserialize_hyphen() {
        let parsed_alphanumeric_id = serde_json::from_str::<AlphaNumericId>(VALID_HYPHEN_ID_JSON);
        let alphanumeric_id = AlphaNumericId::from(VALID_HYPHEN_ID_STRING.into()).unwrap();

        assert_eq!(parsed_alphanumeric_id.unwrap(), alphanumeric_id);
    }

    #[test]
    fn test_id_deserialize_with_spaces() {
        let parsed_alphanumeric_id = serde_json::from_str::<AlphaNumericId>(INVALID_ID_WITH_SPACES);

        assert!(parsed_alphanumeric_id.is_err());
    }

    #[test]
    fn test_id_deserialize_with_emojis() {
        let parsed_alphanumeric_id = serde_json::from_str::<AlphaNumericId>(INVALID_ID_WITH_EMOJIS);

        assert!(parsed_alphanumeric_id.is_err());
    }
}

#[cfg(test)]
mod merchant_reference_id_tests {
    use super::*;

    const VALID_REF_ID_JSON: &str = r#""cus_abcdefghijklmnopqrstuv""#;
    const MAX_LENGTH: u8 = 36;
    const MIN_LENGTH: u8 = 6;

    const INVALID_REF_ID_JSON: &str = r#""cus abcdefghijklmnopqrstuv""#;
    const INVALID_REF_ID_LENGTH: &str = r#""cus_abcdefghijklmnopqrstuvwxyzabcdefghij""#;

    #[test]
    fn test_valid_reference_id() {
        let parsed_merchant_reference_id =
            serde_json::from_str::<LengthId<MAX_LENGTH, MIN_LENGTH>>(VALID_REF_ID_JSON);

        dbg!(&parsed_merchant_reference_id);

        assert!(parsed_merchant_reference_id.is_ok());
    }

    #[test]
    fn test_invalid_ref_id() {
        let parsed_merchant_reference_id =
            serde_json::from_str::<LengthId<MAX_LENGTH, MIN_LENGTH>>(INVALID_REF_ID_JSON);

        assert!(parsed_merchant_reference_id.is_err());
    }

    #[test]
    fn test_invalid_ref_id_error_message() {
        let parsed_merchant_reference_id =
            serde_json::from_str::<LengthId<MAX_LENGTH, MIN_LENGTH>>(INVALID_REF_ID_JSON);

        let expected_error_message =
            r#"value `cus abcdefghijklmnopqrstuv` contains invalid character ` `"#.to_string();

        let error_message = parsed_merchant_reference_id
            .err()
            .map(|error| error.to_string());

        assert_eq!(error_message, Some(expected_error_message));
    }

    #[test]
    fn test_invalid_ref_id_length() {
        let parsed_merchant_reference_id =
            serde_json::from_str::<LengthId<MAX_LENGTH, MIN_LENGTH>>(INVALID_REF_ID_LENGTH);

        dbg!(&parsed_merchant_reference_id);

        let expected_error_message =
            format!("the maximum allowed length for this field is {MAX_LENGTH}");

        assert!(parsed_merchant_reference_id
            .is_err_and(|error_string| error_string.to_string().eq(&expected_error_message)));
    }

    #[test]
    fn test_invalid_ref_id_length_error_type() {
        let parsed_merchant_reference_id =
            LengthId::<MAX_LENGTH, MIN_LENGTH>::from(INVALID_REF_ID_LENGTH.into());

        dbg!(&parsed_merchant_reference_id);

        assert!(
            parsed_merchant_reference_id.is_err_and(|error_type| matches!(
                error_type,
                LengthIdError::MaxLengthViolated(MAX_LENGTH)
            ))
        );
    }
}


// File: crates/common_utils/src/macros.rs

//! Utility macros

#[allow(missing_docs)]
#[macro_export]
macro_rules! newtype_impl {
    ($is_pub:vis, $name:ident, $ty_path:path) => {
        impl core::ops::Deref for $name {
            type Target = $ty_path;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl core::ops::DerefMut for $name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }

        impl From<$ty_path> for $name {
            fn from(ty: $ty_path) -> Self {
                Self(ty)
            }
        }

        impl $name {
            pub fn into_inner(self) -> $ty_path {
                self.0
            }
        }
    };
}

#[allow(missing_docs)]
#[macro_export]
macro_rules! newtype {
    ($is_pub:vis $name:ident = $ty_path:path) => {
        $is_pub struct $name(pub $ty_path);

        $crate::newtype_impl!($is_pub, $name, $ty_path);
    };

    ($is_pub:vis $name:ident = $ty_path:path, derives = ($($trt:path),*)) => {
        #[derive($($trt),*)]
        $is_pub struct $name(pub $ty_path);

        $crate::newtype_impl!($is_pub, $name, $ty_path);
    };
}

/// Use this to ensure that the corresponding
/// openapi route has been implemented in the openapi crate
#[macro_export]
macro_rules! openapi_route {
    ($route_name: ident) => {{
        #[cfg(feature = "openapi")]
        use openapi::routes::$route_name as _;

        $route_name
    }};
}

#[allow(missing_docs)]
#[macro_export]
macro_rules! fallback_reverse_lookup_not_found {
    ($a:expr,$b:expr) => {
        match $a {
            Ok(res) => res,
            Err(err) => {
                router_env::logger::error!(reverse_lookup_fallback = ?err);
                match err.current_context() {
                    errors::StorageError::ValueNotFound(_) => return $b,
                    errors::StorageError::DatabaseError(data_err) => {
                        match data_err.current_context() {
                            diesel_models::errors::DatabaseError::NotFound => return $b,
                            _ => return Err(err)
                        }
                    }
                    _=> return Err(err)
                }
            }
        };
    };
}

/// Collects names of all optional fields that are `None`.
/// This is typically useful for constructing error messages including a list of all missing fields.
#[macro_export]
macro_rules! collect_missing_value_keys {
    [$(($key:literal, $option:expr)),+] => {
        {
            let mut keys: Vec<&'static str> = Vec::new();
            $(
                if $option.is_none() {
                    keys.push($key);
                }
            )*
            keys
        }
    };
}

/// Implements the `ToSql` and `FromSql` traits on a type to allow it to be serialized/deserialized
/// to/from JSON data in the database.
#[macro_export]
macro_rules! impl_to_sql_from_sql_json {
    ($type:ty, $diesel_type:ty) => {
        #[allow(unused_qualifications)]
        impl diesel::serialize::ToSql<$diesel_type, diesel::pg::Pg> for $type {
            fn to_sql<'b>(
                &'b self,
                out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
            ) -> diesel::serialize::Result {
                let value = serde_json::to_value(self)?;

                // the function `reborrow` only works in case of `Pg` backend. But, in case of other backends
                // please refer to the diesel migration blog:
                // https://github.com/Diesel-rs/Diesel/blob/master/guide_drafts/migration_guide.md#changed-tosql-implementations
                <serde_json::Value as diesel::serialize::ToSql<
                                                                $diesel_type,
                                                                diesel::pg::Pg,
                                                            >>::to_sql(&value, &mut out.reborrow())
            }
        }

        #[allow(unused_qualifications)]
        impl diesel::deserialize::FromSql<$diesel_type, diesel::pg::Pg> for $type {
            fn from_sql(
                bytes: <diesel::pg::Pg as diesel::backend::Backend>::RawValue<'_>,
            ) -> diesel::deserialize::Result<Self> {
                let value = <serde_json::Value as diesel::deserialize::FromSql<
                    $diesel_type,
                    diesel::pg::Pg,
                >>::from_sql(bytes)?;
                Ok(serde_json::from_value(value)?)
            }
        }
    };
    ($type: ty) => {
        $crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::Json);
        $crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::Jsonb);
    };
}

mod id_type {
    /// Defines an ID type.
    #[macro_export]
    macro_rules! id_type {
        ($type:ident, $doc:literal, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
            #[doc = $doc]
            #[derive(
                Clone,
                Hash,
                PartialEq,
                Eq,
                serde::Serialize,
                serde::Deserialize,
                diesel::expression::AsExpression,
                utoipa::ToSchema,
            )]
            #[diesel(sql_type = $diesel_type)]
            #[schema(value_type = String)]
            pub struct $type($crate::id_type::LengthId<$max_length, $min_length>);
        };
        ($type:ident, $doc:literal) => {
            $crate::id_type!(
                $type,
                $doc,
                diesel::sql_types::Text,
                { $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
                { $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
            );
        };
    }

    /// Defines a Global Id type
    #[cfg(feature = "v2")]
    #[macro_export]
    macro_rules! global_id_type {
        ($type:ident, $doc:literal) => {
            #[doc = $doc]
            #[derive(
                Debug,
                Clone,
                Hash,
                PartialEq,
                Eq,
                serde::Serialize,
                serde::Deserialize,
                diesel::expression::AsExpression,
            )]
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub struct $type($crate::id_type::global_id::GlobalId);
        };
    }

    /// Implements common methods on the specified ID type.
    #[macro_export]
    macro_rules! impl_id_type_methods {
        ($type:ty, $field_name:literal) => {
            impl $type {
                /// Get the string representation of the ID type.
                pub fn get_string_repr(&self) -> &str {
                    &self.0 .0 .0
                }
            }
        };
    }

    /// Implements the `Debug` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_debug_id_type {
        ($type:ty) => {
            impl core::fmt::Debug for $type {
                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                    f.debug_tuple(stringify!($type))
                        .field(&self.0 .0 .0)
                        .finish()
                }
            }
        };
    }

    /// Implements the `TryFrom<Cow<'static, str>>` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_try_from_cow_str_id_type {
        ($type:ty, $field_name:literal) => {
            impl TryFrom<std::borrow::Cow<'static, str>> for $type {
                type Error = error_stack::Report<$crate::errors::ValidationError>;

                fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
                    use error_stack::ResultExt;

                    let merchant_ref_id = $crate::id_type::LengthId::from(value).change_context(
                        $crate::errors::ValidationError::IncorrectValueProvided {
                            field_name: $field_name,
                        },
                    )?;

                    Ok(Self(merchant_ref_id))
                }
            }
        };
    }

    /// Implements the `Default` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_default_id_type {
        ($type:ty, $prefix:literal) => {
            impl Default for $type {
                fn default() -> Self {
                    Self($crate::generate_ref_id_with_default_length($prefix))
                }
            }
        };
    }

    /// Implements the `GenerateId` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_generate_id_id_type {
        ($type:ty, $prefix:literal) => {
            impl $crate::id_type::GenerateId for $type {
                fn generate() -> Self {
                    Self($crate::generate_ref_id_with_default_length($prefix))
                }
            }
        };
    }

    /// Implements the `SerializableSecret` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_serializable_secret_id_type {
        ($type:ty) => {
            impl masking::SerializableSecret for $type {}
        };
    }

    /// Implements the `ToSql` and `FromSql` traits on the specified ID type.
    #[macro_export]
    macro_rules! impl_to_sql_from_sql_id_type {
        ($type:ty, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
            impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::LengthId<$max_length, $min_length>:
                    diesel::serialize::ToSql<$diesel_type, DB>,
            {
                fn to_sql<'b>(
                    &'b self,
                    out: &mut diesel::serialize::Output<'b, '_, DB>,
                ) -> diesel::serialize::Result {
                    self.0.to_sql(out)
                }
            }

            impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::LengthId<$max_length, $min_length>:
                    diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
                    $crate::id_type::LengthId::<$max_length, $min_length>::from_sql(value).map(Self)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_to_sql_from_sql_id_type!(
                $type,
                diesel::sql_types::Text,
                { $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
                { $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
            );
        };
    }

    #[cfg(feature = "v2")]
    /// Implements the `ToSql` and `FromSql` traits on the specified Global ID type.
    #[macro_export]
    macro_rules! impl_to_sql_from_sql_global_id_type {
        ($type:ty, $diesel_type:ty) => {
            impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::global_id::GlobalId: diesel::serialize::ToSql<$diesel_type, DB>,
            {
                fn to_sql<'b>(
                    &'b self,
                    out: &mut diesel::serialize::Output<'b, '_, DB>,
                ) -> diesel::serialize::Result {
                    self.0.to_sql(out)
                }
            }

            impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::global_id::GlobalId:
                    diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
                    $crate::id_type::global_id::GlobalId::from_sql(value).map(Self)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_to_sql_from_sql_global_id_type!($type, diesel::sql_types::Text);
        };
    }

    /// Implements the `Queryable` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_queryable_id_type {
        ($type:ty, $diesel_type:ty) => {
            impl<DB> diesel::Queryable<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                Self: diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                type Row = Self;

                fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
                    Ok(row)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_queryable_id_type!($type, diesel::sql_types::Text);
        };
    }
}

/// Create new generic list wrapper
#[macro_export]
macro_rules! create_list_wrapper {
    (
        $wrapper_name:ident,
        $type_name: ty,
        impl_functions: {
            $($function_def: tt)*
        }
    ) => {
        #[derive(Clone, Debug)]
        pub struct $wrapper_name(Vec<$type_name>);
        impl $wrapper_name {
            pub fn new(list: Vec<$type_name>) -> Self {
                Self(list)
            }
            pub fn with_capacity(size: usize) -> Self {
                Self(Vec::with_capacity(size))
            }
            $($function_def)*
        }
        impl std::ops::Deref for $wrapper_name {
            type Target = Vec<$type_name>;
            fn deref(&self) -> &<Self as std::ops::Deref>::Target {
                &self.0
            }
        }
        impl std::ops::DerefMut for $wrapper_name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }
        impl IntoIterator for $wrapper_name {
            type Item = $type_name;
            type IntoIter = std::vec::IntoIter<$type_name>;
            fn into_iter(self) -> Self::IntoIter {
                self.0.into_iter()
            }
        }

        impl<'a> IntoIterator for &'a $wrapper_name {
            type Item = &'a $type_name;
            type IntoIter = std::slice::Iter<'a, $type_name>;
            fn into_iter(self) -> Self::IntoIter {
                self.0.iter()
            }
        }

        impl FromIterator<$type_name> for $wrapper_name {
            fn from_iter<T: IntoIterator<Item = $type_name>>(iter: T) -> Self {
                Self(iter.into_iter().collect())
            }
        }
    };
}

/// Get the type name for a type
#[macro_export]
macro_rules! type_name {
    ($type:ty) => {
        std::any::type_name::<$type>()
            .rsplit("::")
            .nth(1)
            .unwrap_or_default();
    };
}

/// **Note** Creates an enum wrapper that implements `FromStr`, `Display`, `Serialize`, and `Deserialize`
/// based on a specific string representation format: `"VariantName<delimiter>FieldValue"`.
/// It handles parsing errors by returning a dedicated `Invalid` variant.
/// *Note*: The macro adds `Invalid,` automatically.
///
/// # Use Case
///
/// This macro is designed for scenarios where you need an enum, with each variant
/// holding a single piece of associated data, to be easily convertible to and from
/// a simple string format. This is useful for cases where enum is serialized to key value pairs
///
/// It avoids more complex serialization structures (like JSON objects `{"VariantName": value}`)
/// in favor of a plain string representation.
///
/// # Input Enum Format and Constraints
///
/// To use this macro, the enum definition must adhere to the following structure:
///
/// 1.  **Public Enum:** The enum must be declared as `pub enum EnumName { ... }`.
/// 2.  **Struct Variants Only:** All variants must be struct variants (using `{}`).
/// 3.  **Exactly One Field:** Each struct variant must contain *exactly one* named field.
///     * **Valid:** `VariantA { value: i32 }`
///     * **Invalid:** `VariantA(i32)` (tuple variant)
///     * **Invalid:** `VariantA` or `VariantA {}` (no field)
///     * **Invalid:** `VariantA { value: i32, other: bool }` (multiple fields)
/// 4.  **Tag Delimiter:** The macro invocation must specify a `tag_delimiter` literal,
///     which is the character used to separate the variant name from the field data in
///     the string representation (e.g., `tag_delimiter = ":",`).
/// 5.  **Field Type Requirements:** The type of the single field in each variant (`$field_ty`)
///     must implement:
///     * `core::str::FromStr`: To parse the field's data from the string part.
///       The `Err` type should ideally be convertible to a meaningful error, though the
///       macro currently uses a generic error message upon failure.
///     * `core::fmt::Display`: To convert the field's data into the string part.
///     * `serde::Serialize` and `serde::Deserialize<'de>`: Although the macro implements
///       custom `Serialize`/`Deserialize` for the *enum* using the string format, the field
///       type itself must satisfy these bounds if required elsewhere or by generic contexts.
///       The macro's implementations rely solely on `Display` and `FromStr` for the conversion.
/// 6.  **Error Type:** This macro uses `core::convert::Infallible` as it never fails but gives
///     `Self::Invalid` variant.
///
/// # Serialization and Deserialization (`serde`)
///
/// When `serde` features are enabled and the necessary traits are derived or implemented,
/// this macro implements `Serialize` and `Deserialize` for the enum:
///
/// **Serialization:** An enum value like `MyEnum::VariantA { value: 123 }` (with `tag_delimiter = ":",`)
///     will be serialized into the string `"VariantA:123"`. If serializing to JSON, this results
///     in a JSON string: `"\"VariantA:123\""`.
/// **Deserialization:** The macro expects a string matching the format `"VariantName<delimiter>FieldValue"`.
///     It uses the enum's `FromStr` implementation internally. When deserializing from JSON, it
///     expects a JSON string containing the correctly formatted value (e.g., `"\"VariantA:123\""`).
///
/// # `Display` and `FromStr`
///
/// **`Display`:** Formats valid variants to `"VariantName<delimiter>FieldValue"` and catch-all cases to `"Invalid"`.
/// **`FromStr`:** Parses `"VariantName<delimiter>FieldValue"` to the variant, or returns `Self::Invalid`
///   if the input string is malformed or `"Invalid"`.
///
/// # Example
///
/// ```rust
/// use std::str::FromStr;
///
/// crate::impl_enum_str!(
///     tag_delimiter = ":",
///     #[derive(Debug, PartialEq, Clone)] // Add other derives as needed
///     pub enum Setting {
///         Timeout { duration_ms: u32 },
///         Username { name: String },
///     }
/// );
/// // Note: The macro adds `Invalid,` automatically.
///
/// fn main() {
///     // Display
///     let setting1 = Setting::Timeout { duration_ms: 5000 };
///     assert_eq!(setting1.to_string(), "Timeout:5000");
///     assert_eq!(Setting::Invalid.to_string(), "Invalid");
///
///     // FromStr (returns Self, not Result)
///     let parsed_setting: Setting = "Username:admin".parse().expect("Valid parse"); // parse() itself doesn't panic
///     assert_eq!(parsed_setting, Setting::Username { name: "admin".to_string() });
///
///     let invalid_format: Setting = "Timeout".parse().expect("Parse always returns Self");
///     assert_eq!(invalid_format, Setting::Invalid); // Malformed input yields Invalid
///
///     let bad_data: Setting = "Timeout:fast".parse().expect("Parse always returns Self");
///     assert_eq!(bad_data, Setting::Invalid); // Bad field data yields Invalid
///
///     let unknown_tag: Setting = "Unknown:abc".parse().expect("Parse always returns Self");
///     assert_eq!(unknown_tag, Setting::Invalid); // Unknown tag yields Invalid
///
///     let explicit_invalid: Setting = "Invalid".parse().expect("Parse always returns Self");
///     assert_eq!(explicit_invalid, Setting::Invalid); // "Invalid" string yields Invalid
///
///     // Serde (requires derive Serialize/Deserialize on Setting)
///     // let json_output = serde_json::to_string(&setting1).unwrap();
///     // assert_eq!(json_output, "\"Timeout:5000\"");
///     // let invalid_json_output = serde_json::to_string(&Setting::Invalid).unwrap();
///     // assert_eq!(invalid_json_output, "\"Invalid\"");
///
///     // let deserialized: Setting = serde_json::from_str("\"Username:guest\"").unwrap();
///     // assert_eq!(deserialized, Setting::Username { name: "guest".to_string() });
///     // let deserialized_invalid: Setting = serde_json::from_str("\"Invalid\"").unwrap();
///     // assert_eq!(deserialized_invalid, Setting::Invalid);
///     // let deserialized_malformed: Setting = serde_json::from_str("\"TimeoutFast\"").unwrap();
///     // assert_eq!(deserialized_malformed, Setting::Invalid); // Malformed -> Invalid
/// }
///
/// # // Mock macro definition for doctest purposes
/// # #[macro_export] macro_rules! impl_enum_str { ($($tt:tt)*) => { $($tt)* } }
/// ```
#[macro_export]
macro_rules! impl_enum_str {
    (
        tag_delimiter = $tag_delim:literal,
        $(#[$enum_attr:meta])*
        pub enum $enum_name:ident {
            $(
                $(#[$variant_attr:meta])*
                $variant:ident {
                    $(#[$field_attr:meta])*
                    $field:ident : $field_ty:ty $(,)?
                }
            ),* $(,)?
        }
    ) => {
        $(#[$enum_attr])*
        pub enum $enum_name {
            $(
                $(#[$variant_attr])*
                $variant {
                    $(#[$field_attr])*
                    $field : $field_ty
                },
            )*
            /// Represents a parsing failure.
            Invalid, // Automatically add the Invalid variant
        }

        // Implement FromStr - now returns Self, not Result
        impl core::str::FromStr for $enum_name {
            // No associated error type needed
            type Err = core::convert::Infallible; // FromStr requires an Err type, use Infallible

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                // Check for explicit "Invalid" string first
                if s == "Invalid" {
                    #[cfg(feature = "logs")]
                    router_env::logger::warn!(
                        "Failed to parse {} enum from 'Invalid': explicit Invalid variant encountered",
                        stringify!($enum_name)
                    );
                    return Ok(Self::Invalid);
                }

                let Some((tag, associated_data)) = s.split_once($tag_delim) else {
                    // Missing delimiter -> Invalid
                    #[cfg(feature = "logs")]
                    router_env::logger::warn!(
                        "Failed to parse {} enum from '{}': missing delimiter",
                        stringify!($enum_name),
                        s
                    );
                    return Ok(Self::Invalid);
                };

                let result = match tag {
                    $(
                        stringify!($variant) => {
                            // Try to parse the field data
                            match associated_data.parse::<$field_ty>() {
                                Ok(parsed_field) => {
                                    // Success -> construct the variant
                                     Self::$variant { $field: parsed_field }
                                },
                                Err(_) => {
                                     // Field parse failure -> Invalid
                                     #[cfg(feature = "logs")]
                                     router_env::logger::warn!(
                                         "Failed to parse {} enum from '{}': field parse failure for variant '{}'",
                                         stringify!($enum_name),
                                         s,
                                         stringify!($variant)
                                     );
                                     Self::Invalid
                                }
                            }
                        }
                    ),*
                    // Unknown tag -> Invalid
                    _ => {
                        #[cfg(feature = "logs")]
                        router_env::logger::warn!(
                            "Failed to parse {} enum from '{}': unknown variant tag '{}'",
                            stringify!($enum_name),
                            s,
                            tag
                        );
                        Self::Invalid
                    },
                };
                Ok(result) // Always Ok because failure modes return Self::Invalid
            }
        }

        // Implement Serialize
        impl ::serde::Serialize for $enum_name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: ::serde::Serializer,
            {
                match self {
                    $(
                        Self::$variant { $field } => {
                            let s = format!("{}{}{}", stringify!($variant), $tag_delim, $field);
                            serializer.serialize_str(&s)
                        }
                    )*
                    // Handle Invalid variant
                    Self::Invalid => serializer.serialize_str("Invalid"),
                }
            }
        }

        // Implement Deserialize
        impl<'de> ::serde::Deserialize<'de> for $enum_name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: ::serde::Deserializer<'de>,
            {
                struct EnumVisitor;

                impl<'de> ::serde::de::Visitor<'de> for EnumVisitor {
                    type Value = $enum_name;

                    fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                        formatter.write_str(concat!("a string like VariantName", $tag_delim, "field_data or 'Invalid'"))
                    }

                    // Leverage the FromStr implementation which now returns Self::Invalid on failure
                    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
                    where
                        E: ::serde::de::Error,
                    {
                        // parse() now returns Result<Self, Infallible>
                        // We unwrap() the Ok because it's infallible.
                       Ok(value.parse::<$enum_name>().unwrap())
                    }

                     fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
                    where
                        E: ::serde::de::Error,
                    {
                        Ok(value.parse::<$enum_name>().unwrap())
                    }
                }

                deserializer.deserialize_str(EnumVisitor)
            }
        }

        // Implement Display
        impl core::fmt::Display for $enum_name {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                match self {
                    $(
                        Self::$variant { $field } => {
                            write!(f, "{}{}{}", stringify!($variant), $tag_delim, $field)
                        }
                    )*
                     // Handle Invalid variant
                    Self::Invalid => write!(f, "Invalid"),
                }
            }
        }

        // Implement HasInvalidVariant trait
        impl $crate::types::HasInvalidVariant for $enum_name {
            fn is_invalid(&self) -> bool {
                matches!(self, Self::Invalid)
            }
        }
    };
}

// --- Tests ---
#[cfg(test)]
mod tests {
    use serde_json::{json, Value as JsonValue};

    use crate::impl_enum_str;

    impl_enum_str!(
        tag_delimiter = ":",
        #[derive(Debug, PartialEq, Clone)]
        pub enum TestEnum {
            VariantA { value: i32 },
            VariantB { text: String },
            VariantC { id: u64 },
            VariantJson { data: JsonValue },
        } // Note: Invalid variant is added automatically by the macro
    );

    #[test]
    fn test_enum_from_str_ok() {
        // Success cases just parse directly
        let parsed_a: TestEnum = "VariantA:42".parse().unwrap(); // Unwrapping Infallible is fine
        assert_eq!(parsed_a, TestEnum::VariantA { value: 42 });

        let parsed_b: TestEnum = "VariantB:hello world".parse().unwrap();
        assert_eq!(
            parsed_b,
            TestEnum::VariantB {
                text: "hello world".to_string()
            }
        );

        let parsed_c: TestEnum = "VariantC:123456789012345".parse().unwrap();
        assert_eq!(
            parsed_c,
            TestEnum::VariantC {
                id: 123456789012345
            }
        );

        let parsed_json: TestEnum = r#"VariantJson:{"ok":true}"#.parse().unwrap();
        assert_eq!(
            parsed_json,
            TestEnum::VariantJson {
                data: json!({"ok": true})
            }
        );
    }

    #[test]
    fn test_enum_from_str_failures_yield_invalid() {
        // Missing delimiter
        let parsed: TestEnum = "VariantA".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Unknown tag
        let parsed: TestEnum = "UnknownVariant:123".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Bad field data for i32
        let parsed: TestEnum = "VariantA:not_a_number".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Bad field data for JsonValue
        let parsed: TestEnum = r#"VariantJson:{"bad_json"#.parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Empty field data for non-string (e.g., i32)
        let parsed: TestEnum = "VariantA:".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Empty field data for string IS valid for String type
        let parsed_str: TestEnum = "VariantB:".parse().unwrap();
        assert_eq!(
            parsed_str,
            TestEnum::VariantB {
                text: "".to_string()
            }
        );

        // Parsing the literal "Invalid" string
        let parsed_invalid_str: TestEnum = "Invalid".parse().unwrap();
        assert_eq!(parsed_invalid_str, TestEnum::Invalid);
    }

    #[test]
    fn test_enum_display_and_serialize() {
        // Display valid
        let value_a = TestEnum::VariantA { value: 99 };
        assert_eq!(value_a.to_string(), "VariantA:99");
        // Serialize valid
        let json_a = serde_json::to_string(&value_a).expect("Serialize A failed");
        assert_eq!(json_a, "\"VariantA:99\""); // Serializes to JSON string

        // Display Invalid
        let value_invalid = TestEnum::Invalid;
        assert_eq!(value_invalid.to_string(), "Invalid");
        // Serialize Invalid
        let json_invalid = serde_json::to_string(&value_invalid).expect("Serialize Invalid failed");
        assert_eq!(json_invalid, "\"Invalid\""); // Serializes to JSON string "Invalid"
    }

    #[test]
    fn test_enum_deserialize() {
        // Deserialize valid
        let input_a = "\"VariantA:123\"";
        let deserialized_a: TestEnum = serde_json::from_str(input_a).expect("Deserialize A failed");
        assert_eq!(deserialized_a, TestEnum::VariantA { value: 123 });

        // Deserialize explicit "Invalid"
        let input_invalid = "\"Invalid\"";
        let deserialized_invalid: TestEnum =
            serde_json::from_str(input_invalid).expect("Deserialize Invalid failed");
        assert_eq!(deserialized_invalid, TestEnum::Invalid);

        // Deserialize malformed string (according to macro rules) -> Invalid
        let input_malformed = "\"VariantA_no_delimiter\"";
        let deserialized_malformed: TestEnum =
            serde_json::from_str(input_malformed).expect("Deserialize malformed should succeed");
        assert_eq!(deserialized_malformed, TestEnum::Invalid);

        // Deserialize string with bad field data -> Invalid
        let input_bad_data = "\"VariantA:not_a_number\"";
        let deserialized_bad_data: TestEnum =
            serde_json::from_str(input_bad_data).expect("Deserialize bad data should succeed");
        assert_eq!(deserialized_bad_data, TestEnum::Invalid);
    }
}


// File: crates/common_utils/src/payout_method_utils.rs

//! This module has common utilities for payout method data in HyperSwitch

use diesel::{sql_types::Jsonb, AsExpression, FromSqlRow};
use masking::Secret;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::new_type::{
    MaskedBankAccount, MaskedBic, MaskedEmail, MaskedIban, MaskedPhoneNumber, MaskedPspToken,
    MaskedRoutingNumber, MaskedSortCode,
};

/// Masked payout method details for storing in db
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub enum AdditionalPayoutMethodData {
    /// Additional data for card payout method
    Card(Box<CardAdditionalData>),
    /// Additional data for bank payout method
    Bank(Box<BankAdditionalData>),
    /// Additional data for wallet payout method
    Wallet(Box<WalletAdditionalData>),
    /// Additional data for Bank Redirect payout method
    BankRedirect(Box<BankRedirectAdditionalData>),
    /// Additional data for Passthrough payout method
    Passthrough(Box<PassthroughAddtionalData>),
}

crate::impl_to_sql_from_sql_json!(AdditionalPayoutMethodData);

/// Masked payout method details for card payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Serialize, Deserialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct CardAdditionalData {
    /// Issuer of the card
    pub card_issuer: Option<String>,

    /// Card network of the card
    #[schema(value_type = Option<CardNetwork>)]
    pub card_network: Option<common_enums::CardNetwork>,

    /// Card type, can be either `credit` or `debit`
    pub card_type: Option<String>,

    /// Card issuing country
    pub card_issuing_country: Option<String>,

    /// Code for Card issuing bank
    pub bank_code: Option<String>,

    /// Last 4 digits of the card number
    pub last4: Option<String>,

    /// The ISIN of the card
    pub card_isin: Option<String>,

    /// Extended bin of card, contains the first 8 digits of card number
    pub card_extended_bin: Option<String>,

    /// Card expiry month
    #[schema(value_type = String, example = "01")]
    pub card_exp_month: Option<Secret<String>>,

    /// Card expiry year
    #[schema(value_type = String, example = "2026")]
    pub card_exp_year: Option<Secret<String>>,

    /// Card holder name
    #[schema(value_type = String, example = "John Doe")]
    pub card_holder_name: Option<Secret<String>>,
}

/// Masked payout method details for bank payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
#[serde(untagged)]
pub enum BankAdditionalData {
    /// Additional data for ach bank transfer payout method
    Ach(Box<AchBankTransferAdditionalData>),
    /// Additional data for bacs bank transfer payout method
    Bacs(Box<BacsBankTransferAdditionalData>),
    /// Additional data for sepa bank transfer payout method
    Sepa(Box<SepaBankTransferAdditionalData>),
    /// Additional data for pix bank transfer payout method
    Pix(Box<PixBankTransferAdditionalData>),
}

/// Masked payout method details for ach bank transfer payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct AchBankTransferAdditionalData {
    /// Partially masked account number for ach bank debit payment
    #[schema(value_type = String, example = "0001****3456")]
    pub bank_account_number: MaskedBankAccount,

    /// Partially masked routing number for ach bank debit payment
    #[schema(value_type = String, example = "110***000")]
    pub bank_routing_number: MaskedRoutingNumber,

    /// Name of the bank
    #[schema(value_type = Option<BankNames>, example = "Deutsche Bank")]
    pub bank_name: Option<String>,

    /// Bank country code
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub bank_country_code: Option<common_enums::CountryAlpha2>,

    /// Bank city
    #[schema(value_type = Option<String>, example = "California")]
    pub bank_city: Option<String>,
}

/// Masked payout method details for bacs bank transfer payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct BacsBankTransferAdditionalData {
    /// Partially masked sort code for Bacs payment method
    #[schema(value_type = String, example = "108800")]
    pub bank_sort_code: MaskedSortCode,

    /// Bank account's owner name
    #[schema(value_type = String, example = "0001****3456")]
    pub bank_account_number: MaskedBankAccount,

    /// Bank name
    #[schema(value_type = Option<String>, example = "Deutsche Bank")]
    pub bank_name: Option<String>,

    /// Bank country code
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub bank_country_code: Option<common_enums::CountryAlpha2>,

    /// Bank city
    #[schema(value_type = Option<String>, example = "California")]
    pub bank_city: Option<String>,
}

/// Masked payout method details for sepa bank transfer payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct SepaBankTransferAdditionalData {
    /// Partially masked international bank account number (iban) for SEPA
    #[schema(value_type = String, example = "DE8937******013000")]
    pub iban: MaskedIban,

    /// Bank name
    #[schema(value_type = Option<String>, example = "Deutsche Bank")]
    pub bank_name: Option<String>,

    /// Bank country code
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub bank_country_code: Option<common_enums::CountryAlpha2>,

    /// Bank city
    #[schema(value_type = Option<String>, example = "California")]
    pub bank_city: Option<String>,

    /// [8 / 11 digits] Bank Identifier Code (bic) / Swift Code - used in many countries for identifying a bank and it's branches
    #[schema(value_type = Option<String>, example = "HSBCGB2LXXX")]
    pub bic: Option<MaskedBic>,
}

/// Masked payout method details for pix bank transfer payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct PixBankTransferAdditionalData {
    /// Partially masked unique key for pix transfer
    #[schema(value_type = String, example = "a1f4102e ****** 6fa48899c1d1")]
    pub pix_key: MaskedBankAccount,

    /// Partially masked CPF - CPF is a Brazilian tax identification number
    #[schema(value_type = Option<String>, example = "**** 124689")]
    pub tax_id: Option<MaskedBankAccount>,

    /// Bank account number is an unique identifier assigned by a bank to a customer.
    #[schema(value_type = String, example = "**** 23456")]
    pub bank_account_number: MaskedBankAccount,

    /// Bank name
    #[schema(value_type = Option<String>, example = "Deutsche Bank")]
    pub bank_name: Option<String>,

    /// Bank branch
    #[schema(value_type = Option<String>, example = "3707")]
    pub bank_branch: Option<String>,
}

/// Masked payout method details for wallet payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
#[serde(untagged)]
pub enum WalletAdditionalData {
    /// Additional data for paypal wallet payout method
    Paypal(Box<PaypalAdditionalData>),
    /// Additional data for venmo wallet payout method
    Venmo(Box<VenmoAdditionalData>),
    /// Additional data for Apple pay decrypt wallet payout method
    ApplePayDecrypt(Box<ApplePayDecryptAdditionalData>),
}

/// Masked payout method details for paypal wallet payout method
#[derive(
    Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct PaypalAdditionalData {
    /// Email linked with paypal account
    #[schema(value_type = Option<String>, example = "john.doe@example.com")]
    pub email: Option<MaskedEmail>,

    /// mobile number linked to paypal account
    #[schema(value_type = Option<String>, example = "******* 3349")]
    pub telephone_number: Option<MaskedPhoneNumber>,

    /// id of the paypal account
    #[schema(value_type = Option<String>, example = "G83K ***** HCQ2")]
    pub paypal_id: Option<MaskedBankAccount>,
}

/// Masked payout method details for venmo wallet payout method
#[derive(
    Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct VenmoAdditionalData {
    /// mobile number linked to venmo account
    #[schema(value_type = Option<String>, example = "******* 3349")]
    pub telephone_number: Option<MaskedPhoneNumber>,
}

/// Masked payout method details for Apple pay decrypt wallet payout method
#[derive(
    Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct ApplePayDecryptAdditionalData {
    /// Card expiry month
    #[schema(value_type = String, example = "01")]
    pub card_exp_month: Secret<String>,

    /// Card expiry year
    #[schema(value_type = String, example = "2026")]
    pub card_exp_year: Secret<String>,

    /// Card holder name
    #[schema(value_type = String, example = "John Doe")]
    pub card_holder_name: Option<Secret<String>>,
}

/// Masked payout method details for wallet payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
#[serde(untagged)]
pub enum BankRedirectAdditionalData {
    /// Additional data for interac bank redirect payout method
    Interac(Box<InteracAdditionalData>),
}

/// Masked payout method details for interac bank redirect payout method
#[derive(
    Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct InteracAdditionalData {
    /// Email linked with interac account
    #[schema(value_type = Option<String>, example = "john.doe@example.com")]
    pub email: Option<MaskedEmail>,
}

/// additional payout method details for passthrough payout method
#[derive(
    Eq, PartialEq, Clone, Debug, Deserialize, Serialize, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct PassthroughAddtionalData {
    /// Psp_token of the passthrough flow
    #[schema(value_type = String, example = "token_12345")]
    pub psp_token: MaskedPspToken,
    /// token_type of the passthrough flow
    #[schema(value_type = PaymentMethodType, example = "paypal")]
    pub token_type: common_enums::PaymentMethodType,
}