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

pub(super) mod customer;
pub(super) mod payment;
pub(super) mod payment_methods;
pub(super) mod refunds;
pub(super) mod token;

use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types};
use error_stack::ResultExt;
use thiserror::Error;

use crate::{
    consts::{CELL_IDENTIFIER_LENGTH, MAX_GLOBAL_ID_LENGTH, MIN_GLOBAL_ID_LENGTH},
    errors, generate_time_ordered_id,
    id_type::{AlphaNumericId, AlphaNumericIdError, LengthId, LengthIdError},
};

#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize)]
/// A global id that can be used to identify any entity
/// This id will have information about the entity and cell in a distributed system architecture
pub(crate) struct GlobalId(LengthId<MAX_GLOBAL_ID_LENGTH, MIN_GLOBAL_ID_LENGTH>);

#[derive(Clone, Copy)]
/// Entities that can be identified by a global id
pub(crate) enum GlobalEntity {
    Customer,
    Payment,
    Attempt,
    AttemptGroup,
    PaymentMethod,
    Refund,
    PaymentMethodSession,
    Token,
}

impl GlobalEntity {
    fn prefix(self) -> &'static str {
        match self {
            Self::Customer => "cus",
            Self::Payment => "pay",
            Self::PaymentMethod => "pm",
            Self::Attempt => "att",
            Self::AttemptGroup => "atg",
            Self::Refund => "ref",
            Self::PaymentMethodSession => "pms",
            Self::Token => "tok",
        }
    }
}

/// Cell identifier for an instance / deployment of application
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct CellId(LengthId<CELL_IDENTIFIER_LENGTH, CELL_IDENTIFIER_LENGTH>);

#[derive(Debug, Error, PartialEq, Eq)]
pub enum CellIdError {
    #[error("cell id error: {0}")]
    InvalidCellLength(LengthIdError),

    #[error("{0}")]
    InvalidCellIdFormat(AlphaNumericIdError),
}

impl From<LengthIdError> for CellIdError {
    fn from(error: LengthIdError) -> Self {
        Self::InvalidCellLength(error)
    }
}

impl From<AlphaNumericIdError> for CellIdError {
    fn from(error: AlphaNumericIdError) -> Self {
        Self::InvalidCellIdFormat(error)
    }
}

impl CellId {
    /// Create a new cell id from a string
    fn from_str(cell_id_string: impl AsRef<str>) -> Result<Self, CellIdError> {
        let trimmed_input_string = cell_id_string.as_ref().trim().to_string();
        let alphanumeric_id = AlphaNumericId::from(trimmed_input_string.into())?;
        let length_id = LengthId::from_alphanumeric_id(alphanumeric_id)?;
        Ok(Self(length_id))
    }

    /// Create a new cell id from a string
    pub fn from_string(
        input_string: impl AsRef<str>,
    ) -> error_stack::Result<Self, errors::ValidationError> {
        Self::from_str(input_string).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "cell_id",
            },
        )
    }

    /// Get the string representation of the cell id
    fn get_string_repr(&self) -> &str {
        &self.0 .0 .0
    }
}

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

/// Error generated from violation of constraints for MerchantReferenceId
#[derive(Debug, Error, PartialEq, Eq)]
pub(crate) enum GlobalIdError {
    /// The format for the global id is invalid
    #[error("The id format is invalid, expected format is {{cell_id:5}}_{{entity_prefix:3}}_{{uuid:32}}_{{random:24}}")]
    InvalidIdFormat,

    /// LengthIdError and AlphanumericIdError
    #[error("{0}")]
    LengthIdError(#[from] LengthIdError),

    /// CellIdError because of invalid cell id format
    #[error("{0}")]
    CellIdError(#[from] CellIdError),
}

impl GlobalId {
    /// Create a new global id from entity and cell information
    /// The entity prefix is used to identify the entity, `cus` for customers, `pay`` for payments etc.
    pub fn generate(cell_id: &CellId, entity: GlobalEntity) -> Self {
        let prefix = format!("{}_{}", cell_id.get_string_repr(), entity.prefix());
        let id = generate_time_ordered_id(&prefix);
        let alphanumeric_id = AlphaNumericId::new_unchecked(id);
        Self(LengthId::new_unchecked(alphanumeric_id))
    }

    pub(crate) fn from_string(
        input_string: std::borrow::Cow<'static, str>,
    ) -> Result<Self, GlobalIdError> {
        let length_id = LengthId::from(input_string)?;
        let input_string = &length_id.0 .0;
        let (cell_id, _remaining) = input_string
            .split_once("_")
            .ok_or(GlobalIdError::InvalidIdFormat)?;

        CellId::from_str(cell_id)?;

        Ok(Self(length_id))
    }

    pub(crate) fn get_string_repr(&self) -> &str {
        &self.0 .0 .0
    }
}

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

impl<DB> FromSql<sql_types::Text, DB> for GlobalId
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)?;
        let alphanumeric_id = AlphaNumericId::from(string_val.into())?;
        let length_id = LengthId::from_alphanumeric_id(alphanumeric_id)?;
        Ok(Self(length_id))
    }
}

