                    VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data)
                }
                Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => {
                    VaultFetchAction::FetchCardDetailsForNetworkTransactionIdFlowFromLocker
                }
                Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) | None => {
                    VaultFetchAction::NoFetchAction
                }
            },
            None => {
                //saved card flow
                let is_network_token_supported_connector = connector
                    .map(|conn| network_tokenization_supported_connectors.contains(&conn))
                    .unwrap_or(false);

                match (
                    is_network_token_supported_connector,
                    network_token_requestor_ref_id,
                ) {
                    (true, Some(ref_id)) => {
                        VaultFetchAction::FetchNetworkTokenDataFromTokenizationService(ref_id)
                    }
                    (false, Some(_)) | (true, None) | (false, None) => {
                        VaultFetchAction::FetchCardDetailsFromLocker
                    }
                }
            }
        }
    }
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn retrieve_payment_method_data_with_permanent_token(
    state: &SessionState,
    locker_id: &str,
    _payment_method_id: &str,
    payment_intent: &PaymentIntent,
    card_token_data: Option<&domain::CardToken>,
    merchant_key_store: &domain::MerchantKeyStore,
    _storage_scheme: enums::MerchantStorageScheme,
    mandate_id: Option<api_models::payments::MandateIds>,
    payment_method_info: domain::PaymentMethod,
    business_profile: &domain::Profile,
    connector: Option<String>,
    should_retry_with_pan: bool,
    vault_data: Option<&domain_payments::VaultData>,
) -> RouterResult<domain::PaymentMethodData> {
    let customer_id = payment_intent
        .customer_id
        .as_ref()
        .get_required_value("customer_id")
        .change_context(errors::ApiErrorResponse::UnprocessableEntity {
            message: "no customer id provided for the payment".to_string(),
        })?;

    let network_tokenization_supported_connectors = &state
        .conf
        .network_tokenization_supported_connectors
        .connector_list;

    let connector_variant = connector
        .as_ref()
        .map(|conn| {
            api_enums::Connector::from_str(conn.as_str())
                .change_context(errors::ApiErrorResponse::InvalidDataValue {
                    field_name: "connector",
                })
                .attach_printable_lazy(|| format!("unable to parse connector name {connector:?}"))
        })
        .transpose()?;

    let vault_fetch_action = decide_payment_method_retrieval_action(
        business_profile.is_network_tokenization_enabled,
        mandate_id,
        connector_variant,
        network_tokenization_supported_connectors,
        should_retry_with_pan,
        payment_method_info
            .network_token_requestor_reference_id
            .clone(),
    );

    let co_badged_card_data = payment_method_info
        .get_payment_methods_data()
        .and_then(|payment_methods_data| payment_methods_data.get_co_badged_card_data());

    match vault_fetch_action {
        VaultFetchAction::FetchCardDetailsFromLocker => {
            let card = vault_data
                .and_then(|vault_data| vault_data.get_card_vault_data())
                .map(Ok)
                .async_unwrap_or_else(|| async {
                    Box::pin(fetch_card_details_from_locker(
                        state,
                        customer_id,
                        &payment_intent.merchant_id,
                        locker_id,
                        card_token_data,
                        co_badged_card_data,
                        payment_method_info,
                        merchant_key_store,
                    ))
                    .await
                })
                .await?;

            Ok(domain::PaymentMethodData::Card(card))
        }
        VaultFetchAction::FetchCardDetailsForNetworkTransactionIdFlowFromLocker => {
            fetch_card_details_for_network_transaction_flow_from_locker(
                state,
                customer_id,
                &payment_intent.merchant_id,
                locker_id,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to fetch card information from the permanent locker")
        }
        VaultFetchAction::FetchNetworkTokenDataFromTokenizationService(
            network_token_requestor_ref_id,
        ) => {
            logger::info!("Fetching network token data from tokenization service");
            match network_tokenization::get_token_from_tokenization_service(
                state,
                network_token_requestor_ref_id,
                &payment_method_info,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to fetch network token data from tokenization service")
            {
                Ok(network_token_data) => {
                    Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
                }
                Err(err) => {
                    logger::info!(
                        "Failed to fetch network token data from tokenization service {err:?}"
                    );
                    logger::info!("Falling back to fetch card details from locker");
                    Ok(domain::PaymentMethodData::Card(
                        vault_data
                            .and_then(|vault_data| vault_data.get_card_vault_data())
                            .map(Ok)
                            .async_unwrap_or_else(|| async {
                                Box::pin(fetch_card_details_from_locker(
                                    state,
                                    customer_id,
                                    &payment_intent.merchant_id,
                                    locker_id,
                                    card_token_data,
                                    co_badged_card_data,
                                    payment_method_info,
                                    merchant_key_store,
                                ))
                                .await
                            })
                            .await?,
                    ))
                }
            }
        }
        VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) => {
            if let Some(network_token_locker_id) =
                payment_method_info.network_token_locker_id.as_ref()
            {
                let network_token_data = vault_data
                    .and_then(|vault_data| vault_data.get_network_token_data())
                    .map(Ok)
                    .async_unwrap_or_else(|| async {
                        fetch_network_token_details_from_locker(
                            state,
                            customer_id,
                            &payment_intent.merchant_id,
                            network_token_locker_id,
                            nt_data,
                        )
                        .await
                    })
                    .await?;
                Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
            } else {
                Err(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Network token locker id is not present")
            }
        }
        VaultFetchAction::NoFetchAction => Err(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Payment method data is not present"),
    }
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn retrieve_card_with_permanent_token_for_external_authentication(
    state: &SessionState,
    locker_id: &str,
    payment_intent: &PaymentIntent,
    card_token_data: Option<&domain::CardToken>,
    _merchant_key_store: &domain::MerchantKeyStore,
    _storage_scheme: enums::MerchantStorageScheme,
) -> RouterResult<domain::PaymentMethodData> {
    let customer_id = payment_intent
        .customer_id
        .as_ref()
        .get_required_value("customer_id")
        .change_context(errors::ApiErrorResponse::UnprocessableEntity {
            message: "no customer id provided for the payment".to_string(),
        })?;
    Ok(domain::PaymentMethodData::Card(
        fetch_card_details_from_internal_locker(
            state,
            customer_id,
            &payment_intent.merchant_id,
            locker_id,
            card_token_data,
            None,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("failed to fetch card information from the permanent locker")?,
    ))
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn fetch_card_details_from_locker(
    state: &SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    locker_id: &str,
    card_token_data: Option<&domain::CardToken>,
    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
    payment_method_info: domain::PaymentMethod,
    merchant_key_store: &domain::MerchantKeyStore,
) -> RouterResult<domain::Card> {
    match &payment_method_info.vault_source_details.clone() {
        domain::PaymentMethodVaultSourceDetails::ExternalVault {
            ref external_vault_source,
        } => {
            fetch_card_details_from_external_vault(
                state,
                merchant_id,
                card_token_data,
                co_badged_card_data,
                payment_method_info,
                merchant_key_store,
                external_vault_source,
            )
            .await
        }
        domain::PaymentMethodVaultSourceDetails::InternalVault => {
            fetch_card_details_from_internal_locker(
                state,
                customer_id,
                merchant_id,
                locker_id,
                card_token_data,
                co_badged_card_data,
            )
            .await
        }
    }
}

#[cfg(feature = "v1")]
pub async fn fetch_card_details_from_internal_locker(
    state: &SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    locker_id: &str,
    card_token_data: Option<&domain::CardToken>,
    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
) -> RouterResult<domain::Card> {
    logger::debug!("Fetching card details from locker");
    let card = cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("failed to fetch card information from the permanent locker")?;

    // The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
    // from payment_method_data.card_token object
    let name_on_card = if let Some(name) = card.name_on_card.clone() {
        if name.clone().expose().is_empty() {
            card_token_data
                .and_then(|token_data| token_data.card_holder_name.clone())
                .or(Some(name))
        } else {
            card.name_on_card
        }
    } else {
        card_token_data.and_then(|token_data| token_data.card_holder_name.clone())
    };

    let api_card = api::Card {
        card_number: card.card_number,
        card_holder_name: name_on_card,
        card_exp_month: card.card_exp_month,
        card_exp_year: card.card_exp_year,
        card_cvc: card_token_data
            .cloned()
            .unwrap_or_default()
            .card_cvc
            .unwrap_or_default(),
        card_issuer: None,
        nick_name: card.nick_name.map(masking::Secret::new),
        card_network: card
            .card_brand
            .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
            .transpose()
            .map_err(|e| {
                logger::error!("Failed to parse card network {e:?}");
            })
            .ok()
            .flatten(),
        card_type: None,
        card_issuing_country: None,
        bank_code: None,
    };
    Ok(domain::Card::from((api_card, co_badged_card_data)))
}

#[cfg(feature = "v1")]
pub async fn fetch_card_details_from_external_vault(
    state: &SessionState,
    merchant_id: &id_type::MerchantId,
    card_token_data: Option<&domain::CardToken>,
    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
    payment_method_info: domain::PaymentMethod,
    merchant_key_store: &domain::MerchantKeyStore,
    external_vault_mca_id: &id_type::MerchantConnectorAccountId,
) -> RouterResult<domain::Card> {
    let key_manager_state = &state.into();

    let merchant_connector_account_details = state
        .store
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            merchant_id,
            external_vault_mca_id,
            merchant_key_store,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: external_vault_mca_id.get_string_repr().to_string(),
        })?;

    let vault_resp = vault::retrieve_payment_method_from_vault_external_v1(
        state,
        merchant_id,
        &payment_method_info,
        merchant_connector_account_details,
    )
    .await?;

    let payment_methods_data = payment_method_info.get_payment_methods_data();

    match vault_resp {
        hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card) => Ok(
            domain::Card::from((card, card_token_data, co_badged_card_data)),
        ),
        hyperswitch_domain_models::vault::PaymentMethodVaultingData::CardNumber(card_number) => {
            let payment_methods_data = payment_methods_data
                .get_required_value("PaymentMethodsData")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Payment methods data not present")?;

            let card = payment_methods_data
                .get_card_details()
                .get_required_value("CardDetails")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Card details not present")?;

            Ok(
                domain::Card::try_from((card_number, card_token_data, co_badged_card_data, card))
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to generate card data")?,
            )
        }
    }
}
#[cfg(feature = "v1")]
pub async fn fetch_network_token_details_from_locker(
    state: &SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    network_token_locker_id: &str,
    network_transaction_data: api_models::payments::NetworkTokenWithNTIRef,
) -> RouterResult<domain::NetworkTokenData> {
    let mut token_data =
        cards::get_card_from_locker(state, customer_id, merchant_id, network_token_locker_id)
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "failed to fetch network token information from the permanent locker",
            )?;
    let expiry = network_transaction_data
        .token_exp_month
        .zip(network_transaction_data.token_exp_year);
    if let Some((exp_month, exp_year)) = expiry {
        token_data.card_exp_month = exp_month;
        token_data.card_exp_year = exp_year;
    }

    let card_network = token_data
        .card_brand
        .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
        .transpose()
        .map_err(|e| {
            logger::error!("Failed to parse card network {e:?}");
        })
        .ok()
        .flatten();

    let network_token_data = domain::NetworkTokenData {
        token_number: token_data.card_number,
        token_cryptogram: None,
        token_exp_month: token_data.card_exp_month,
        token_exp_year: token_data.card_exp_year,
        nick_name: token_data.nick_name.map(masking::Secret::new),
        card_issuer: None,
        card_network,
        card_type: None,
        card_issuing_country: None,
        bank_code: None,
        eci: None,
    };
    Ok(network_token_data)
}

#[cfg(feature = "v1")]
pub async fn fetch_card_details_for_network_transaction_flow_from_locker(
    state: &SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    locker_id: &str,
) -> RouterResult<domain::PaymentMethodData> {
    let card_details_from_locker =
        cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to fetch card details from locker")?;

    let card_network = card_details_from_locker
        .card_brand
        .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
        .transpose()
        .map_err(|e| {
            logger::error!("Failed to parse card network {e:?}");
        })
        .ok()
        .flatten();

    let card_details_for_network_transaction_id =
        hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId {
            card_number: card_details_from_locker.card_number,
            card_exp_month: card_details_from_locker.card_exp_month,
            card_exp_year: card_details_from_locker.card_exp_year,
            card_issuer: None,
            card_network,
            card_type: None,
            card_issuing_country: None,
            bank_code: None,
            nick_name: card_details_from_locker.nick_name.map(masking::Secret::new),
            card_holder_name: card_details_from_locker.name_on_card.clone(),
        };

    Ok(
        domain::PaymentMethodData::CardDetailsForNetworkTransactionId(
            card_details_for_network_transaction_id,
        ),
    )
}

#[cfg(feature = "v2")]
pub async fn retrieve_payment_method_from_db_with_token_data(
    state: &SessionState,
    merchant_key_store: &domain::MerchantKeyStore,
    token_data: &storage::PaymentTokenData,
    storage_scheme: storage::enums::MerchantStorageScheme,
) -> RouterResult<Option<domain::PaymentMethod>> {
    todo!()
}

#[cfg(feature = "v1")]
pub async fn retrieve_payment_method_from_db_with_token_data(
    state: &SessionState,
    merchant_key_store: &domain::MerchantKeyStore,
    token_data: &storage::PaymentTokenData,
    storage_scheme: storage::enums::MerchantStorageScheme,
) -> RouterResult<Option<domain::PaymentMethod>> {
    match token_data {
        storage::PaymentTokenData::PermanentCard(data) => {
            if let Some(ref payment_method_id) = data.payment_method_id {
                state
                    .store
                    .find_payment_method(
                        &(state.into()),
                        merchant_key_store,
                        payment_method_id,
                        storage_scheme,
                    )
                    .await
                    .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)
                    .attach_printable("error retrieving payment method from DB")
                    .map(Some)
            } else {
                Ok(None)
            }
        }

        storage::PaymentTokenData::WalletToken(data) => state
            .store
            .find_payment_method(
                &(state.into()),
                merchant_key_store,
                &data.payment_method_id,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)
            .attach_printable("error retrieveing payment method from DB")
            .map(Some),

        storage::PaymentTokenData::Temporary(_)
        | storage::PaymentTokenData::TemporaryGeneric(_)
        | storage::PaymentTokenData::Permanent(_)
        | storage::PaymentTokenData::AuthBankDebit(_) => Ok(None),
    }
}

#[cfg(feature = "v1")]
pub async fn retrieve_payment_token_data(
    state: &SessionState,
    token: String,
    payment_method: Option<storage_enums::PaymentMethod>,
) -> RouterResult<storage::PaymentTokenData> {
    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get redis connection")?;

    let key = format!(
        "pm_token_{}_{}_hyperswitch",
        token,
        payment_method.get_required_value("payment_method")?
    );

    let token_data_string = redis_conn
        .get_key::<Option<String>>(&key.into())
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to fetch the token from redis")?
        .ok_or(error_stack::Report::new(
            errors::ApiErrorResponse::UnprocessableEntity {
                message: "Token is invalid or expired".to_owned(),
            },
        ))?;

    let token_data_result = token_data_string
        .clone()
        .parse_struct("PaymentTokenData")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("failed to deserialize hyperswitch token data");

    let token_data = match token_data_result {
        Ok(data) => data,
        Err(e) => {
            // The purpose of this logic is backwards compatibility to support tokens
            // in redis that might be following the old format.
            if token_data_string.starts_with('{') {
                return Err(e);
            } else {
                storage::PaymentTokenData::temporary_generic(token_data_string)
            }
        }
    };

    Ok(token_data)
}

#[cfg(feature = "v2")]
pub async fn make_pm_data<'a, F: Clone, R, D>(
    _operation: BoxedOperation<'a, F, R, D>,
    _state: &'a SessionState,
    _payment_data: &mut PaymentData<F>,
    _merchant_key_store: &domain::MerchantKeyStore,
    _customer: &Option<domain::Customer>,
    _storage_scheme: common_enums::enums::MerchantStorageScheme,
    _business_profile: Option<&domain::Profile>,
) -> RouterResult<(
    BoxedOperation<'a, F, R, D>,
    Option<domain::PaymentMethodData>,
    Option<String>,
)> {
    todo!()
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn make_pm_data<'a, F: Clone, R, D>(
    operation: BoxedOperation<'a, F, R, D>,
    state: &'a SessionState,
    payment_data: &mut PaymentData<F>,
    merchant_key_store: &domain::MerchantKeyStore,
    customer: &Option<domain::Customer>,
    storage_scheme: common_enums::enums::MerchantStorageScheme,
    business_profile: &domain::Profile,
    should_retry_with_pan: bool,
) -> RouterResult<(
    BoxedOperation<'a, F, R, D>,
    Option<domain::PaymentMethodData>,
    Option<String>,
)> {
    use super::OperationSessionSetters;
    use crate::core::payments::OperationSessionGetters;

    let request = payment_data.payment_method_data.clone();

    let mut card_token_data = payment_data
        .payment_method_data
        .clone()
        .and_then(|pmd| match pmd {
            domain::PaymentMethodData::CardToken(token_data) => Some(token_data),
            _ => None,
        })
        .or(Some(domain::CardToken::default()));

    if let Some(cvc) = payment_data.card_cvc.clone() {
        if let Some(token_data) = card_token_data.as_mut() {
            token_data.card_cvc = Some(cvc);
        }
    }

    if payment_data.token_data.is_none() {
        if let Some(payment_method_info) = &payment_data.payment_method_info {
            if payment_method_info.get_payment_method_type()
                == Some(storage_enums::PaymentMethod::Card)
            {
                payment_data.token_data =
                    Some(storage::PaymentTokenData::PermanentCard(CardTokenData {
                        payment_method_id: Some(payment_method_info.get_id().clone()),
                        locker_id: payment_method_info
                            .locker_id
                            .clone()
                            .or(Some(payment_method_info.get_id().clone())),
                        token: payment_method_info
                            .locker_id
                            .clone()
                            .unwrap_or(payment_method_info.get_id().clone()),
                        network_token_locker_id: payment_method_info
                            .network_token_requestor_reference_id
                            .clone()
                            .or(Some(payment_method_info.get_id().clone())),
                    }));
            }
        }
    }

    let mandate_id = payment_data.mandate_id.clone();

    // TODO: Handle case where payment method and token both are present in request properly.
    let (payment_method, pm_id) = match (&request, payment_data.token_data.as_ref()) {
        (_, Some(hyperswitch_token)) => {
            let existing_vault_data = payment_data.get_vault_operation();

            let vault_data = existing_vault_data.and_then(|data| match data {
                domain_payments::VaultOperation::ExistingVaultData(vault_data) => Some(vault_data),
                domain_payments::VaultOperation::SaveCardData(_)
                | domain_payments::VaultOperation::SaveCardAndNetworkTokenData(_) => None,
            });

            let pm_data = Box::pin(payment_methods::retrieve_payment_method_with_token(
                state,
                merchant_key_store,
                hyperswitch_token,
                &payment_data.payment_intent,
                &payment_data.payment_attempt,
                card_token_data.as_ref(),
                customer,
                storage_scheme,
                mandate_id,
                payment_data.payment_method_info.clone(),
                business_profile,
                should_retry_with_pan,
                vault_data,
            ))
            .await;

            let payment_method_details = pm_data.attach_printable("in 'make_pm_data'")?;

            if let Some(ref payment_method_data) = payment_method_details.payment_method_data {
                let updated_vault_operation =
                    domain_payments::VaultOperation::get_updated_vault_data(
                        existing_vault_data,
                        payment_method_data,
                    );

                if let Some(vault_operation) = updated_vault_operation {
                    payment_data.set_vault_operation(vault_operation);
                }

                // Temporarily store payment method data along with the cvc in redis for saved card payments, if required by the connector based on its configs
                if payment_data.token.is_none() {
                    let (_, payment_token) = payment_methods::retrieve_payment_method_core(
                        &Some(payment_method_data.clone()),
                        state,
                        &payment_data.payment_intent,
                        &payment_data.payment_attempt,
                        merchant_key_store,
                        Some(business_profile),
                    )
                    .await?;

                    payment_data.token = payment_token;
                }
            };

            Ok::<_, error_stack::Report<errors::ApiErrorResponse>>(
                if let Some(payment_method_data) = payment_method_details.payment_method_data {
                    payment_data.payment_attempt.payment_method =
                        payment_method_details.payment_method;
                    (
                        Some(payment_method_data),
                        payment_method_details.payment_method_id,
                    )
                } else {
                    (None, payment_method_details.payment_method_id)
                },
            )
        }

        (Some(_), _) => {
            let (payment_method_data, payment_token) =
                payment_methods::retrieve_payment_method_core(
                    &request,
                    state,
                    &payment_data.payment_intent,
                    &payment_data.payment_attempt,
                    merchant_key_store,
                    Some(business_profile),
                )
                .await?;

            payment_data.token = payment_token;

            Ok((payment_method_data, None))
        }
        _ => Ok((None, None)),
    }?;

    Ok((operation, payment_method, pm_id))
}