/// Deserialize the global id from string
/// The format should match {cell_id:5}_{entity_prefix:3}_{time_ordered_id:32}_{.*:24}
impl<'de> serde::Deserialize<'de> for GlobalId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized_string = String::deserialize(deserializer)?;
        Self::from_string(deserialized_string.into()).map_err(serde::de::Error::custom)
    }
}

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

    #[test]
    fn test_cell_id_from_str() {
        let cell_id_string = "12345";
        let cell_id = CellId::from_str(cell_id_string).unwrap();
        assert_eq!(cell_id.get_string_repr(), cell_id_string);
    }

    #[test]
    fn test_global_id_generate() {
        let cell_id_string = "12345";
        let entity = GlobalEntity::Customer;
        let cell_id = CellId::from_str(cell_id_string).unwrap();
        let global_id = GlobalId::generate(&cell_id, entity);

        // Generate a regex for globalid
        // Eg - 12abc_cus_abcdefghijklmnopqrstuvwxyz1234567890
        let regex = regex::Regex::new(r"[a-z0-9]{5}_cus_[a-z0-9]{32}").unwrap();

        assert!(regex.is_match(&global_id.0 .0 .0));
    }

    #[test]
    fn test_global_id_from_string() {
        let input_string = "12345_cus_abcdefghijklmnopqrstuvwxyz1234567890";
        let global_id = GlobalId::from_string(input_string.into()).unwrap();
        assert_eq!(global_id.0 .0 .0, input_string);
    }

    #[test]
    fn test_global_id_deser() {
        let input_string_for_serde_json_conversion =
            r#""12345_cus_abcdefghijklmnopqrstuvwxyz1234567890""#;

        let input_string = "12345_cus_abcdefghijklmnopqrstuvwxyz1234567890";
        let global_id =
            serde_json::from_str::<GlobalId>(input_string_for_serde_json_conversion).unwrap();
        assert_eq!(global_id.0 .0 .0, input_string);
    }

    #[test]
    fn test_global_id_deser_error() {
        let input_string_for_serde_json_conversion =
            r#""123_45_cus_abcdefghijklmnopqrstuvwxyz1234567890""#;

        let global_id = serde_json::from_str::<GlobalId>(input_string_for_serde_json_conversion);
        assert!(global_id.is_err());

        let expected_error_message = format!(
            "cell id error: the minimum required length for this field is {CELL_IDENTIFIER_LENGTH}"
        );

        let error_message = global_id.unwrap_err().to_string();
        assert_eq!(error_message, expected_error_message);
    }
}


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

crate::id_type!(
    SubscriptionId,
    " A type for subscription_id that can be used for subscription ids"
);

crate::impl_id_type_methods!(SubscriptionId, "subscription_id");

// This is to display the `SubscriptionId` as SubscriptionId(subs)
crate::impl_debug_id_type!(SubscriptionId);
crate::impl_try_from_cow_str_id_type!(SubscriptionId, "subscription_id");

crate::impl_generate_id_id_type!(SubscriptionId, "sub");
crate::impl_serializable_secret_id_type!(SubscriptionId);
crate::impl_queryable_id_type!(SubscriptionId);
crate::impl_to_sql_from_sql_id_type!(SubscriptionId);

impl crate::events::ApiEventMetric for SubscriptionId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Subscription)
    }
}


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

//! Contains the id type for merchant account
//!
//! Ids for merchant account are derived from the merchant name
//! If there are any special characters, they are removed

use crate::{
    date_time,
    errors::{CustomResult, ValidationError},
    generate_id_with_default_len,
    id_type::{AlphaNumericId, LengthId},
    new_type::MerchantName,
    types::keymanager,
};

crate::id_type!(
    MerchantId,
    "A type for merchant_id that can be used for merchant ids"
);
crate::impl_id_type_methods!(MerchantId, "merchant_id");

// This is to display the `MerchantId` as MerchantId(abcd)
crate::impl_debug_id_type!(MerchantId);
crate::impl_default_id_type!(MerchantId, "mer");
crate::impl_try_from_cow_str_id_type!(MerchantId, "merchant_id");

crate::impl_generate_id_id_type!(MerchantId, "mer");
crate::impl_serializable_secret_id_type!(MerchantId);
crate::impl_queryable_id_type!(MerchantId);
crate::impl_to_sql_from_sql_id_type!(MerchantId);

// This is implemented so that we can use merchant id directly as attribute in metrics
#[cfg(feature = "metrics")]
impl From<MerchantId> for router_env::opentelemetry::Value {
    fn from(val: MerchantId) -> Self {
        Self::from(val.0 .0 .0)
    }
}

impl MerchantId {
    /// Create a Merchant id from MerchantName
    pub fn from_merchant_name(merchant_name: MerchantName) -> Self {
        let merchant_name_string = merchant_name.into_inner();

        let merchant_id_prefix = merchant_name_string.trim().to_lowercase().replace(' ', "");

        let alphanumeric_id =
            AlphaNumericId::new_unchecked(generate_id_with_default_len(&merchant_id_prefix));
        let length_id = LengthId::new_unchecked(alphanumeric_id);

        Self(length_id)
    }

    /// Get a merchant id with the const value of `MERCHANT_ID_NOT_FOUND`
    pub fn get_merchant_id_not_found() -> Self {
        let alphanumeric_id = AlphaNumericId::new_unchecked("MERCHANT_ID_NOT_FOUND".to_string());
        let length_id = LengthId::new_unchecked(alphanumeric_id);
        Self(length_id)
    }

    /// Get a merchant id for internal use only
    pub fn get_internal_user_merchant_id(merchant_id: &str) -> Self {
        let alphanumeric_id = AlphaNumericId::new_unchecked(merchant_id.to_string());
        let length_id = LengthId::new_unchecked(alphanumeric_id);
        Self(length_id)
    }

    /// Create a new merchant_id from unix timestamp, of the format `merchant_{timestamp}`
    pub fn new_from_unix_timestamp() -> Self {
        let merchant_id = format!("merchant_{}", date_time::now_unix_timestamp());

        let alphanumeric_id = AlphaNumericId::new_unchecked(merchant_id);
        let length_id = LengthId::new_unchecked(alphanumeric_id);

        Self(length_id)
    }

    /// Get a merchant id with a value of `irrelevant_merchant_id`
    pub fn get_irrelevant_merchant_id() -> Self {
        let alphanumeric_id = AlphaNumericId::new_unchecked("irrelevant_merchant_id".to_string());
        let length_id = LengthId::new_unchecked(alphanumeric_id);
        Self(length_id)
    }

    /// Get a merchant id from String
    pub fn wrap(merchant_id: String) -> CustomResult<Self, ValidationError> {
        Self::try_from(std::borrow::Cow::from(merchant_id))
    }
}

impl From<MerchantId> for keymanager::Identifier {
    fn from(value: MerchantId) -> Self {
        Self::Merchant(value)
    }
}

/// All the keys that can be formed from merchant id
impl MerchantId {
    /// get step up enabled key
    pub fn get_step_up_enabled_key(&self) -> String {
        format!("step_up_enabled_{}", self.get_string_repr())
    }