#[cfg(feature = "v1")]
pub async fn store_in_vault_and_generate_ppmt(
    state: &SessionState,
    payment_method_data: &domain::PaymentMethodData,
    payment_intent: &PaymentIntent,
    payment_attempt: &PaymentAttempt,
    payment_method: enums::PaymentMethod,
    merchant_key_store: &domain::MerchantKeyStore,
    business_profile: Option<&domain::Profile>,
) -> RouterResult<String> {
    let router_token = vault::Vault::store_payment_method_data_in_locker(
        state,
        None,
        payment_method_data,
        payment_intent.customer_id.to_owned(),
        payment_method,
        merchant_key_store,
    )
    .await?;
    let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");
    let key_for_hyperswitch_token = payment_attempt.get_payment_method().map(|payment_method| {
        payment_methods_handler::ParentPaymentMethodToken::create_key_for_token((
            &parent_payment_method_token,
            payment_method,
        ))
    });

    let intent_fulfillment_time = business_profile
        .and_then(|b_profile| b_profile.get_order_fulfillment_time())
        .unwrap_or(consts::DEFAULT_FULFILLMENT_TIME);

    if let Some(key_for_hyperswitch_token) = key_for_hyperswitch_token {
        key_for_hyperswitch_token
            .insert(
                intent_fulfillment_time,
                storage::PaymentTokenData::temporary_generic(router_token),
                state,
            )
            .await?;
    };
    Ok(parent_payment_method_token)
}