    /// get_max_auto_retries_enabled key
    pub fn get_max_auto_retries_enabled(&self) -> String {
        format!("max_auto_retries_enabled_{}", self.get_string_repr())
    }

    /// get_requires_cvv_key
    pub fn get_requires_cvv_key(&self) -> String {
        format!("{}_requires_cvv", self.get_string_repr())
    }

    /// get_pm_filters_cgraph_key
    pub fn get_pm_filters_cgraph_key(&self) -> String {
        format!("pm_filters_cgraph_{}", self.get_string_repr())
    }

    /// get_blocklist_enabled_key
    pub fn get_blocklist_guard_key(&self) -> String {
        format!("guard_blocklist_for_{}", self.get_string_repr())
    }

    /// get_merchant_fingerprint_secret_key
    pub fn get_merchant_fingerprint_secret_key(&self) -> String {
        format!("fingerprint_secret_{}", self.get_string_repr())
    }

    /// get_surcharge_dsk_key
    pub fn get_surcharge_dsk_key(&self) -> String {
        format!("surcharge_dsl_{}", self.get_string_repr())
    }

    /// get_dsk_key
    pub fn get_dsl_config(&self) -> String {
        format!("dsl_{}", self.get_string_repr())
    }

    /// get_creds_identifier_key
    pub fn get_creds_identifier_key(&self, creds_identifier: &str) -> String {
        format!("mcd_{}_{creds_identifier}", self.get_string_repr())
    }

    /// get_poll_id
    pub fn get_poll_id(&self, unique_id: &str) -> String {
        format!("poll_{}_{unique_id}", self.get_string_repr())
    }

    /// get_skip_saving_wallet_at_connector_key
    pub fn get_skip_saving_wallet_at_connector_key(&self) -> String {
        format!("skip_saving_wallet_at_connector_{}", self.get_string_repr())
    }

    /// get_payment_config_routing_id
    pub fn get_payment_config_routing_id(&self) -> String {
        format!("payment_config_id_{}", self.get_string_repr())
    }

    /// get_payment_method_surcharge_routing_id
    pub fn get_payment_method_surcharge_routing_id(&self) -> String {
        format!("payment_method_surcharge_id_{}", self.get_string_repr())
    }

    /// get_webhook_config_disabled_events_key
    pub fn get_webhook_config_disabled_events_key(&self, connector_id: &str) -> String {
        format!(
            "whconf_disabled_events_{}_{connector_id}",
            self.get_string_repr()
        )
    }

    /// get_should_call_gsm_payout_key
    pub fn get_should_call_gsm_payout_key(
        &self,
        payout_retry_type: common_enums::PayoutRetryType,
    ) -> String {
        match payout_retry_type {
            common_enums::PayoutRetryType::SingleConnector => format!(
                "should_call_gsm_single_connector_payout_{}",
                self.get_string_repr()
            ),
            common_enums::PayoutRetryType::MultiConnector => format!(
                "should_call_gsm_multiple_connector_payout_{}",
                self.get_string_repr()
            ),
        }
    }

    /// Get should call gsm key for payment
    pub fn get_should_call_gsm_key(&self) -> String {
        format!("should_call_gsm_{}", self.get_string_repr())
    }

    /// get should call auth tokenization for modular authentication
    pub fn get_should_disable_auth_tokenization(&self) -> String {
        format!(
            "should_disable_auth_tokenization_{}",
            self.get_string_repr()
        )
    }

    /// get_max_auto_single_connector_payout_retries_enabled_
    pub fn get_max_auto_single_connector_payout_retries_enabled(
        &self,
        payout_retry_type: common_enums::PayoutRetryType,
    ) -> String {
        match payout_retry_type {
            common_enums::PayoutRetryType::SingleConnector => format!(
                "max_auto_single_connector_payout_retries_enabled_{}",
                self.get_string_repr()
            ),
            common_enums::PayoutRetryType::MultiConnector => format!(
                "max_auto_multiple_connector_payout_retries_enabled_{}",
                self.get_string_repr()
            ),
        }
    }
    /// allow payment update via client auth default should be false
    pub fn get_payment_update_enabled_for_client_auth_key(&self) -> String {
        format!(
            "payment_update_enabled_for_client_auth_{}",
            self.get_string_repr()
        )
    }

    /// Get should perform eligibility check key for payment
    pub fn get_should_perform_eligibility_check_key(&self) -> String {
        format!("should_perform_eligibility_{}", self.get_string_repr())
    }

    /// Get should store eligibility check data for authentication
    pub fn get_should_store_eligibility_check_data_for_authentication(&self) -> String {
        format!(
            "should_store_eligibility_check_data_for_authentication_{}",
            self.get_string_repr()
        )
    }
}


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

use crate::{
    errors::{CustomResult, ValidationError},
    generate_id_with_default_len,
    id_type::{AlphaNumericId, LengthId},
};

crate::id_type!(
    PaymentId,
    "A type for payment_id that can be used for payment ids"
);
crate::impl_id_type_methods!(PaymentId, "payment_id");

// This is to display the `PaymentId` as PaymentId(abcd)
crate::impl_debug_id_type!(PaymentId);
crate::impl_default_id_type!(PaymentId, "pay");
crate::impl_try_from_cow_str_id_type!(PaymentId, "payment_id");

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(PaymentId);
crate::impl_to_sql_from_sql_id_type!(PaymentId);

impl PaymentId {
    /// Get the hash key to be stored in redis
    pub fn get_hash_key_for_kv_store(&self) -> String {
        format!("pi_{}", self.0 .0 .0)
    }

    // This function should be removed once we have a better way to handle mandatory payment id in other flows
    /// Get payment id in the format of irrelevant_payment_id_in_{flow}
    pub fn get_irrelevant_id(flow: &str) -> Self {
        let alphanumeric_id =
            AlphaNumericId::new_unchecked(format!("irrelevant_payment_id_in_{flow}"));
        let id = LengthId::new_unchecked(alphanumeric_id);
        Self(id)
    }

    /// Get the attempt id for the payment id based on the attempt count
    pub fn get_attempt_id(&self, attempt_count: i16) -> String {
        format!("{}_{attempt_count}", self.get_string_repr())
    }