#[cfg(feature = "v2")]
pub async fn store_payment_method_data_in_vault(
    state: &SessionState,
    payment_attempt: &PaymentAttempt,
    payment_intent: &PaymentIntent,
    payment_method: enums::PaymentMethod,
    payment_method_data: &domain::PaymentMethodData,
    merchant_key_store: &domain::MerchantKeyStore,
    business_profile: Option<&domain::Profile>,
) -> RouterResult<Option<String>> {
    todo!()
}

#[cfg(feature = "v1")]
pub async fn store_payment_method_data_in_vault(
    state: &SessionState,
    payment_attempt: &PaymentAttempt,
    payment_intent: &PaymentIntent,
    payment_method: enums::PaymentMethod,
    payment_method_data: &domain::PaymentMethodData,
    merchant_key_store: &domain::MerchantKeyStore,
    business_profile: Option<&domain::Profile>,
) -> RouterResult<Option<String>> {
    if should_store_payment_method_data_in_vault(
        &state.conf.temp_locker_enable_config,
        payment_attempt.connector.clone(),
        payment_method,
    ) || payment_intent.request_external_three_ds_authentication == Some(true)
    {
        let parent_payment_method_token = store_in_vault_and_generate_ppmt(
            state,
            payment_method_data,
            payment_intent,
            payment_attempt,
            payment_method,
            merchant_key_store,
            business_profile,
        )
        .await?;

        return Ok(Some(parent_payment_method_token));
    }

    Ok(None)
}
pub fn should_store_payment_method_data_in_vault(
    temp_locker_enable_config: &TempLockerEnableConfig,
    option_connector: Option<String>,
    payment_method: enums::PaymentMethod,
) -> bool {
    option_connector
        .map(|connector| {
            temp_locker_enable_config
                .0
                .get(&connector)
                .map(|config| config.payment_method.contains(&payment_method))
                .unwrap_or(false)
        })
        .unwrap_or(true)
}

#[instrument(skip_all)]
pub(crate) fn validate_capture_method(
    capture_method: storage_enums::CaptureMethod,
) -> RouterResult<()> {
    utils::when(
        capture_method == storage_enums::CaptureMethod::Automatic,
        || {
            Err(report!(errors::ApiErrorResponse::PaymentUnexpectedState {
                field_name: "capture_method".to_string(),
                current_flow: "captured".to_string(),
                current_value: capture_method.to_string(),
                states: "manual, manual_multiple, scheduled".to_string()
            }))
        },
    )
}