    /// Generate a client id for the payment id
    pub fn generate_client_secret(&self) -> String {
        generate_id_with_default_len(&format!("{}_secret", self.get_string_repr()))
    }

    /// Generate a key for pm_auth
    pub fn get_pm_auth_key(&self) -> String {
        format!("pm_auth_{}", self.get_string_repr())
    }

    /// Get external authentication request poll id
    pub fn get_external_authentication_request_poll_id(&self) -> String {
        format!("external_authentication_{}", self.get_string_repr())
    }

    /// Generate a test payment id with prefix test_
    pub fn generate_test_payment_id_for_sample_data() -> Self {
        let id = generate_id_with_default_len("test");
        let alphanumeric_id = AlphaNumericId::new_unchecked(id);
        let id = LengthId::new_unchecked(alphanumeric_id);
        Self(id)
    }

    /// Wrap a string inside PaymentId
    pub fn wrap(payment_id_string: String) -> CustomResult<Self, ValidationError> {
        Self::try_from(std::borrow::Cow::from(payment_id_string))
    }
}

crate::id_type!(PaymentReferenceId, "A type for payment_reference_id");
crate::impl_id_type_methods!(PaymentReferenceId, "payment_reference_id");

// This is to display the `PaymentReferenceId` as PaymentReferenceId(abcd)
crate::impl_debug_id_type!(PaymentReferenceId);
crate::impl_try_from_cow_str_id_type!(PaymentReferenceId, "payment_reference_id");

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(PaymentReferenceId);
crate::impl_to_sql_from_sql_id_type!(PaymentReferenceId);

// This is implemented so that we can use payment id directly as attribute in metrics
#[cfg(feature = "metrics")]
impl From<PaymentId> for router_env::opentelemetry::Value {
    fn from(val: PaymentId) -> Self {
        Self::from(val.0 .0 .0)
    }
}

impl std::str::FromStr for PaymentReferenceId {
    type Err = error_stack::Report<ValidationError>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cow_string = std::borrow::Cow::Owned(s.to_string());
        Self::try_from(cow_string)
    }
}


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

crate::id_type!(
    InvoiceId,
    " A type for invoice_id that can be used for invoice ids"
);

crate::impl_id_type_methods!(InvoiceId, "invoice_id");

// This is to display the `InvoiceId` as InvoiceId(subs)
crate::impl_debug_id_type!(InvoiceId);
crate::impl_try_from_cow_str_id_type!(InvoiceId, "invoice_id");

crate::impl_generate_id_id_type!(InvoiceId, "invoice");
crate::impl_serializable_secret_id_type!(InvoiceId);
crate::impl_queryable_id_type!(InvoiceId);
crate::impl_to_sql_from_sql_id_type!(InvoiceId);

impl crate::events::ApiEventMetric for InvoiceId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Invoice)
    }
}


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

crate::id_type!(
    CustomerId,
    "A type for customer_id that can be used for customer ids"
);
crate::impl_id_type_methods!(CustomerId, "customer_id");

// This is to display the `CustomerId` as CustomerId(abcd)
crate::impl_debug_id_type!(CustomerId);
crate::impl_default_id_type!(CustomerId, "cus");
crate::impl_try_from_cow_str_id_type!(CustomerId, "customer_id");

crate::impl_generate_id_id_type!(CustomerId, "cus");
crate::impl_serializable_secret_id_type!(CustomerId);
crate::impl_queryable_id_type!(CustomerId);
crate::impl_to_sql_from_sql_id_type!(CustomerId);

#[cfg(feature = "v1")]
impl crate::events::ApiEventMetric for CustomerId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Customer {
            customer_id: self.clone(),
        })
    }
}


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

use std::str::FromStr;

crate::id_type!(
    ProfileAcquirerId,
    "A type for profile_acquirer_id that can be used for profile acquirer ids"
);
crate::impl_id_type_methods!(ProfileAcquirerId, "profile_acquirer_id");

// This is to display the `ProfileAcquirerId` as ProfileAcquirerId(abcd)
crate::impl_debug_id_type!(ProfileAcquirerId);
crate::impl_try_from_cow_str_id_type!(ProfileAcquirerId, "profile_acquirer_id");

crate::impl_generate_id_id_type!(ProfileAcquirerId, "pro_acq");
crate::impl_serializable_secret_id_type!(ProfileAcquirerId);
crate::impl_queryable_id_type!(ProfileAcquirerId);
crate::impl_to_sql_from_sql_id_type!(ProfileAcquirerId);

impl Ord for ProfileAcquirerId {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.0 .0 .0.cmp(&other.0 .0 .0)
    }
}

impl PartialOrd for ProfileAcquirerId {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl crate::events::ApiEventMetric for ProfileAcquirerId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::ProfileAcquirer {
            profile_acquirer_id: self.clone(),
        })
    }
}

impl FromStr for ProfileAcquirerId {
    type Err = error_stack::Report<crate::errors::ValidationError>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cow_string = std::borrow::Cow::Owned(s.to_string());
        Self::try_from(cow_string)
    }
}

// This is implemented so that we can use profile acquirer id directly as attribute in metrics
#[cfg(feature = "metrics")]
impl From<ProfileAcquirerId> for router_env::opentelemetry::Value {
    fn from(val: ProfileAcquirerId) -> Self {
        Self::from(val.0 .0 .0)
    }
}


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

crate::id_type!(
    AuthenticationId,
    "A type for authentication_id that can be used for authentication IDs"
);
crate::impl_id_type_methods!(AuthenticationId, "authentication_id");

// This is to display the `AuthenticationId` as AuthenticationId(abcd)
crate::impl_debug_id_type!(AuthenticationId);
crate::impl_try_from_cow_str_id_type!(AuthenticationId, "authentication_id");

crate::impl_serializable_secret_id_type!(AuthenticationId);
crate::impl_queryable_id_type!(AuthenticationId);
crate::impl_to_sql_from_sql_id_type!(AuthenticationId);