#[instrument(skip_all)]
pub(crate) fn validate_status_with_capture_method(
    status: storage_enums::IntentStatus,
    capture_method: storage_enums::CaptureMethod,
) -> RouterResult<()> {
    if status == storage_enums::IntentStatus::Processing
        && !(capture_method == storage_enums::CaptureMethod::ManualMultiple)
    {
        return Err(report!(errors::ApiErrorResponse::PaymentUnexpectedState {
            field_name: "capture_method".to_string(),
            current_flow: "captured".to_string(),
            current_value: capture_method.to_string(),
            states: "manual_multiple".to_string()
        }));
    }
    utils::when(
        status != storage_enums::IntentStatus::RequiresCapture
            && status != storage_enums::IntentStatus::PartiallyCapturedAndCapturable
            && status != storage_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture
            && status != storage_enums::IntentStatus::Processing,
        || {
            Err(report!(errors::ApiErrorResponse::PaymentUnexpectedState {
                field_name: "payment.status".to_string(),
                current_flow: "captured".to_string(),
                current_value: status.to_string(),
                states: "requires_capture, partially_captured_and_capturable, processing"
                    .to_string()
            }))
        },
    )
}

#[instrument(skip_all)]
pub(crate) fn validate_amount_to_capture(
    amount: i64,
    amount_to_capture: Option<i64>,
) -> RouterResult<()> {
    utils::when(amount_to_capture.is_some_and(|value| value <= 0), || {
        Err(report!(errors::ApiErrorResponse::InvalidDataFormat {
            field_name: "amount".to_string(),
            expected_format: "positive integer".to_string(),
        }))
    })?;

    utils::when(
        amount_to_capture.is_some() && (Some(amount) < amount_to_capture),
        || {
            Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                message: "amount_to_capture is greater than amount".to_string()
            }))
        },
    )
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub(crate) fn validate_payment_method_fields_present(
    req: &api_models::payments::PaymentsRequest,
) -> RouterResult<()> {
    let payment_method_data =
        req.payment_method_data
            .as_ref()
            .and_then(|request_payment_method_data| {
                request_payment_method_data.payment_method_data.as_ref()
            });
    utils::when(
        req.payment_method.is_none() && payment_method_data.is_some(),
        || {
            Err(errors::ApiErrorResponse::MissingRequiredField {
                field_name: "payment_method",
            })
        },
    )?;

    utils::when(
        !matches!(
            req.payment_method,
            Some(api_enums::PaymentMethod::Card) | None
        ) && (req.payment_method_type.is_none()),
        || {
            Err(errors::ApiErrorResponse::MissingRequiredField {
                field_name: "payment_method_type",
            })
        },
    )?;

    utils::when(
        req.payment_method.is_some()
            && payment_method_data.is_none()
            && req.payment_token.is_none()
            && req.recurring_details.is_none()
            && req.ctp_service_details.is_none(),
        || {
            Err(errors::ApiErrorResponse::MissingRequiredField {
                field_name: "payment_method_data",
            })
        },
    )?;

    utils::when(
        req.payment_method.is_some() && req.payment_method_type.is_some(),
        || {
            req.payment_method
                .map_or(Ok(()), |req_payment_method| {
                    req.payment_method_type.map_or(Ok(()), |req_payment_method_type| {
                        if !validate_payment_method_type_against_payment_method(req_payment_method, req_payment_method_type) {
                            Err(errors::ApiErrorResponse::InvalidRequestData {
                                message: ("payment_method_type doesn't correspond to the specified payment_method"
                                    .to_string()),
                            })
                        } else {
                            Ok(())
                        }
                    })
                })
        },
    )?;

    let validate_payment_method_and_payment_method_data =
        |req_payment_method_data, req_payment_method: api_enums::PaymentMethod| {
            api_enums::PaymentMethod::foreign_try_from(req_payment_method_data).and_then(|payment_method|
                if req_payment_method != payment_method {
                    Err(errors::ApiErrorResponse::InvalidRequestData {
                        message: ("payment_method_data doesn't correspond to the specified payment_method"
                            .to_string()),
                    })
                } else {
                    Ok(())
                })
        };

    utils::when(
        req.payment_method.is_some() && payment_method_data.is_some(),
        || {
            payment_method_data
                .cloned()
                .map_or(Ok(()), |payment_method_data| {
                    req.payment_method.map_or(Ok(()), |req_payment_method| {
                        validate_payment_method_and_payment_method_data(
                            payment_method_data,
                            req_payment_method,
                        )
                    })
                })
        },
    )?;

    Ok(())
}

pub fn check_force_psync_precondition(status: storage_enums::AttemptStatus) -> bool {
    !matches!(
        status,
        storage_enums::AttemptStatus::Charged
            | storage_enums::AttemptStatus::AutoRefunded
            | storage_enums::AttemptStatus::Voided
            | storage_enums::AttemptStatus::CodInitiated
            | storage_enums::AttemptStatus::Started
            | storage_enums::AttemptStatus::Failure
    )
}

pub fn append_option<T, U, F, V>(func: F, option1: Option<T>, option2: Option<U>) -> Option<V>
where
    F: FnOnce(T, U) -> V,
{
    Some(func(option1?, option2?))
}

#[cfg(all(feature = "olap", feature = "v1"))]
pub(super) async fn filter_by_constraints(
    state: &SessionState,
    constraints: &PaymentIntentFetchConstraints,
    merchant_id: &id_type::MerchantId,
    key_store: &domain::MerchantKeyStore,
    storage_scheme: storage_enums::MerchantStorageScheme,
) -> CustomResult<Vec<PaymentIntent>, errors::StorageError> {
    let db = &*state.store;
    let result = db
        .filter_payment_intent_by_constraints(
            &(state).into(),
            merchant_id,
            constraints,
            key_store,
            storage_scheme,
        )
        .await?;
    Ok(result)
}

#[cfg(feature = "olap")]
pub(super) fn validate_payment_list_request(
    req: &api::PaymentListConstraints,
) -> CustomResult<(), errors::ApiErrorResponse> {
    use common_utils::consts::PAYMENTS_LIST_MAX_LIMIT_V1;

    utils::when(
        req.limit > PAYMENTS_LIST_MAX_LIMIT_V1 || req.limit < 1,
        || {
            Err(errors::ApiErrorResponse::InvalidRequestData {
                message: format!("limit should be in between 1 and {PAYMENTS_LIST_MAX_LIMIT_V1}"),
            })
        },
    )?;
    Ok(())
}
#[cfg(feature = "olap")]
pub(super) fn validate_payment_list_request_for_joins(
    limit: u32,
) -> CustomResult<(), errors::ApiErrorResponse> {
    use common_utils::consts::PAYMENTS_LIST_MAX_LIMIT_V2;

    utils::when(!(1..=PAYMENTS_LIST_MAX_LIMIT_V2).contains(&limit), || {
        Err(errors::ApiErrorResponse::InvalidRequestData {
            message: format!("limit should be in between 1 and {PAYMENTS_LIST_MAX_LIMIT_V2}"),
        })
    })?;
    Ok(())
}


// Struct: IncrementalAuthorization
// File: crates/hyperswitch_domain_models/src/router_flow_types/payments.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct IncrementalAuthorization


// File: crates/hyperswitch_connectors/src/connectors/archipel/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 29

use bytes::Bytes;
use common_enums::{
    self, AttemptStatus, AuthorizationStatus, CaptureMethod, Currency, FutureUsage,
    PaymentMethodStatus, RefundStatus,
};
use common_utils::{date_time, ext_traits::Encode, pii, types::MinorUnit};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    address::AddressDetails,
    payment_method_data::{Card, PaymentMethodData, WalletData},
    router_data::{ConnectorAuthType, ErrorResponse, PaymentMethodToken, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{
        AuthenticationData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData,
        PaymentsIncrementalAuthorizationData, PaymentsSyncData, ResponseId,
        SetupMandateRequestData,
    },
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsIncrementalAuthorizationRouterData, RefundsRouterData, SetupMandateRouterData,
    },
};
use hyperswitch_interfaces::{consts, errors};
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    unimplemented_payment_method,
    utils::{
        self, AddressData, AddressDetailsData, CardData, CardIssuer, PaymentsAuthorizeRequestData,
        RouterData as _,
    },
};

const THREE_DS_MAX_SUPPORTED_VERSION: &str = "2.2.0";