impl AuthenticationId {
    /// Generate Authentication Id from prefix
    pub fn generate_authentication_id(prefix: &'static str) -> Self {
        Self(crate::generate_ref_id_with_default_length(prefix))
    }

    /// Get external authentication request poll id
    pub fn get_external_authentication_request_poll_id(&self) -> String {
        format!("external_authentication_{}", self.get_string_repr())
    }
}

impl crate::events::ApiEventMetric for AuthenticationId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Authentication {
            authentication_id: self.clone(),
        })
    }
}

impl crate::events::ApiEventMetric for (super::MerchantId, AuthenticationId) {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Authentication {
            authentication_id: self.1.clone(),
        })
    }
}

impl crate::events::ApiEventMetric for (&super::MerchantId, &AuthenticationId) {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Authentication {
            authentication_id: self.1.clone(),
        })
    }
}

crate::impl_default_id_type!(AuthenticationId, "authentication");


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

crate::id_type!(
    RoutingId,
    " A type for routing_id that can be used for routing ids"
);

crate::impl_id_type_methods!(RoutingId, "routing_id");

// This is to display the `RoutingId` as RoutingId(abcd)
crate::impl_debug_id_type!(RoutingId);
crate::impl_try_from_cow_str_id_type!(RoutingId, "routing_id");

crate::impl_generate_id_id_type!(RoutingId, "routing");
crate::impl_serializable_secret_id_type!(RoutingId);
crate::impl_queryable_id_type!(RoutingId);
crate::impl_to_sql_from_sql_id_type!(RoutingId);

impl crate::events::ApiEventMetric for RoutingId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Routing)
    }
}


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

crate::id_type!(
    ApiKeyId,
    "A type for key_id that can be used for API key IDs"
);
crate::impl_id_type_methods!(ApiKeyId, "key_id");

// This is to display the `ApiKeyId` as ApiKeyId(abcd)
crate::impl_debug_id_type!(ApiKeyId);
crate::impl_try_from_cow_str_id_type!(ApiKeyId, "key_id");

crate::impl_serializable_secret_id_type!(ApiKeyId);
crate::impl_queryable_id_type!(ApiKeyId);
crate::impl_to_sql_from_sql_id_type!(ApiKeyId);

impl ApiKeyId {
    /// Generate Api Key Id from prefix
    pub fn generate_key_id(prefix: &'static str) -> Self {
        Self(crate::generate_ref_id_with_default_length(prefix))
    }
}

impl crate::events::ApiEventMetric for ApiKeyId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::ApiKey {
            key_id: self.clone(),
        })
    }
}

impl crate::events::ApiEventMetric for (super::MerchantId, ApiKeyId) {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::ApiKey {
            key_id: self.1.clone(),
        })
    }
}

impl crate::events::ApiEventMetric for (&super::MerchantId, &ApiKeyId) {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::ApiKey {
            key_id: self.1.clone(),
        })
    }
}

crate::impl_default_id_type!(ApiKeyId, "key");


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

use std::str::FromStr;

crate::id_type!(
    RelayId,
    "A type for relay_id that can be used for relay ids"
);
crate::impl_id_type_methods!(RelayId, "relay_id");

crate::impl_try_from_cow_str_id_type!(RelayId, "relay_id");
crate::impl_generate_id_id_type!(RelayId, "relay");
crate::impl_serializable_secret_id_type!(RelayId);
crate::impl_queryable_id_type!(RelayId);
crate::impl_to_sql_from_sql_id_type!(RelayId);

crate::impl_debug_id_type!(RelayId);

impl FromStr for RelayId {
    type Err = error_stack::Report<crate::errors::ValidationError>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cow_string = std::borrow::Cow::Owned(s.to_string());
        Self::try_from(cow_string)
    }
}


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

use crate::errors::{CustomResult, ValidationError};

crate::id_type!(
    WebhookEndpointId,
    "A type for webhook_endpoint_id that can be used for unique identifier for a webhook_endpoint"
);
crate::impl_id_type_methods!(WebhookEndpointId, "webhook_endpoint_id");
crate::impl_generate_id_id_type!(WebhookEndpointId, "whe");
crate::impl_default_id_type!(WebhookEndpointId, "whe");

// This is to display the `WebhookEndpointId` as WebhookEndpointId(abcd)
crate::impl_debug_id_type!(WebhookEndpointId);
crate::impl_try_from_cow_str_id_type!(WebhookEndpointId, "webhook_endpoint_id");

crate::impl_serializable_secret_id_type!(WebhookEndpointId);
crate::impl_queryable_id_type!(WebhookEndpointId);
crate::impl_to_sql_from_sql_id_type!(WebhookEndpointId);

impl WebhookEndpointId {
    /// Get webhook_endpoint id from String
    pub fn try_from_string(webhook_endpoint_id: String) -> CustomResult<Self, ValidationError> {
        Self::try_from(std::borrow::Cow::from(webhook_endpoint_id))
    }
}


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

use error_stack::ResultExt;

use crate::{
    errors::CustomResult,
    id_type::global_id::{CellId, GlobalEntity, GlobalId},
};

/// A global id that can be used to identify a payment method
#[derive(
    Debug,
    Clone,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct GlobalPaymentMethodId(GlobalId);

/// A global id that can be used to identify a payment method session
#[derive(
    Debug,
    Clone,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct GlobalPaymentMethodSessionId(GlobalId);

#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
pub enum GlobalPaymentMethodIdError {
    #[error("Failed to construct GlobalPaymentMethodId")]
    ConstructionError,
}

#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
pub enum GlobalPaymentMethodSessionIdError {
    #[error("Failed to construct GlobalPaymentMethodSessionId")]
    ConstructionError,
}

impl GlobalPaymentMethodSessionId {
    /// Create a new GlobalPaymentMethodSessionId from cell id information
    pub fn generate(
        cell_id: &CellId,
    ) -> error_stack::Result<Self, GlobalPaymentMethodSessionIdError> {
        let global_id = GlobalId::generate(cell_id, GlobalEntity::PaymentMethodSession);
        Ok(Self(global_id))
    }

    /// Get the string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Construct a redis key from the id to be stored in redis
    pub fn get_redis_key(&self) -> String {
        format!("payment_method_session:{}", self.get_string_repr())
    }
}