#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)]
#[serde(transparent)]
pub struct ArchipelTenantId(pub String);

impl From<String> for ArchipelTenantId {
    fn from(value: String) -> Self {
        Self(value)
    }
}

pub struct ArchipelRouterData<T> {
    pub amount: MinorUnit,
    pub tenant_id: ArchipelTenantId,
    pub router_data: T,
}

impl<T> From<(MinorUnit, ArchipelTenantId, T)> for ArchipelRouterData<T> {
    fn from((amount, tenant_id, router_data): (MinorUnit, ArchipelTenantId, T)) -> Self {
        Self {
            amount,
            tenant_id,
            router_data,
        }
    }
}

pub struct ArchipelAuthType {
    pub(super) ca_certificate: Option<Secret<String>>,
}

impl TryFrom<&ConnectorAuthType> for ArchipelAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                ca_certificate: Some(api_key.to_owned()),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct ArchipelConfigData {
    pub tenant_id: ArchipelTenantId,
    pub platform_url: String,
}

impl TryFrom<&Option<pii::SecretSerdeValue>> for ArchipelConfigData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(connector_metadata: &Option<pii::SecretSerdeValue>) -> Result<Self, Self::Error> {
        let config_data = utils::to_connector_meta_from_secret::<Self>(connector_metadata.clone())
            .change_context(errors::ConnectorError::InvalidConnectorConfig {
                config: "metadata. Required fields: tenant_id, platform_url",
            })?;
        Ok(config_data)
    }
}

#[derive(Debug, Default, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum ArchipelPaymentInitiator {
    #[default]
    Customer,
    Merchant,
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ArchipelWalletProvider {
    ApplePay,
    GooglePay,
    SamsungPay,
}

#[derive(Debug, Default, Serialize, Eq, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum ArchipelPaymentCertainty {
    #[default]
    Final,
    Estimated,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelOrderRequest {
    amount: MinorUnit,
    currency: String,
    certainty: ArchipelPaymentCertainty,
    initiator: ArchipelPaymentInitiator,
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
pub struct CardExpiryDate {
    month: Secret<String>,
    year: Secret<String>,
}

#[derive(Debug, Serialize, Default, Eq, PartialEq, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ApplicationSelectionIndicator {
    #[default]
    ByDefault,
    CustomerChoice,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Archipel3DS {
    #[serde(rename = "acsTransID")]
    acs_trans_id: Option<Secret<String>>,
    #[serde(rename = "dsTransID")]
    ds_trans_id: Option<Secret<String>>,
    #[serde(rename = "3DSRequestorName")]
    three_ds_requestor_name: Option<Secret<String>>,
    #[serde(rename = "3DSAuthDate")]
    three_ds_auth_date: Option<String>,
    #[serde(rename = "3DSAuthAmt")]
    three_ds_auth_amt: Option<MinorUnit>,
    #[serde(rename = "3DSAuthStatus")]
    three_ds_auth_status: Option<String>,
    #[serde(rename = "3DSMaxSupportedVersion")]
    three_ds_max_supported_version: String,
    #[serde(rename = "3DSVersion")]
    three_ds_version: Option<common_utils::types::SemanticVersion>,
    authentication_value: Secret<String>,
    authentication_method: Option<Secret<String>>,
    eci: Option<String>,
}

impl From<AuthenticationData> for Archipel3DS {
    fn from(three_ds_data: AuthenticationData) -> Self {
        let now = date_time::date_as_yyyymmddthhmmssmmmz().ok();
        Self {
            acs_trans_id: None,
            ds_trans_id: three_ds_data.ds_trans_id.map(Secret::new),
            three_ds_requestor_name: None,
            three_ds_auth_date: now,
            three_ds_auth_amt: None,
            three_ds_auth_status: None,
            three_ds_max_supported_version: THREE_DS_MAX_SUPPORTED_VERSION.into(),
            three_ds_version: three_ds_data.message_version,
            authentication_value: three_ds_data.cavv,
            authentication_method: None,
            eci: three_ds_data.eci,
        }
    }
}

#[derive(Clone, Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelCardHolder {
    billing_address: Option<ArchipelBillingAddress>,
}

impl From<Option<ArchipelBillingAddress>> for ArchipelCardHolder {
    fn from(value: Option<ArchipelBillingAddress>) -> Self {
        Self {
            billing_address: value,
        }
    }
}

#[derive(Clone, Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelBillingAddress {
    address: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
}

pub trait ToArchipelBillingAddress {
    fn to_archipel_billing_address(&self) -> Option<ArchipelBillingAddress>;
}

impl ToArchipelBillingAddress for AddressDetails {
    fn to_archipel_billing_address(&self) -> Option<ArchipelBillingAddress> {
        let address = self.get_combined_address_line().ok();
        let postal_code = self.get_optional_zip();

        match (address, postal_code) {
            (None, None) => None,
            (addr, zip) => Some(ArchipelBillingAddress {
                address: addr,
                postal_code: zip,
            }),
        }
    }
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum ArchipelCredentialIndicatorStatus {
    Initial,
    Subsequent,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelCredentialIndicator {
    status: ArchipelCredentialIndicatorStatus,
    recurring: Option<bool>,
    transaction_id: Option<String>,
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct TokenizedCardData {
    card_data: ArchipelTokenizedCard,
    wallet_information: ArchipelWalletInformation,
}

impl TryFrom<(&WalletData, &Option<PaymentMethodToken>)> for TokenizedCardData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (wallet_data, pm_token): (&WalletData, &Option<PaymentMethodToken>),
    ) -> Result<Self, Self::Error> {
        let WalletData::ApplePay(apple_pay_data) = wallet_data else {
            return Err(error_stack::Report::from(
                errors::ConnectorError::NotSupported {
                    message: "Wallet type used".to_string(),
                    connector: "Archipel",
                },
            ));
        };

        let Some(PaymentMethodToken::ApplePayDecrypt(apple_pay_decrypt_data)) = pm_token else {
            return Err(error_stack::Report::from(unimplemented_payment_method!(
                "Apple Pay",
                "Manual",
                "Archipel"
            )));
        };

        let card_number = apple_pay_decrypt_data
            .application_primary_account_number
            .clone();

        let expiry_year_2_digit = apple_pay_decrypt_data
            .get_two_digit_expiry_year()
            .change_context(errors::ConnectorError::MissingRequiredField {
                field_name: "Apple pay expiry year",
            })?;
        let expiry_month = apple_pay_decrypt_data.get_expiry_month().change_context(
            errors::ConnectorError::InvalidDataFormat {
                field_name: "expiration_month",
            },
        )?;

        Ok(Self {
            card_data: ArchipelTokenizedCard {
                expiry: CardExpiryDate {
                    year: expiry_year_2_digit,
                    month: expiry_month,
                },
                number: card_number,
                scheme: ArchipelCardScheme::from(apple_pay_data.payment_method.network.as_str()),
            },
            wallet_information: {
                ArchipelWalletInformation {
                    wallet_provider: ArchipelWalletProvider::ApplePay,
                    wallet_indicator: apple_pay_decrypt_data.payment_data.eci_indicator.clone(),
                    wallet_cryptogram: apple_pay_decrypt_data
                        .payment_data
                        .online_payment_cryptogram
                        .clone(),
                }
            },
        })
    }
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelTokenizedCard {
    number: cards::CardNumber,
    expiry: CardExpiryDate,
    scheme: ArchipelCardScheme,
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelCard {
    number: cards::CardNumber,
    expiry: CardExpiryDate,
    security_code: Option<Secret<String>>,
    card_holder_name: Option<Secret<String>>,
    application_selection_indicator: ApplicationSelectionIndicator,
    scheme: ArchipelCardScheme,
}

impl TryFrom<(Option<Secret<String>>, Option<ArchipelCardHolder>, &Card)> for ArchipelCard {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (card_holder_name, card_holder_billing, ccard): (
            Option<Secret<String>>,
            Option<ArchipelCardHolder>,
            &Card,
        ),
    ) -> Result<Self, Self::Error> {
        // NOTE: Archipel does not accept `card.card_holder_name` field without `cardholder` field.
        // So if `card_holder` is None, `card.card_holder_name` must also be None.
        // However, the reverse is allowed — the `cardholder` field can exist without `card.card_holder_name`.
        let card_holder_name = card_holder_billing
            .as_ref()
            .and_then(|_| ccard.card_holder_name.clone().or(card_holder_name.clone()));

        let scheme: ArchipelCardScheme = ccard.get_card_issuer().ok().into();
        Ok(Self {
            number: ccard.card_number.clone(),
            expiry: CardExpiryDate {
                month: ccard.card_exp_month.clone(),
                year: ccard.get_card_expiry_year_2_digit()?,
            },
            security_code: Some(ccard.card_cvc.clone()),
            application_selection_indicator: ApplicationSelectionIndicator::ByDefault,
            card_holder_name,
            scheme,
        })
    }
}

impl
    TryFrom<(
        Option<Secret<String>>,
        Option<ArchipelCardHolder>,
        &hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId,
    )> for ArchipelCard
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (card_holder_name, card_holder_billing, card_details): (
            Option<Secret<String>>,
            Option<ArchipelCardHolder>,
            &hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId,
        ),
    ) -> Result<Self, Self::Error> {
        // NOTE: Archipel does not accept `card.card_holder_name` field without `cardholder` field.
        // So if `card_holder` is None, `card.card_holder_name` must also be None.
        // However, the reverse is allowed — the `cardholder` field can exist without `card.card_holder_name`.
        let card_holder_name = card_holder_billing.as_ref().and_then(|_| {
            card_details
                .card_holder_name
                .clone()
                .or(card_holder_name.clone())
        });

        let scheme: ArchipelCardScheme = card_details.get_card_issuer().ok().into();
        Ok(Self {
            number: card_details.card_number.clone(),
            expiry: CardExpiryDate {
                month: card_details.card_exp_month.clone(),
                year: card_details.get_card_expiry_year_2_digit()?,
            },
            security_code: None,
            application_selection_indicator: ApplicationSelectionIndicator::ByDefault,
            card_holder_name,
            scheme,
        })
    }
}

#[derive(Debug, Serialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelWalletInformation {
    wallet_indicator: Option<String>,
    wallet_provider: ArchipelWalletProvider,
    wallet_cryptogram: Secret<String>,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelPaymentInformation {
    order: ArchipelOrderRequest,
    cardholder: Option<ArchipelCardHolder>,
    card_holder_name: Option<Secret<String>>,
    credential_indicator: Option<ArchipelCredentialIndicator>,
    stored_on_file: bool,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelWalletAuthorizationRequest {
    order: ArchipelOrderRequest,
    card: ArchipelTokenizedCard,
    cardholder: Option<ArchipelCardHolder>,
    wallet: ArchipelWalletInformation,
    #[serde(rename = "3DS")]
    three_ds: Option<Archipel3DS>,
    credential_indicator: Option<ArchipelCredentialIndicator>,
    stored_on_file: bool,
    tenant_id: ArchipelTenantId,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelCardAuthorizationRequest {
    order: ArchipelOrderRequest,
    card: ArchipelCard,
    cardholder: Option<ArchipelCardHolder>,
    #[serde(rename = "3DS")]
    three_ds: Option<Archipel3DS>,
    credential_indicator: Option<ArchipelCredentialIndicator>,
    stored_on_file: bool,
    tenant_id: ArchipelTenantId,
}

// PaymentsResponse

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum ArchipelCardScheme {
    Amex,
    Mastercard,
    Visa,
    Discover,
    Diners,
    Unknown,
}

impl From<&str> for ArchipelCardScheme {
    fn from(input: &str) -> Self {
        match input {
            "Visa" => Self::Visa,
            "Amex" => Self::Amex,
            "Diners" => Self::Diners,
            "MasterCard" => Self::Mastercard,
            "Discover" => Self::Discover,
            _ => Self::Unknown,
        }
    }
}

impl From<Option<CardIssuer>> for ArchipelCardScheme {
    fn from(card_issuer: Option<CardIssuer>) -> Self {
        match card_issuer {
            Some(CardIssuer::Visa) => Self::Visa,
            Some(CardIssuer::Master | CardIssuer::Maestro) => Self::Mastercard,
            Some(CardIssuer::AmericanExpress) => Self::Amex,
            Some(CardIssuer::Discover) => Self::Discover,
            Some(CardIssuer::DinersClub) => Self::Diners,
            _ => Self::Unknown,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum ArchipelPaymentStatus {
    #[default]
    Succeeded,
    Failed,
}

impl TryFrom<(AttemptStatus, CaptureMethod)> for ArchipelPaymentFlow {
    type Error = errors::ConnectorError;

    fn try_from(
        (status, capture_method): (AttemptStatus, CaptureMethod),
    ) -> Result<Self, Self::Error> {
        let is_auto_capture = matches!(capture_method, CaptureMethod::Automatic);

        match status {
            AttemptStatus::AuthenticationFailed => Ok(Self::Verify),
            AttemptStatus::Authorizing
            | AttemptStatus::Authorized
            | AttemptStatus::AuthorizationFailed => Ok(Self::Authorize),
            AttemptStatus::Voided | AttemptStatus::VoidInitiated | AttemptStatus::VoidFailed => {
                Ok(Self::Cancel)
            }
            AttemptStatus::CaptureInitiated | AttemptStatus::CaptureFailed => {
                if is_auto_capture {
                    Ok(Self::Pay)
                } else {
                    Ok(Self::Capture)
                }
            }
            AttemptStatus::PaymentMethodAwaited | AttemptStatus::ConfirmationAwaited => {
                if is_auto_capture {
                    Ok(Self::Pay)
                } else {
                    Ok(Self::Authorize)
                }
            }
            _ => Err(errors::ConnectorError::ProcessingStepFailed(Some(
                Bytes::from_static(
                    "Impossible to determine Archipel flow from AttemptStatus".as_bytes(),
                ),
            ))),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ArchipelPaymentFlow {
    Verify,
    Authorize,
    Pay,
    Capture,
    Cancel,
}

struct ArchipelFlowStatus {
    status: ArchipelPaymentStatus,
    flow: ArchipelPaymentFlow,
}
impl ArchipelFlowStatus {
    fn new(status: ArchipelPaymentStatus, flow: ArchipelPaymentFlow) -> Self {
        Self { status, flow }
    }
}

impl From<ArchipelFlowStatus> for AttemptStatus {
    fn from(ArchipelFlowStatus { status, flow }: ArchipelFlowStatus) -> Self {
        match status {
            ArchipelPaymentStatus::Succeeded => match flow {
                ArchipelPaymentFlow::Authorize => Self::Authorized,
                ArchipelPaymentFlow::Pay
                | ArchipelPaymentFlow::Verify
                | ArchipelPaymentFlow::Capture => Self::Charged,
                ArchipelPaymentFlow::Cancel => Self::Voided,
            },
            ArchipelPaymentStatus::Failed => match flow {
                ArchipelPaymentFlow::Authorize | ArchipelPaymentFlow::Pay => {
                    Self::AuthorizationFailed
                }
                ArchipelPaymentFlow::Verify => Self::AuthenticationFailed,
                ArchipelPaymentFlow::Capture => Self::CaptureFailed,
                ArchipelPaymentFlow::Cancel => Self::VoidFailed,
            },
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelOrderResponse {
    id: String,
    amount: Option<i64>,
    currency: Option<Currency>,
    captured_amount: Option<i64>,
    authorized_amount: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ArchipelErrorMessage {
    pub code: String,
    pub description: Option<String>,
}

impl Default for ArchipelErrorMessage {
    fn default() -> Self {
        Self {
            code: consts::NO_ERROR_CODE.to_string(),
            description: Some(consts::NO_ERROR_MESSAGE.to_string()),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct ArchipelErrorMessageWithHttpCode {
    error_message: ArchipelErrorMessage,
    http_code: u16,
}
impl ArchipelErrorMessageWithHttpCode {
    fn new(error_message: ArchipelErrorMessage, http_code: u16) -> Self {
        Self {
            error_message,
            http_code,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelTransactionMetadata {
    pub transaction_id: String,
    pub transaction_date: String,
    pub financial_network_code: Option<String>,
    pub issuer_transaction_id: Option<String>,
    pub response_code: Option<String>,
    pub authorization_code: Option<String>,
    pub payment_account_reference: Option<Secret<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ArchipelPaymentsResponse {
    order: ArchipelOrderResponse,
    transaction_id: String,
    transaction_date: String,
    transaction_result: ArchipelPaymentStatus,
    error: Option<ArchipelErrorMessage>,
    financial_network_code: Option<String>,
    issuer_transaction_id: Option<String>,
    response_code: Option<String>,
    authorization_code: Option<String>,
    payment_account_reference: Option<Secret<String>>,
}

impl From<&ArchipelPaymentsResponse> for ArchipelTransactionMetadata {
    fn from(payment_response: &ArchipelPaymentsResponse) -> Self {
        Self {
            transaction_id: payment_response.transaction_id.clone(),
            transaction_date: payment_response.transaction_date.clone(),
            financial_network_code: payment_response.financial_network_code.clone(),
            issuer_transaction_id: payment_response.issuer_transaction_id.clone(),
            response_code: payment_response.response_code.clone(),
            authorization_code: payment_response.authorization_code.clone(),
            payment_account_reference: payment_response.payment_account_reference.clone(),
        }
    }
}

// AUTHORIZATION FLOW
impl TryFrom<(MinorUnit, &PaymentsAuthorizeRouterData)> for ArchipelPaymentInformation {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        (amount, router_data): (MinorUnit, &PaymentsAuthorizeRouterData),
    ) -> Result<Self, Self::Error> {
        let is_recurring_payment = router_data
            .request
            .mandate_id
            .as_ref()
            .and_then(|mandate_ids| mandate_ids.mandate_id.as_ref())
            .is_some();

        let is_subsequent_trx = router_data
            .request
            .mandate_id
            .as_ref()
            .and_then(|mandate_ids| mandate_ids.mandate_reference_id.as_ref())
            .is_some();

        let is_saved_card_payment = (router_data.request.is_mandate_payment())
            | (router_data.request.setup_future_usage == Some(FutureUsage::OnSession))
            | (router_data.payment_method_status == Some(PaymentMethodStatus::Active));

        let certainty = if router_data.request.request_incremental_authorization {
            if is_recurring_payment {
                ArchipelPaymentCertainty::Final
            } else {
                ArchipelPaymentCertainty::Estimated
            }
        } else {
            ArchipelPaymentCertainty::Final
        };

        let transaction_initiator = if is_recurring_payment {
            ArchipelPaymentInitiator::Merchant
        } else {
            ArchipelPaymentInitiator::Customer
        };

        let order = ArchipelOrderRequest {
            amount,
            currency: router_data.request.currency.to_string(),
            certainty,
            initiator: transaction_initiator.clone(),
        };

        let cardholder = router_data
            .get_billing_address()
            .ok()
            .and_then(|address| address.to_archipel_billing_address())
            .map(|billing_address| ArchipelCardHolder {
                billing_address: Some(billing_address),
            });

        // NOTE: Archipel does not accept `card.card_holder_name` field without `cardholder` field.
        // So if `card_holder` is None, `card.card_holder_name` must also be None.
        // However, the reverse is allowed — the `cardholder` field can exist without `card.card_holder_name`.
        let card_holder_name = cardholder.as_ref().and_then(|_| {
            router_data
                .get_billing()
                .ok()
                .and_then(|billing| billing.get_optional_full_name())
        });

        let indicator_status = if is_subsequent_trx {
            ArchipelCredentialIndicatorStatus::Subsequent
        } else {
            ArchipelCredentialIndicatorStatus::Initial
        };

        let stored_on_file =
            is_saved_card_payment | router_data.request.is_customer_initiated_mandate_payment();

        let credential_indicator = stored_on_file.then(|| ArchipelCredentialIndicator {
            status: indicator_status.clone(),
            recurring: Some(is_recurring_payment),
            transaction_id: match indicator_status {
                ArchipelCredentialIndicatorStatus::Initial => None,
                ArchipelCredentialIndicatorStatus::Subsequent => {
                    router_data.request.get_optional_network_transaction_id()
                }
            },
        });

        Ok(Self {
            order,
            cardholder,
            card_holder_name,
            credential_indicator,
            stored_on_file,
        })
    }
}

impl TryFrom<ArchipelRouterData<&PaymentsAuthorizeRouterData>>
    for ArchipelCardAuthorizationRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: ArchipelRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let ArchipelRouterData {
            amount,
            tenant_id,
            router_data,
        } = item;

        let payment_information: ArchipelPaymentInformation =
            ArchipelPaymentInformation::try_from((amount, router_data))?;
        let payment_method_data = match &item.router_data.request.payment_method_data {
            PaymentMethodData::Card(ccard) => ArchipelCard::try_from((
                payment_information.card_holder_name,
                payment_information.cardholder.clone(),
                ccard,
            ))?,
            PaymentMethodData::CardDetailsForNetworkTransactionId(card_details) => {
                ArchipelCard::try_from((
                    payment_information.card_holder_name,
                    payment_information.cardholder.clone(),
                    card_details,
                ))?
            }
            PaymentMethodData::CardRedirect(..)
            | PaymentMethodData::Wallet(..)
            | PaymentMethodData::PayLater(..)
            | PaymentMethodData::BankRedirect(..)
            | PaymentMethodData::BankDebit(..)
            | PaymentMethodData::BankTransfer(..)
            | PaymentMethodData::Crypto(..)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(..)
            | PaymentMethodData::Upi(..)
            | PaymentMethodData::Voucher(..)
            | PaymentMethodData::GiftCard(..)
            | PaymentMethodData::CardToken(..)
            | PaymentMethodData::OpenBanking(..)
            | PaymentMethodData::NetworkToken(..)
            | PaymentMethodData::MobilePayment(..) => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Archipel"),
            ))?,
        };

        let three_ds: Option<Archipel3DS> = if item.router_data.is_three_ds() {
            let auth_data = item
                .router_data
                .request
                .get_authentication_data()
                .change_context(errors::ConnectorError::NotSupported {
                    message: "Selected 3DS authentication method".to_string(),
                    connector: "archipel",
                })?;
            Some(Archipel3DS::from(auth_data))
        } else {
            None
        };

        Ok(Self {
            order: payment_information.order,
            cardholder: payment_information.cardholder,
            card: payment_method_data,
            three_ds,
            credential_indicator: payment_information.credential_indicator,
            stored_on_file: payment_information.stored_on_file,
            tenant_id,
        })
    }
}

impl TryFrom<ArchipelRouterData<&PaymentsAuthorizeRouterData>>
    for ArchipelWalletAuthorizationRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: ArchipelRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let ArchipelRouterData {
            amount,
            tenant_id,
            router_data,
        } = item;

        let payment_information = ArchipelPaymentInformation::try_from((amount, router_data))?;
        let payment_method_data = match &item.router_data.request.payment_method_data {
            PaymentMethodData::Wallet(wallet_data) => {
                TokenizedCardData::try_from((wallet_data, &item.router_data.payment_method_token))?
            }
            PaymentMethodData::Card(..)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(..)
            | PaymentMethodData::CardRedirect(..)
            | PaymentMethodData::PayLater(..)
            | PaymentMethodData::BankRedirect(..)
            | PaymentMethodData::BankDebit(..)
            | PaymentMethodData::BankTransfer(..)
            | PaymentMethodData::Crypto(..)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(..)
            | PaymentMethodData::Upi(..)
            | PaymentMethodData::Voucher(..)
            | PaymentMethodData::GiftCard(..)
            | PaymentMethodData::CardToken(..)
            | PaymentMethodData::OpenBanking(..)
            | PaymentMethodData::NetworkToken(..)
            | PaymentMethodData::MobilePayment(..) => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Archipel"),
            ))?,
        };

        Ok(Self {
            order: payment_information.order,
            cardholder: payment_information.cardholder,
            card: payment_method_data.card_data.clone(),
            wallet: payment_method_data.wallet_information.clone(),
            three_ds: None,
            credential_indicator: payment_information.credential_indicator,
            stored_on_file: payment_information.stored_on_file,
            tenant_id,
        })
    }
}

// Responses for AUTHORIZATION FLOW
impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            ArchipelPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    > for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            ArchipelPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        if let Some(error) = item.response.error {
            return Ok(Self {
                response: Err(ArchipelErrorMessageWithHttpCode::new(error, item.http_code).into()),
                ..item.data
            });
        };

        let capture_method = item
            .data
            .request
            .capture_method
            .ok_or_else(|| errors::ConnectorError::CaptureMethodNotSupported)?;

        let (archipel_flow, is_incremental_allowed) = match capture_method {
            CaptureMethod::Automatic => (ArchipelPaymentFlow::Pay, false),
            _ => (
                ArchipelPaymentFlow::Authorize,
                item.data.request.request_incremental_authorization,
            ),
        };

        let connector_metadata: Option<serde_json::Value> =
            ArchipelTransactionMetadata::from(&item.response)
                .encode_to_value()
                .ok();

        let status: AttemptStatus =
            ArchipelFlowStatus::new(item.response.transaction_result, archipel_flow).into();

        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.order.id),
                charges: None,
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata,
                // Save archipel initial transaction uuid for network transaction mit/cit
                network_txn_id: item
                    .data
                    .request
                    .is_customer_initiated_mandate_payment()
                    .then_some(item.response.transaction_id),
                connector_response_reference_id: None,
                incremental_authorization_allowed: Some(is_incremental_allowed),
            }),
            ..item.data
        })
    }
}

// PSYNC FLOW
impl<F>
    TryFrom<ResponseRouterData<F, ArchipelPaymentsResponse, PaymentsSyncData, PaymentsResponseData>>
    for RouterData<F, PaymentsSyncData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            ArchipelPaymentsResponse,
            PaymentsSyncData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        if let Some(error) = item.response.error {
            return Ok(Self {
                response: Err(ArchipelErrorMessageWithHttpCode::new(error, item.http_code).into()),
                ..item.data
            });
        };

        let connector_metadata: Option<serde_json::Value> =
            ArchipelTransactionMetadata::from(&item.response)
                .encode_to_value()
                .ok();

        let capture_method = item
            .data
            .request
            .capture_method
            .ok_or_else(|| errors::ConnectorError::CaptureMethodNotSupported)?;

        let archipel_flow: ArchipelPaymentFlow = (item.data.status, capture_method).try_into()?;

        let status: AttemptStatus =
            ArchipelFlowStatus::new(item.response.transaction_result, archipel_flow).into();

        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.order.id),
                charges: None,
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
            }),
            ..item.data
        })
    }
}