#[cfg(feature = "v2")]
impl crate::events::ApiEventMetric for GlobalPaymentMethodSessionId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::PaymentMethodSession {
            payment_method_session_id: self.clone(),
        })
    }
}

impl crate::events::ApiEventMetric for GlobalPaymentMethodId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(
            crate::events::ApiEventsType::PaymentMethodListForPaymentMethods {
                payment_method_id: self.clone(),
            },
        )
    }
}

impl GlobalPaymentMethodId {
    /// Create a new GlobalPaymentMethodId from cell id information
    pub fn generate(cell_id: &CellId) -> error_stack::Result<Self, GlobalPaymentMethodIdError> {
        let global_id = GlobalId::generate(cell_id, GlobalEntity::PaymentMethod);
        Ok(Self(global_id))
    }

    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Construct a new GlobalPaymentMethodId from a string
    pub fn generate_from_string(value: String) -> CustomResult<Self, GlobalPaymentMethodIdError> {
        let id = GlobalId::from_string(value.into())
            .change_context(GlobalPaymentMethodIdError::ConstructionError)?;
        Ok(Self(id))
    }
}

impl<DB> diesel::Queryable<diesel::sql_types::Text, DB> for GlobalPaymentMethodId
where
    DB: diesel::backend::Backend,
    Self: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
    type Row = Self;
    fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
        Ok(row)
    }
}

impl<DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for GlobalPaymentMethodId
where
    DB: diesel::backend::Backend,
    GlobalId: diesel::serialize::ToSql<diesel::sql_types::Text, 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::sql_types::Text, DB> for GlobalPaymentMethodId
where
    DB: diesel::backend::Backend,
    GlobalId: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
    fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
        let global_id = GlobalId::from_sql(value)?;
        Ok(Self(global_id))
    }
}

impl<DB> diesel::Queryable<diesel::sql_types::Text, DB> for GlobalPaymentMethodSessionId
where
    DB: diesel::backend::Backend,
    Self: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
    type Row = Self;
    fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
        Ok(row)
    }
}

impl<DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for GlobalPaymentMethodSessionId
where
    DB: diesel::backend::Backend,
    GlobalId: diesel::serialize::ToSql<diesel::sql_types::Text, 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::sql_types::Text, DB> for GlobalPaymentMethodSessionId
where
    DB: diesel::backend::Backend,
    GlobalId: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
    fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
        let global_id = GlobalId::from_sql(value)?;
        Ok(Self(global_id))
    }
}


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

use error_stack::ResultExt;

use crate::errors;

/// A global id that can be used to identify a refund
#[derive(
    Debug,
    Clone,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct GlobalRefundId(super::GlobalId);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalRefundId);

impl GlobalRefundId {
    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Generate a new GlobalRefundId from a cell id
    pub fn generate(cell_id: &crate::id_type::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Refund);
        Self(global_id)
    }
}

// TODO: refactor the macro to include this id use case as well
impl TryFrom<std::borrow::Cow<'static, str>> for GlobalRefundId {
    type Error = error_stack::Report<errors::ValidationError>;
    fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
        let merchant_ref_id = super::GlobalId::from_string(value).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "refund_id",
            },
        )?;
        Ok(Self(merchant_ref_id))
    }
}

// TODO: refactor the macro to include this id use case as well
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for GlobalRefundId
where
    DB: diesel::backend::Backend,
    super::GlobalId: diesel::serialize::ToSql<diesel::sql_types::Text, 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::sql_types::Text, DB> for GlobalRefundId
where
    DB: diesel::backend::Backend,
    super::GlobalId: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
    fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
        super::GlobalId::from_sql(value).map(Self)
    }
}


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

use std::borrow::Cow;

use error_stack::ResultExt;

use crate::errors::{CustomResult, ValidationError};

crate::global_id_type!(
    GlobalTokenId,
    "A global id that can be used to identify a token.

The format will be `<cell_id>_<entity_prefix>_<time_ordered_id>`.

Example: `cell1_tok_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p`"
);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalTokenId);
crate::impl_to_sql_from_sql_global_id_type!(GlobalTokenId);

impl GlobalTokenId {
    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    ///Get GlobalTokenId from a string
    pub fn from_string(token_string: &str) -> CustomResult<Self, ValidationError> {
        let token = super::GlobalId::from_string(Cow::Owned(token_string.to_string()))
            .change_context(ValidationError::IncorrectValueProvided {
                field_name: "GlobalTokenId",
            })?;
        Ok(Self(token))
    }

    /// Generate a new GlobalTokenId from a cell id
    pub fn generate(cell_id: &crate::id_type::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Token);
        Self(global_id)
    }
}

impl crate::events::ApiEventMetric for GlobalTokenId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Token {
            token_id: Some(self.clone()),
        })
    }
}


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

use common_enums::enums;
use error_stack::ResultExt;

use crate::errors;

crate::global_id_type!(
    GlobalPaymentId,
    "A global id that can be used to identify a payment.

The format will be `<cell_id>_<entity_prefix>_<time_ordered_id>`.

Example: `cell1_pay_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p`"
);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalPaymentId);
crate::impl_to_sql_from_sql_global_id_type!(GlobalPaymentId);

impl GlobalPaymentId {
    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Generate a new GlobalPaymentId from a cell id
    pub fn generate(cell_id: &crate::id_type::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Payment);
        Self(global_id)
    }

    /// Generate the id for revenue recovery Execute PT workflow
    pub fn get_execute_revenue_recovery_id(
        &self,
        task: &str,
        runner: enums::ProcessTrackerRunner,
    ) -> String {
        format!("{runner}_{task}_{}", self.get_string_repr())
    }

    /// Generate a key for gift card connector
    pub fn get_gift_card_connector_key(&self) -> String {
        format!("gift_mca_{}", self.get_string_repr())
    }
}

// TODO: refactor the macro to include this id use case as well
impl TryFrom<std::borrow::Cow<'static, str>> for GlobalPaymentId {
    type Error = error_stack::Report<errors::ValidationError>;
    fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
        let merchant_ref_id = super::GlobalId::from_string(value).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "payment_id",
            },
        )?;
        Ok(Self(merchant_ref_id))
    }
}

crate::global_id_type!(
    GlobalAttemptId,
    "A global id that can be used to identify a payment attempt"
);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalAttemptId);
crate::impl_to_sql_from_sql_global_id_type!(GlobalAttemptId);

impl GlobalAttemptId {
    /// Generate a new GlobalAttemptId from a cell id
    pub fn generate(cell_id: &super::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Attempt);
        Self(global_id)
    }

    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Generate the id for Revenue Recovery Psync PT workflow
    pub fn get_psync_revenue_recovery_id(
        &self,
        task: &str,
        runner: enums::ProcessTrackerRunner,
    ) -> String {
        format!("{runner}_{task}_{}", self.get_string_repr())
    }
}

impl TryFrom<std::borrow::Cow<'static, str>> for GlobalAttemptId {
    type Error = error_stack::Report<errors::ValidationError>;
    fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
        let global_attempt_id = super::GlobalId::from_string(value).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "payment_id",
            },
        )?;
        Ok(Self(global_attempt_id))
    }
}

crate::global_id_type!(
    GlobalAttemptGroupId,
    "A global id that can be used to identify a payment attempt group"
);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalAttemptGroupId);
crate::impl_to_sql_from_sql_global_id_type!(GlobalAttemptGroupId);

impl GlobalAttemptGroupId {
    /// Generate a new GlobalAttemptId from a cell id
    pub fn generate(cell_id: &super::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::AttemptGroup);
        Self(global_id)
    }

    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }
}

impl TryFrom<std::borrow::Cow<'static, str>> for GlobalAttemptGroupId {
    type Error = error_stack::Report<errors::ValidationError>;
    fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
        let global_attempt_group_id = super::GlobalId::from_string(value).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "global_attempt_group_id",
            },
        )?;
        Ok(Self(global_attempt_group_id))
    }
}


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

use crate::errors;

crate::global_id_type!(
    GlobalCustomerId,
    "A global id that can be used to identify a customer.

The format will be `<cell_id>_<entity_prefix>_<time_ordered_id>`.

Example: `cell1_cus_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p`"
);

// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalCustomerId);
crate::impl_to_sql_from_sql_global_id_type!(GlobalCustomerId);

impl GlobalCustomerId {
    /// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }

    /// Generate a new GlobalCustomerId from a cell id
    pub fn generate(cell_id: &crate::id_type::CellId) -> Self {
        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Customer);
        Self(global_id)
    }
}

impl TryFrom<GlobalCustomerId> for crate::id_type::CustomerId {
    type Error = error_stack::Report<errors::ValidationError>;

    fn try_from(value: GlobalCustomerId) -> Result<Self, Self::Error> {
        Self::try_from(std::borrow::Cow::from(value.get_string_repr().to_owned()))
    }
}

impl crate::events::ApiEventMetric for GlobalCustomerId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Customer {
            customer_id: Some(self.clone()),
        })
    }
}


// File: crates/hyperswitch_domain_models/Cargo.toml

[package]
name = "hyperswitch_domain_models"
description = "Represents the data/domain models used by the business layer"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
readme = "README.md"
license.workspace = true

[features]
default = ["olap", "frm"]
encryption_service = []
olap = []
payouts = ["api_models/payouts"]
frm = ["api_models/frm"]
v2 = ["api_models/v2", "diesel_models/v2", "common_utils/v2", "common_types/v2", "payment_link/v2"]
v1 = ["api_models/v1", "diesel_models/v1", "common_utils/v1", "common_types/v1", "payment_link/v1"]
tokenization_v2 = ["api_models/tokenization_v2", "diesel_models/tokenization_v2"]
dummy_connector = []
revenue_recovery= []

[dependencies]
# First party deps
api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] }
cards = { version = "0.1.0", path = "../cards" }
common_enums = { version = "0.1.0", path = "../common_enums" }
common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext", "metrics", "encryption_service", "keymanager"] }
common_types = { version = "0.1.0", path = "../common_types" }
diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store"], default-features = false }
masking = { version = "0.1.0", path = "../masking" }
payment_link = { version = "0.1.0", path = "../payment_link", default-features = false }
router_derive = { version = "0.1.0", path = "../router_derive" }
router_env = { version = "0.1.0", path = "../router_env" }

# Third party deps
actix-web = "4.11.0"
async-trait = "0.1.88"
error-stack = "0.4.1"
futures = "0.3.31"
http = "0.2.12"
mime = "0.3.17"
rustc-hash = "1.1.0"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
serde_with = "3.12.0"
time = { version = "0.3.41", features = ["serde", "serde-well-known", "std"] }
url = { version = "2.5.4", features = ["serde"] }
utoipa = { version = "4.2.3", features = ["preserve_order", "preserve_path_order", "time"] }

[lints]
workspace = true


// File: crates/hyperswitch_domain_models/README.md

# Hyperswitch domain models

Represents the data/domain models used by the business/domain layer


// File: crates/hyperswitch_domain_models/src/tokenization.rs

use common_utils::{
    self, date_time,
    errors::{CustomResult, ValidationError},
    types::keymanager,
};
use masking::Secret;
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Tokenization {
    pub id: common_utils::id_type::GlobalTokenId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::GlobalCustomerId,
    pub locker_id: String,
    pub created_at: PrimitiveDateTime,
    pub updated_at: PrimitiveDateTime,
    pub flag: common_enums::TokenizationFlag,
    pub version: common_enums::ApiVersion,
}

impl Tokenization {
    pub fn is_disabled(&self) -> bool {
        self.flag == common_enums::TokenizationFlag::Disabled
    }
}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenizationNew {
    pub id: common_utils::id_type::GlobalTokenId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::GlobalCustomerId,
    pub locker_id: String,
    pub flag: common_enums::TokenizationFlag,
    pub version: common_enums::ApiVersion,
}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenizationResponse {
    pub token: String,
    pub created_at: PrimitiveDateTime,
    pub flag: common_enums::TokenizationFlag,
}