/* CAPTURE FLOW */

#[derive(Debug, Serialize, Eq, PartialEq)]
pub struct ArchipelCaptureRequest {
    order: ArchipelCaptureOrderRequest,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
pub struct ArchipelCaptureOrderRequest {
    amount: MinorUnit,
}

impl From<ArchipelRouterData<&PaymentsCaptureRouterData>> for ArchipelCaptureRequest {
    fn from(item: ArchipelRouterData<&PaymentsCaptureRouterData>) -> Self {
        Self {
            order: ArchipelCaptureOrderRequest {
                amount: item.amount,
            },
        }
    }
}

impl<F>
    TryFrom<
        ResponseRouterData<F, ArchipelPaymentsResponse, PaymentsCaptureData, PaymentsResponseData>,
    > for RouterData<F, PaymentsCaptureData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            ArchipelPaymentsResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        if let Some(error) = item.response.error {
            return Ok(Self {
                response: Err(ArchipelErrorMessageWithHttpCode::new(error, item.http_code).into()),
                ..item.data
            });
        };

        let connector_metadata: Option<serde_json::Value> =
            ArchipelTransactionMetadata::from(&item.response)
                .encode_to_value()
                .ok();

        let status: AttemptStatus = ArchipelFlowStatus::new(
            item.response.transaction_result,
            ArchipelPaymentFlow::Capture,
        )
        .into();

        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.order.id),
                charges: None,
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
            }),
            ..item.data
        })
    }
}

// Setup Mandate FLow
impl TryFrom<ArchipelRouterData<&SetupMandateRouterData>> for ArchipelCardAuthorizationRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: ArchipelRouterData<&SetupMandateRouterData>) -> Result<Self, Self::Error> {
        let order = ArchipelOrderRequest {
            amount: item.amount,
            currency: item.router_data.request.currency.to_string(),
            certainty: ArchipelPaymentCertainty::Final,
            initiator: ArchipelPaymentInitiator::Customer,
        };

        let cardholder = Some(ArchipelCardHolder {
            billing_address: item
                .router_data
                .get_billing_address()
                .ok()
                .and_then(|address| address.to_archipel_billing_address()),
        });

        // NOTE: Archipel does not accept `card.card_holder_name` field without `cardholder` field.
        // So if `card_holder` is None, `card.card_holder_name` must also be None.
        // However, the reverse is allowed — the `cardholder` field can exist without `card.card_holder_name`.
        let card_holder_name = cardholder.as_ref().and_then(|_| {
            item.router_data
                .get_billing()
                .ok()
                .and_then(|billing| billing.get_optional_full_name())
        });

        let stored_on_file = true;

        let credential_indicator = Some(ArchipelCredentialIndicator {
            status: ArchipelCredentialIndicatorStatus::Initial,
            recurring: Some(false),
            transaction_id: None,
        });


// Function: lower_program
// File: crates/euclid/src/frontend/dir/lowering.rs
// Module: euclid

pub fn lower_program<O>(
    dir_program: dir::DirProgram<O>,
) -> Result<vir::ValuedProgram<O>, AnalysisError>


// Implementation: impl Relay
// File: crates/router/src/routes/app.rs
// Module: router
// Methods: 1 total (1 public)

impl Relay


// Implementation: impl fred::types::FromRedis for for HsetnxReply
// File: crates/redis_interface/src/types.rs
// Module: redis_interface
// Methods: 1 total (0 public)

impl fred::types::FromRedis for for HsetnxReply


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/wellsfargopayout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


// Struct: MultipleCaptureRequestData
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct MultipleCaptureRequestData


// Implementation: impl api::PaymentVoid for for Aci
// File: crates/hyperswitch_connectors/src/connectors/aci.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentVoid for for Aci


// Struct: RsyncApplicationInformation
// File: crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RsyncApplicationInformation


// Function: new
// File: crates/common_utils/src/types/user/theme.rs
// Module: common_utils

// Documentation: Constructor for ThemeLineage

pub fn new(
        entity_type: EntityType,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
        merchant_id: id_type::MerchantId,
        profile_id: id_type::ProfileId,
    ) -> Self


// Struct: WellsfargoAuthenticationErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WellsfargoAuthenticationErrorResponse


// Implementation: impl super::behaviour::Conversion for for MerchantKeyStore
// File: crates/hyperswitch_domain_models/src/merchant_key_store.rs
// Module: hyperswitch_domain_models
// Methods: 3 total (0 public)

impl super::behaviour::Conversion for for MerchantKeyStore


// File: crates/router/src/routes/metrics/bg_metrics_collector.rs
// Module: router
// Public functions: 1

use storage_impl::redis::cache;

const DEFAULT_BG_METRICS_COLLECTION_INTERVAL_IN_SECS: u16 = 15;

pub fn spawn_metrics_collector(metrics_collection_interval_in_secs: Option<u16>) {
    let metrics_collection_interval = metrics_collection_interval_in_secs
        .unwrap_or(DEFAULT_BG_METRICS_COLLECTION_INTERVAL_IN_SECS);

    let cache_instances = [
        &cache::CONFIG_CACHE,
        &cache::ACCOUNTS_CACHE,
        &cache::ROUTING_CACHE,
        &cache::CGRAPH_CACHE,
        &cache::PM_FILTERS_CGRAPH_CACHE,
        &cache::DECISION_MANAGER_CACHE,
        &cache::SURCHARGE_CACHE,
        &cache::SUCCESS_BASED_DYNAMIC_ALGORITHM_CACHE,
        &cache::CONTRACT_BASED_DYNAMIC_ALGORITHM_CACHE,
        &cache::ELIMINATION_BASED_DYNAMIC_ALGORITHM_CACHE,
    ];

    tokio::spawn(async move {
        loop {
            for instance in cache_instances {
                instance.record_entry_count_metric().await
            }

            tokio::time::sleep(std::time::Duration::from_secs(
                metrics_collection_interval.into(),
            ))
            .await
        }
    });
}


// Function: get_merchant_reference_id
// File: crates/api_models/src/admin.rs
// Module: api_models

pub fn get_merchant_reference_id(&self) -> id_type::MerchantId


// Struct: RefundPaymentData
// File: crates/hyperswitch_connectors/src/connectors/getnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundPaymentData


// Function: get_sso_id_from_redis
// File: crates/router/src/utils/user.rs
// Module: router

pub fn get_sso_id_from_redis(
    state: &SessionState,
    oidc_state: Secret<String>,
) -> UserResult<String>


// Implementation: impl api::RefundSync for for Authipay
// File: crates/hyperswitch_connectors/src/connectors/authipay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundSync for for Authipay