impl From<Tokenization> for TokenizationResponse {
    fn from(value: Tokenization) -> Self {
        Self {
            token: value.id.get_string_repr().to_string(),
            created_at: value.created_at,
            flag: value.flag,
        }
    }
}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum TokenizationUpdate {
    DeleteTokenizationRecordUpdate {
        flag: Option<common_enums::enums::TokenizationFlag>,
    },
}

#[async_trait::async_trait]
impl super::behaviour::Conversion for Tokenization {
    type DstType = diesel_models::tokenization::Tokenization;
    type NewDstType = diesel_models::tokenization::Tokenization;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        Ok(diesel_models::tokenization::Tokenization {
            id: self.id,
            merchant_id: self.merchant_id,
            customer_id: self.customer_id,
            locker_id: self.locker_id,
            created_at: self.created_at,
            updated_at: self.updated_at,
            version: self.version,
            flag: self.flag,
        })
    }

    async fn convert_back(
        _state: &keymanager::KeyManagerState,
        item: Self::DstType,
        _key: &Secret<Vec<u8>>,
        _key_manager_identifier: keymanager::Identifier,
    ) -> CustomResult<Self, ValidationError> {
        Ok(Self {
            id: item.id,
            merchant_id: item.merchant_id,
            customer_id: item.customer_id,
            locker_id: item.locker_id,
            created_at: item.created_at,
            updated_at: item.updated_at,
            flag: item.flag,
            version: item.version,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        Ok(diesel_models::tokenization::Tokenization {
            id: self.id,
            merchant_id: self.merchant_id,
            customer_id: self.customer_id,
            locker_id: self.locker_id,
            created_at: self.created_at,
            updated_at: self.updated_at,
            version: self.version,
            flag: self.flag,
        })
    }
}

impl From<TokenizationUpdate> for diesel_models::tokenization::TokenizationUpdateInternal {
    fn from(value: TokenizationUpdate) -> Self {
        let now = date_time::now();
        match value {
            TokenizationUpdate::DeleteTokenizationRecordUpdate { flag } => Self {
                updated_at: now,
                flag,
            },
        }
    }
}


// File: crates/hyperswitch_domain_models/src/ext_traits.rs

use common_utils::{
    errors::{self, CustomResult},
    ext_traits::ValueExt,
    fp_utils::when,
};
use error_stack::ResultExt;

use crate::errors::api_error_response;

pub type DomainResult<T> = CustomResult<T, api_error_response::ApiErrorResponse>;
pub trait OptionExt<T> {
    fn check_value_present(&self, field_name: &'static str) -> DomainResult<()>;

    fn get_required_value(self, field_name: &'static str) -> DomainResult<T>;

    fn parse_enum<E>(self, enum_name: &'static str) -> CustomResult<E, errors::ParsingError>
    where
        T: AsRef<str>,
        E: std::str::FromStr,
        // Requirement for converting the `Err` variant of `FromStr` to `Report<Err>`
        <E as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static;

    fn parse_value<U>(self, type_name: &'static str) -> CustomResult<U, errors::ParsingError>
    where
        T: ValueExt,
        U: serde::de::DeserializeOwned;

    fn update_value(&mut self, value: Option<T>);
}

impl<T> OptionExt<T> for Option<T> {
    fn check_value_present(&self, field_name: &'static str) -> DomainResult<()> {
        when(self.is_none(), || {
            Err(error_stack::Report::new(
                api_error_response::ApiErrorResponse::MissingRequiredField { field_name },
            )
            .attach_printable(format!("Missing required field {field_name}")))
        })
    }

    // This will allow the error message that was generated in this function to point to the call site
    #[track_caller]
    fn get_required_value(self, field_name: &'static str) -> DomainResult<T> {
        match self {
            Some(v) => Ok(v),
            None => Err(error_stack::Report::new(
                api_error_response::ApiErrorResponse::MissingRequiredField { field_name },
            )
            .attach_printable(format!("Missing required field {field_name}"))),
        }
    }

    fn parse_enum<E>(self, enum_name: &'static str) -> CustomResult<E, errors::ParsingError>
    where
        T: AsRef<str>,
        E: std::str::FromStr,
        <E as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
    {
        let value = self
            .get_required_value(enum_name)
            .change_context(errors::ParsingError::UnknownError)?;

        E::from_str(value.as_ref())
            .change_context(errors::ParsingError::UnknownError)
            .attach_printable_lazy(|| format!("Invalid {{ {enum_name} }} "))
    }

    fn parse_value<U>(self, type_name: &'static str) -> CustomResult<U, errors::ParsingError>
    where
        T: ValueExt,
        U: serde::de::DeserializeOwned,
    {
        let value = self
            .get_required_value(type_name)
            .change_context(errors::ParsingError::UnknownError)?;
        value.parse_value(type_name)
    }

    fn update_value(&mut self, value: Self) {
        if let Some(a) = value {
            *self = Some(a)
        }
    }
}


// File: crates/hyperswitch_domain_models/src/consts.rs

//! Constants that are used in the domain models.

use std::{collections::HashSet, sync::LazyLock};

pub static ROUTING_ENABLED_PAYMENT_METHODS: LazyLock<HashSet<common_enums::PaymentMethod>> =
    LazyLock::new(|| {
        let mut set = HashSet::new();
        set.insert(common_enums::PaymentMethod::BankTransfer);
        set.insert(common_enums::PaymentMethod::BankDebit);
        set.insert(common_enums::PaymentMethod::BankRedirect);
        set
    });

pub static ROUTING_ENABLED_PAYMENT_METHOD_TYPES: LazyLock<
    HashSet<common_enums::PaymentMethodType>,
> = LazyLock::new(|| {
    let mut set = HashSet::new();
    set.insert(common_enums::PaymentMethodType::GooglePay);
    set.insert(common_enums::PaymentMethodType::ApplePay);
    set.insert(common_enums::PaymentMethodType::Klarna);
    set.insert(common_enums::PaymentMethodType::Paypal);
    set.insert(common_enums::PaymentMethodType::SamsungPay);
    set
});

/// Length of the unique reference ID generated for connector mandate requests
pub const CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH: usize = 18;