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

pub struct SyncIntegrityObject


// Implementation: impl Responder
// File: crates/router/src/analytics.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Struct: Opennode
// File: crates/hyperswitch_connectors/src/connectors/opennode.rs
// Module: hyperswitch_connectors
// Implementations: 17
// Traits: api::Payment, api::PaymentSession, api::PaymentToken, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, ConnectorCommon, ConnectorValidation, IncomingWebhook, ConnectorSpecifications

pub struct Opennode

api::Payment api::PaymentSession api::PaymentToken api::ConnectorAccessToken api::MandateSetup api::PaymentAuthorize api::PaymentSync api::PaymentCapture api::PaymentVoid api::Refund api::RefundExecute api::RefundSync ConnectorCommon ConnectorValidation IncomingWebhook ConnectorSpecifications


// Function: list_payment_methods_core
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn list_payment_methods_core(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    customer_id: &id_type::GlobalCustomerId,
) -> RouterResult<payment_methods::CustomerPaymentMethodsListResponse>


// Implementation: impl api::ConnectorTransactionId for for ConnectorEnum
// File: crates/hyperswitch_interfaces/src/connector_integration_interface.rs
// Module: hyperswitch_interfaces
// Methods: 1 total (0 public)

impl api::ConnectorTransactionId for for ConnectorEnum


// Function: profile_retrieve
// File: crates/router/src/routes/profiles.rs
// Module: router

pub fn profile_retrieve(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::ProfileId>,
) -> HttpResponse


// Struct: WisePayoutsWebhookData
// File: crates/hyperswitch_connectors/src/connectors/wise/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WisePayoutsWebhookData


// Function: authorize_postprocessing_steps
// File: crates/router/src/core/payments/flows/authorize_flow.rs
// Module: router

pub fn authorize_postprocessing_steps<F: Clone>(
    state: &SessionState,
    router_data: &types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>,
    confirm: bool,
    connector: &api::ConnectorData,
) -> RouterResult<types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>>


// Implementation: impl api::Refund for for Coingate
// File: crates/hyperswitch_connectors/src/connectors/coingate.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Refund for for Coingate


// Implementation: impl ConnectorCommon for for Itaubank
// File: crates/hyperswitch_connectors/src/connectors/itaubank.rs
// Module: hyperswitch_connectors
// Methods: 5 total (0 public)

impl ConnectorCommon for for Itaubank


// Function: handle_unified_connector_service_response_for_payment_repeat
// File: crates/router/src/core/unified_connector_service.rs
// Module: router

pub fn handle_unified_connector_service_response_for_payment_repeat(
    response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> UnifiedConnectorServiceResult


// Implementation: impl ApiEventMetric for for AuthenticationSyncPostUpdateRequest
// File: crates/api_models/src/authentication.rs
// Module: api_models
// Methods: 1 total (0 public)

impl ApiEventMetric for for AuthenticationSyncPostUpdateRequest


// Function: get_merchant_tax_registration_id
// File: crates/hyperswitch_domain_models/src/merchant_account.rs
// Module: hyperswitch_domain_models

// Documentation: Extract merchant_tax_registration_id from merchant_details

pub fn get_merchant_tax_registration_id(&self) -> Option<Secret<String>>


// File: crates/common_utils/src/id_type/api_key.rs
// Module: common_utils
// Public functions: 1

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");


// Function: validate_connectors_in_routing_config
// File: crates/router/src/core/routing/helpers.rs
// Module: router

pub fn validate_connectors_in_routing_config(&self) -> RouterResult<()>


// Struct: MinimalRoleInfo
// File: crates/api_models/src/user_role/role.rs
// Module: api_models
// Implementations: 0

pub struct MinimalRoleInfo


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

pub struct RefundResponse


// File: crates/api_models/src/payments/trait_impls.rs
// Module: api_models

#[cfg(feature = "v1")]
use common_enums::enums;
#[cfg(feature = "v1")]
use common_utils::errors;

#[cfg(feature = "v1")]
use crate::payments;

#[cfg(feature = "v1")]
impl crate::ValidateFieldAndGet<payments::PaymentsRequest>
    for common_types::primitive_wrappers::RequestExtendedAuthorizationBool
{
    fn validate_field_and_get(
        &self,
        request: &payments::PaymentsRequest,
    ) -> errors::CustomResult<Self, errors::ValidationError>
    where
        Self: Sized,
    {
        match request.capture_method{
            Some(enums::CaptureMethod::Automatic)
            | Some(enums::CaptureMethod::Scheduled)
            | Some(enums::CaptureMethod::SequentialAutomatic)
            | None => Err(error_stack::report!(errors::ValidationError::InvalidValue { message: "request_extended_authorization must be sent only if capture method is manual or manual_multiple".to_string() })),
            Some(enums::CaptureMethod::Manual)
            | Some(enums::CaptureMethod::ManualMultiple) => Ok(*self)
        }
    }
}


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

pub struct RefundResponse


// Struct: MaxLatency
// File: crates/analytics/src/api_event/metrics/latency.rs
// Module: analytics
// Implementations: 0

pub struct MaxLatency


// Struct: PayoutCreateResponse
// File: crates/api_models/src/payouts.rs
// Module: api_models
// Implementations: 0

pub struct PayoutCreateResponse


// Struct: SquareTokenResponse
// File: crates/hyperswitch_connectors/src/connectors/square/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SquareTokenResponse


// Struct: LoanInformation
// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct LoanInformation


// Implementation: impl webhooks::IncomingWebhook for for Vgs
// File: crates/hyperswitch_connectors/src/connectors/vgs.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl webhooks::IncomingWebhook for for Vgs


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

pub struct RefundResponse


// File: crates/router/src/types/storage/kv.rs
// Module: router

pub use diesel_models::kv::{
    AddressUpdateMems, DBOperation, Insertable, PaymentAttemptUpdateMems, PaymentIntentUpdateMems,
    RefundUpdateMems, TypedSql, Updateable,
};


// Function: get_gsm
// File: crates/router/src/core/payouts/retry.rs
// Module: router

pub fn get_gsm(
    state: &app::SessionState,
    original_connector_data: &api::ConnectorData,
    payout_data: &PayoutData,
) -> RouterResult<Option<hyperswitch_domain_models::gsm::GatewayStatusMap>>


// Struct: PayuPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/payu/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayuPaymentsRequest


// Struct: PaymentMethodInfo
// File: crates/hyperswitch_connectors/src/connectors/xendit/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentMethodInfo


// Implementation: impl ConnectorCommon for for Gpayments
// File: crates/hyperswitch_connectors/src/connectors/gpayments.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl ConnectorCommon for for Gpayments


// Implementation: impl ConnectorValidation for for Nuvei
// File: crates/hyperswitch_connectors/src/connectors/nuvei.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ConnectorValidation for for Nuvei


// Struct: ConfirmSubscriptionResponse
// File: crates/api_models/src/subscription.rs
// Module: api_models
// Implementations: 1
// Traits: ApiEventMetric

pub struct ConfirmSubscriptionResponse


// Function: get_expiry_date_as_mmyy
// File: crates/common_types/src/payments.rs
// Module: common_types

// Documentation: Get the expiry date in MMYY format from the Apple Pay pre-decrypt data

pub fn get_expiry_date_as_mmyy(&self) -> Result<Secret<String>, errors::ValidationError>


// Struct: StripePaymentMethodData
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router
// Implementations: 0

pub struct StripePaymentMethodData


// Function: list_webhook_delivery_attempts
// File: crates/router/src/routes/webhook_events.rs
// Module: router

pub fn list_webhook_delivery_attempts(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<(common_utils::id_type::MerchantId, String)


// Function: payments_list
// File: crates/router/src/routes/payments.rs
// Module: router

pub fn payments_list(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    payload: web::Query<payment_types::PaymentListConstraints>,
) -> impl Responder


// Function: new
// File: crates/common_utils/src/request.rs
// Module: common_utils

pub fn new(method: Method, url: &str) -> Self


// Function: get_mandate_reference
// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors

pub fn get_mandate_reference(&self) -> Box<Option<MandateReference>>


// Implementation: impl PaymentSync for for DummyConnector
// File: crates/hyperswitch_connectors/src/connectors/dummyconnector.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl PaymentSync for for DummyConnector


// Struct: PrimaryBusinessDetails
// File: crates/api_models/src/admin.rs
// Module: api_models
// Implementations: 0

pub struct PrimaryBusinessDetails


// Implementation: impl api::PaymentSession for for Gigadat
// File: crates/hyperswitch_connectors/src/connectors/gigadat.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Gigadat


// File: crates/drainer/src/connection.rs
// Module: drainer
// Public functions: 3

use bb8::PooledConnection;
use common_utils::DbConnectionParams;
use diesel::PgConnection;

use crate::{settings::Database, Settings};

pub type PgPool = bb8::Pool<async_bb8_diesel::ConnectionManager<PgConnection>>;

#[allow(clippy::expect_used)]
pub async fn redis_connection(conf: &Settings) -> redis_interface::RedisConnectionPool {
    redis_interface::RedisConnectionPool::new(&conf.redis)
        .await
        .expect("Failed to create Redis connection Pool")
}

// TODO: use stores defined in storage_impl instead
/// # Panics
///
/// Will panic if could not create a db pool
#[allow(clippy::expect_used)]
pub async fn diesel_make_pg_pool(
    database: &Database,
    _test_transaction: bool,
    schema: &str,
) -> PgPool {
    let database_url = database.get_database_url(schema);
    let manager = async_bb8_diesel::ConnectionManager::<PgConnection>::new(database_url);
    let pool = bb8::Pool::builder()
        .max_size(database.pool_size)
        .connection_timeout(std::time::Duration::from_secs(database.connection_timeout));

    pool.build(manager)
        .await
        .expect("Failed to create PostgreSQL connection pool")
}

#[allow(clippy::expect_used)]
pub async fn pg_connection(
    pool: &PgPool,
) -> PooledConnection<'_, async_bb8_diesel::ConnectionManager<PgConnection>> {
    pool.get()
        .await
        .expect("Couldn't retrieve PostgreSQL connection")
}


// Function: wrap
// File: crates/common_utils/src/id_type/payment.rs
// Module: common_utils

// Documentation: Wrap a string inside PaymentId

pub fn wrap(payment_id_string: String) -> CustomResult<Self, ValidationError>


// File: crates/router/src/core/fraud_check/flows/transaction_flow.rs
// Module: router
// Public functions: 1

use async_trait::async_trait;
use common_utils::ext_traits::ValueExt;
use error_stack::ResultExt;

use crate::{
    core::{
        errors::{ConnectorErrorExt, RouterResult},
        fraud_check::{FeatureFrm, FrmData},
        payments::{self, flows::ConstructFlowSpecificData, helpers},
    },
    errors, services,
    types::{
        api::fraud_check as frm_api,
        domain,
        fraud_check::{
            FraudCheckResponseData, FraudCheckTransactionData, FrmTransactionRouterData,
        },
        storage::enums as storage_enums,
        ConnectorAuthType, MerchantRecipientData, ResponseId, RouterData,
    },
    SessionState,
};

#[async_trait]
impl
    ConstructFlowSpecificData<
        frm_api::Transaction,
        FraudCheckTransactionData,
        FraudCheckResponseData,
    > for FrmData
{
    #[cfg(feature = "v2")]
    async fn construct_router_data<'a>(
        &self,
        _state: &SessionState,
        _connector_id: &str,
        _merchant_context: &domain::MerchantContext,
        _customer: &Option<domain::Customer>,
        _merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
        _merchant_recipient_data: Option<MerchantRecipientData>,
        _header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<
        RouterData<frm_api::Transaction, FraudCheckTransactionData, FraudCheckResponseData>,
    > {
        todo!()
    }

    #[cfg(feature = "v1")]
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
        _merchant_recipient_data: Option<MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<
        RouterData<frm_api::Transaction, FraudCheckTransactionData, FraudCheckResponseData>,
    > {
        let status = storage_enums::AttemptStatus::Pending;

        let auth_type: ConnectorAuthType = merchant_connector_account
            .get_connector_account_details()
            .parse_value("ConnectorAuthType")
            .change_context(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                id: "ConnectorAuthType".to_string(),
            })?;

        let customer_id = customer.to_owned().map(|customer| customer.customer_id);

        let payment_method = self.payment_attempt.payment_method;
        let currency = self.payment_attempt.currency;

        let router_data = RouterData {
            flow: std::marker::PhantomData,
            merchant_id: merchant_context.get_merchant_account().get_id().clone(),
            tenant_id: state.tenant.tenant_id.clone(),
            customer_id,
            connector: connector_id.to_string(),
            payment_id: self.payment_intent.payment_id.get_string_repr().to_owned(),
            attempt_id: self.payment_attempt.attempt_id.clone(),
            status,
            payment_method: self
                .payment_attempt
                .payment_method
                .ok_or(errors::ApiErrorResponse::PaymentMethodNotFound)?,
            connector_auth_type: auth_type,
            description: None,
            address: self.address.clone(),
            auth_type: storage_enums::AuthenticationType::NoThreeDs,
            connector_meta_data: None,
            connector_wallets_details: None,
            amount_captured: None,
            minor_amount_captured: None,
            request: FraudCheckTransactionData {
                amount: self
                    .payment_attempt
                    .net_amount
                    .get_total_amount()
                    .get_amount_as_i64(),
                order_details: self.order_details.clone(),
                currency,
                payment_method,
                error_code: self.payment_attempt.error_code.clone(),
                error_message: self.payment_attempt.error_message.clone(),
                connector_transaction_id: self
                    .payment_attempt
                    .get_connector_payment_id()
                    .map(ToString::to_string),
                connector: self.payment_attempt.connector.clone(),
            }, // self.order_details
            response: Ok(FraudCheckResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId("".to_string()),
                connector_metadata: None,
                status: storage_enums::FraudCheckStatus::Pending,
                score: None,
                reason: None,
            }),
            access_token: None,
            session_token: None,
            reference_id: None,
            payment_method_token: None,
            connector_customer: None,
            preprocessing_id: None,
            connector_request_reference_id: uuid::Uuid::new_v4().to_string(),
            test_mode: None,
            recurring_mandate_payment_data: None,
            #[cfg(feature = "payouts")]
            payout_method_data: None,
            #[cfg(feature = "payouts")]
            quote_id: None,
            payment_method_balance: None,
            connector_http_status_code: None,
            external_latency: None,
            connector_api_version: None,
            payment_method_status: None,
            apple_pay_flow: None,
            frm_metadata: self.frm_metadata.clone(),
            refund_id: None,
            dispute_id: None,
            connector_response: None,
            integrity_check: Ok(()),
            additional_merchant_data: None,
            header_payload,
            connector_mandate_request_reference_id: None,
            authentication_id: None,
            psd2_sca_exemption_type: None,
            raw_connector_response: None,
            is_payment_id_from_merchant: None,
            l2_l3_data: None,
            minor_amount_capturable: None,
        };

        Ok(router_data)
    }
}

#[async_trait]
impl FeatureFrm<frm_api::Transaction, FraudCheckTransactionData> for FrmTransactionRouterData {
    async fn decide_frm_flows<'a>(
        mut self,
        state: &SessionState,
        connector: &frm_api::FraudCheckConnectorData,
        call_connector_action: payments::CallConnectorAction,
        merchant_context: &domain::MerchantContext,
    ) -> RouterResult<Self> {
        decide_frm_flow(
            &mut self,
            state,
            connector,
            call_connector_action,
            merchant_context,
        )
        .await
    }
}

pub async fn decide_frm_flow(
    router_data: &mut FrmTransactionRouterData,
    state: &SessionState,
    connector: &frm_api::FraudCheckConnectorData,
    call_connector_action: payments::CallConnectorAction,
    _merchant_context: &domain::MerchantContext,
) -> RouterResult<FrmTransactionRouterData> {
    let connector_integration: services::BoxedFrmConnectorIntegrationInterface<
        frm_api::Transaction,
        FraudCheckTransactionData,
        FraudCheckResponseData,
    > = connector.connector.get_connector_integration();
    let resp = services::execute_connector_processing_step(
        state,
        connector_integration,
        router_data,
        call_connector_action,
        None,
        None,
    )
    .await
    .to_payment_failed_response()?;

    Ok(resp)
}


// Struct: SilverflowAuthType
// File: crates/hyperswitch_connectors/src/connectors/silverflow/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SilverflowAuthType


// Function: build_webhook_secrets_from_merchant_connector_account
// File: crates/router/src/core/unified_connector_service.rs
// Module: router

pub fn build_webhook_secrets_from_merchant_connector_account(
    #[cfg(feature = "v1")


// Function: store_data_in_redis
// File: crates/router/src/routes/dummy_connector/utils.rs
// Module: router

pub fn store_data_in_redis(
    state: &SessionState,
    key: String,
    data: impl serde::Serialize + Debug,
    ttl: i64,
) -> types::DummyConnectorResult<()>


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/coingate.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Function: retrieve_customer
// File: crates/router/src/core/customers.rs
// Module: router

pub fn retrieve_customer(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    _profile_id: Option<id_type::ProfileId>,
    customer_id: id_type::CustomerId,
) -> errors::CustomerResponse<customers::CustomerResponse>


// Function: get_allowed_signals
// File: crates/common_utils/src/signals.rs
// Module: common_utils

pub fn get_allowed_signals() -> Result<signal_hook_tokio::SignalsInfo, std::io::Error>


// Implementation: impl OperationsDeriveInputExt for for DeriveInput
// File: crates/router_derive/src/macros/operation.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl OperationsDeriveInputExt for for DeriveInput


// Function: get_dispute_dimensions
// File: crates/analytics/src/utils.rs
// Module: analytics

pub fn get_dispute_dimensions() -> Vec<NameDescription>


// Implementation: impl ConnectorCommon for for Payu
// File: crates/hyperswitch_connectors/src/connectors/payu.rs
// Module: hyperswitch_connectors
// Methods: 5 total (0 public)

impl ConnectorCommon for for Payu


// Implementation: impl api::ConnectorAccessToken for for Stax
// File: crates/hyperswitch_connectors/src/connectors/stax.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Stax


// Struct: DeutschebankMandatePostResponse
// File: crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DeutschebankMandatePostResponse


// Function: store_card_and_token_in_locker
// File: crates/router/src/core/payment_methods/tokenize/card_executor.rs
// Module: router

pub fn store_card_and_token_in_locker(
        &self,
        network_token: &NetworkTokenizationResponse,
        card: &domain::CardDetail,
        customer_id: &id_type::CustomerId,
    ) -> RouterResult<StoreLockerResponse>


// Function: get_order_fulfillment_time
// File: crates/hyperswitch_domain_models/src/business_profile.rs
// Module: hyperswitch_domain_models

pub fn get_order_fulfillment_time(&self) -> Option<i64>


// Struct: TokenizedWalletValue2
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct TokenizedWalletValue2


// File: crates/euclid/src/backend/interpreter/types.rs
// Module: euclid
// Public structs: 2

use std::{collections::HashMap, fmt, ops::Deref, string::ToString};

use serde::Serialize;

use crate::{backend::inputs, frontend::ast::ValueType, types::EuclidKey};

#[derive(Debug, Clone, Serialize, thiserror::Error)]
#[serde(tag = "type", content = "data", rename_all = "snake_case")]
pub enum InterpreterErrorType {
    #[error("Invalid key received '{0}'")]
    InvalidKey(String),
    #[error("Invalid Comparison")]
    InvalidComparison,
}

#[derive(Debug, Clone, Serialize, thiserror::Error)]
pub struct InterpreterError {
    pub error_type: InterpreterErrorType,
    pub metadata: HashMap<String, serde_json::Value>,
}

impl fmt::Display for InterpreterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        InterpreterErrorType::fmt(&self.error_type, f)
    }
}

pub struct Context(HashMap<String, Option<ValueType>>);

impl Deref for Context {
    type Target = HashMap<String, Option<ValueType>>;

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

impl From<inputs::BackendInput> for Context {
    fn from(input: inputs::BackendInput) -> Self {
        let ctx = HashMap::<String, Option<ValueType>>::from_iter([
            (
                EuclidKey::PaymentMethod.to_string(),
                input
                    .payment_method
                    .payment_method
                    .map(|pm| ValueType::EnumVariant(pm.to_string())),
            ),
            (
                EuclidKey::PaymentMethodType.to_string(),
                input
                    .payment_method
                    .payment_method_type
                    .map(|pt| ValueType::EnumVariant(pt.to_string())),
            ),
            (
                EuclidKey::AuthenticationType.to_string(),
                input
                    .payment
                    .authentication_type
                    .map(|at| ValueType::EnumVariant(at.to_string())),
            ),
            (
                EuclidKey::CaptureMethod.to_string(),
                input
                    .payment
                    .capture_method
                    .map(|cm| ValueType::EnumVariant(cm.to_string())),
            ),
            (
                EuclidKey::PaymentAmount.to_string(),
                Some(ValueType::Number(input.payment.amount)),
            ),
            (
                EuclidKey::PaymentCurrency.to_string(),
                Some(ValueType::EnumVariant(input.payment.currency.to_string())),
            ),
        ]);

        Self(ctx)
    }
}


// Struct: CustombillingRouterData
// File: crates/hyperswitch_connectors/src/connectors/custombilling/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustombillingRouterData<T>


// Implementation: impl PaymentMethodsUpdateForm
// File: crates/router/src/core/payment_methods/migration.rs
// Module: router
// Methods: 1 total (1 public)

impl PaymentMethodsUpdateForm


// Function: find_by_id
// File: crates/diesel_models/src/query/merchant_connector_account.rs
// Module: diesel_models

pub fn find_by_id(
        conn: &PgPooledConn,
        id: &common_utils::id_type::MerchantConnectorAccountId,
    ) -> StorageResult<Self>


// Struct: ItaubankTokenErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/itaubank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ItaubankTokenErrorResponse


// Struct: AirwallexDisputeObject
// File: crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AirwallexDisputeObject


// Struct: BackendInput
// File: crates/euclid/src/backend/inputs.rs
// Module: euclid
// Implementations: 0

pub struct BackendInput


// Function: vault_payment_method_external
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn vault_payment_method_external(
    state: &SessionState,
    pmd: &domain::PaymentMethodVaultingData,
    merchant_account: &domain::MerchantAccount,
    merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
) -> RouterResult<pm_types::AddVaultResponse>


// File: crates/router/tests/connectors/paysafe.rs
// Module: router

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::types::{self, api, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct PaysafeTest;
impl ConnectorActions for PaysafeTest {}
impl utils::Connector for PaysafeTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Paysafe;
        utils::construct_connector_data_old(
            Box::new(Paysafe::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .paysafe
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "paysafe".to_string()
    }
}

static CONNECTOR: PaysafeTest = PaysafeTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


// Struct: StoreCardRespPayload
// File: crates/router/src/core/payment_methods/transformers.rs
// Module: router
// Implementations: 0

pub struct StoreCardRespPayload


// Struct: FiuuAuthType
// File: crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FiuuAuthType


// Implementation: impl ConnectorCommon for for Square
// File: crates/hyperswitch_connectors/src/connectors/square.rs
// Module: hyperswitch_connectors
// Methods: 5 total (0 public)

impl ConnectorCommon for for Square


// File: crates/router/src/core/routing.rs
// Module: router
// Public functions: 34
// Public structs: 4

pub mod helpers;
pub mod transformers;
use std::collections::HashSet;

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use api_models::routing::DynamicRoutingAlgoAccessor;
use api_models::{
    enums, mandates as mandates_api,
    open_router::{
        DecideGatewayResponse, OpenRouterDecideGatewayRequest, UpdateScorePayload,
        UpdateScoreResponse,
    },
    routing,
    routing::{
        self as routing_types, RoutingRetrieveQuery, RuleMigrationError, RuleMigrationResponse,
    },
};
use async_trait::async_trait;
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use common_utils::ext_traits::AsyncExt;
use common_utils::request::Method;
use diesel_models::routing_algorithm::RoutingAlgorithm;
use error_stack::ResultExt;
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use external_services::grpc_client::dynamic_routing::{
    contract_routing_client::ContractBasedDynamicRouting,
    elimination_based_client::EliminationBasedRouting,
    success_rate_client::SuccessBasedDynamicRouting,
};
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use helpers::{
    enable_decision_engine_dynamic_routing_setup, update_decision_engine_dynamic_routing_setup,
};
use hyperswitch_domain_models::{mandates, payment_address};
use payment_methods::helpers::StorageErrorExt;
use rustc_hash::FxHashSet;
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use storage_impl::redis::cache;

#[cfg(feature = "payouts")]
use super::payouts;
use super::{
    errors::RouterResult,
    payments::{
        routing::{
            utils::*,
            {self as payments_routing},
        },
        OperationSessionGetters,
    },
};
#[cfg(feature = "v1")]
use crate::utils::ValueExt;
#[cfg(feature = "v2")]
use crate::{core::admin, utils::ValueExt};
use crate::{
    core::{
        errors::{self, CustomResult, RouterResponse},
        metrics, utils as core_utils,
    },
    db::StorageInterface,
    routes::SessionState,
    services::api as service_api,
    types::{
        api, domain,
        storage::{self, enums as storage_enums},
        transformers::{ForeignInto, ForeignTryFrom},
    },
    utils::{self, OptionExt},
};

pub enum TransactionData<'a> {
    Payment(PaymentsDslInput<'a>),
    #[cfg(feature = "payouts")]
    Payout(&'a payouts::PayoutData),
}

#[derive(Clone)]
pub struct PaymentsDslInput<'a> {
    pub setup_mandate: Option<&'a mandates::MandateData>,
    pub payment_attempt: &'a storage::PaymentAttempt,
    pub payment_intent: &'a storage::PaymentIntent,
    pub payment_method_data: Option<&'a domain::PaymentMethodData>,
    pub address: &'a payment_address::PaymentAddress,
    pub recurring_details: Option<&'a mandates_api::RecurringDetails>,
    pub currency: storage_enums::Currency,
}

impl<'a> PaymentsDslInput<'a> {
    pub fn new(
        setup_mandate: Option<&'a mandates::MandateData>,
        payment_attempt: &'a storage::PaymentAttempt,
        payment_intent: &'a storage::PaymentIntent,
        payment_method_data: Option<&'a domain::PaymentMethodData>,
        address: &'a payment_address::PaymentAddress,
        recurring_details: Option<&'a mandates_api::RecurringDetails>,
        currency: storage_enums::Currency,
    ) -> Self {
        Self {
            setup_mandate,
            payment_attempt,
            payment_intent,
            payment_method_data,
            address,
            recurring_details,
            currency,
        }
    }
}

#[cfg(feature = "v2")]
struct RoutingAlgorithmUpdate(RoutingAlgorithm);

#[cfg(feature = "v2")]
impl RoutingAlgorithmUpdate {
    pub fn create_new_routing_algorithm(
        request: &routing_types::RoutingConfigRequest,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id: common_utils::id_type::ProfileId,
        transaction_type: enums::TransactionType,
    ) -> Self {
        let algorithm_id = common_utils::generate_routing_id_of_default_length();
        let timestamp = common_utils::date_time::now();
        let algo = RoutingAlgorithm {
            algorithm_id,
            profile_id,
            merchant_id: merchant_id.clone(),
            name: request.name.clone(),
            description: Some(request.description.clone()),
            kind: request.algorithm.get_kind().foreign_into(),
            algorithm_data: serde_json::json!(request.algorithm),
            created_at: timestamp,
            modified_at: timestamp,
            algorithm_for: transaction_type,
            decision_engine_routing_id: None,
        };
        Self(algo)
    }
    pub async fn fetch_routing_algo(
        merchant_id: &common_utils::id_type::MerchantId,
        algorithm_id: &common_utils::id_type::RoutingId,
        db: &dyn StorageInterface,
    ) -> RouterResult<Self> {
        let routing_algo = db
            .find_routing_algorithm_by_algorithm_id_merchant_id(algorithm_id, merchant_id)
            .await
            .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
        Ok(Self(routing_algo))
    }
}

pub async fn retrieve_merchant_routing_dictionary(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
    query_params: RoutingRetrieveQuery,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingKind> {
    metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(1, &[]);

    let routing_metadata: Vec<diesel_models::routing_algorithm::RoutingProfileMetadata> = state
        .store
        .list_routing_algorithm_metadata_by_merchant_id_transaction_type(
            merchant_context.get_merchant_account().get_id(),
            &transaction_type,
            i64::from(query_params.limit.unwrap_or_default()),
            i64::from(query_params.offset.unwrap_or_default()),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
    let routing_metadata = super::utils::filter_objects_based_on_profile_id_list(
        profile_id_list.clone(),
        routing_metadata,
    );

    let mut result = routing_metadata
        .into_iter()
        .map(ForeignInto::foreign_into)
        .collect::<Vec<_>>();

    if let Some(profile_ids) = profile_id_list {
        let mut de_result: Vec<routing_types::RoutingDictionaryRecord> = vec![];
        // DE_TODO: need to replace this with batch API call to reduce the number of network calls
        for profile_id in &profile_ids {
            let list_request = ListRountingAlgorithmsRequest {
                created_by: profile_id.get_string_repr().to_string(),
            };
            list_de_euclid_routing_algorithms(&state, list_request)
                .await
                .map_err(|e| {
                    router_env::logger::error!(decision_engine_error=?e, "decision_engine_euclid");
                })
                .ok() // Avoid throwing error if Decision Engine is not available or other errors
                .map(|mut de_routing| de_result.append(&mut de_routing));
            // filter de_result based on transaction type
            de_result.retain(|record| record.algorithm_for == Some(transaction_type));
            // append dynamic routing algorithms to de_result
            de_result.append(
                &mut result
                    .clone()
                    .into_iter()
                    .filter(|record: &routing_types::RoutingDictionaryRecord| {
                        record.kind == routing_types::RoutingAlgorithmKind::Dynamic
                    })
                    .collect::<Vec<_>>(),
            );
        }
        compare_and_log_result(
            de_result.clone(),
            result.clone(),
            "list_routing".to_string(),
        );
        result = build_list_routing_result(
            &state,
            merchant_context,
            &result,
            &de_result,
            profile_ids.clone(),
        )
        .await?;
    }

    metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_types::RoutingKind::RoutingAlgorithm(result),
    ))
}

async fn build_list_routing_result(
    state: &SessionState,
    merchant_context: domain::MerchantContext,
    hs_results: &[routing_types::RoutingDictionaryRecord],
    de_results: &[routing_types::RoutingDictionaryRecord],
    profile_ids: Vec<common_utils::id_type::ProfileId>,
) -> RouterResult<Vec<routing_types::RoutingDictionaryRecord>> {
    let db = state.store.as_ref();
    let key_manager_state = &state.into();
    let mut list_result: Vec<routing_types::RoutingDictionaryRecord> = vec![];
    for profile_id in profile_ids.iter() {
        let by_profile =
            |rec: &&routing_types::RoutingDictionaryRecord| &rec.profile_id == profile_id;
        let de_result_for_profile = de_results.iter().filter(by_profile).cloned().collect();
        let hs_result_for_profile = hs_results.iter().filter(by_profile).cloned().collect();
        let business_profile = core_utils::validate_and_get_business_profile(
            db,
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            Some(profile_id),
            merchant_context.get_merchant_account().get_id(),
        )
        .await?
        .get_required_value("Profile")
        .change_context(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?;

        list_result.append(
            &mut select_routing_result(
                state,
                &business_profile,
                hs_result_for_profile,
                de_result_for_profile,
            )
            .await,
        );
    }
    Ok(list_result)
}

#[cfg(feature = "v2")]
pub async fn create_routing_algorithm_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    request: routing_types::RoutingConfigRequest,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]);
    let db = &*state.store;
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&request.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;
    let merchant_id = merchant_context.get_merchant_account().get_id();
    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
    let all_mcas = state
        .store
        .find_merchant_connector_account_by_merchant_id_and_disabled_list(
            key_manager_state,
            merchant_id,
            true,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .change_context(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_id.get_string_repr().to_owned(),
        })?;

    let name_mca_id_set = helpers::ConnectNameAndMCAIdForProfile(
        all_mcas.filter_by_profile(business_profile.get_id(), |mca| {
            (&mca.connector_name, mca.get_id())
        }),
    );

    let name_set = helpers::ConnectNameForProfile(
        all_mcas.filter_by_profile(business_profile.get_id(), |mca| &mca.connector_name),
    );

    let algorithm_helper = helpers::RoutingAlgorithmHelpers {
        name_mca_id_set,
        name_set,
        routing_algorithm: &request.algorithm,
    };

    algorithm_helper.validate_connectors_in_routing_config()?;

    let algo = RoutingAlgorithmUpdate::create_new_routing_algorithm(
        &request,
        merchant_context.get_merchant_account().get_id(),
        business_profile.get_id().to_owned(),
        transaction_type,
    );

    let record = state
        .store
        .as_ref()
        .insert_routing_algorithm(algo.0)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let new_record = record.foreign_into();

    metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(new_record))
}

#[cfg(feature = "v1")]
pub async fn create_routing_algorithm_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    request: routing_types::RoutingConfigRequest,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    use api_models::routing::StaticRoutingAlgorithm as EuclidAlgorithm;

    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let name = request
        .name
        .get_required_value("name")
        .change_context(errors::ApiErrorResponse::MissingRequiredField { field_name: "name" })
        .attach_printable("Name of config not given")?;

    let description = request
        .description
        .get_required_value("description")
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "description",
        })
        .attach_printable("Description of config not given")?;

    let algorithm = request
        .algorithm
        .clone()
        .get_required_value("algorithm")
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "algorithm",
        })
        .attach_printable("Algorithm of config not given")?;

    let algorithm_id = common_utils::generate_routing_id_of_default_length();

    let profile_id = request
        .profile_id
        .get_required_value("profile_id")
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "profile_id",
        })
        .attach_printable("Profile_id not provided")?;

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;

    if algorithm.should_validate_connectors_in_routing_config() {
        helpers::validate_connectors_in_routing_config(
            &state,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().get_id(),
            &profile_id,
            &algorithm,
        )
        .await?;
    }

    let mut decision_engine_routing_id: Option<String> = None;

    if let Some(euclid_algorithm) = request.algorithm.clone() {
        let maybe_static_algorithm: Option<StaticRoutingAlgorithm> = match euclid_algorithm {
            EuclidAlgorithm::Advanced(program) => match program.try_into() {
                Ok(internal_program) => Some(StaticRoutingAlgorithm::Advanced(internal_program)),
                Err(e) => {
                    router_env::logger::error!(decision_engine_error = ?e, "decision_engine_euclid");
                    None
                }
            },
            EuclidAlgorithm::Single(conn) => {
                Some(StaticRoutingAlgorithm::Single(Box::new(conn.into())))
            }
            EuclidAlgorithm::Priority(connectors) => {
                let converted: Vec<ConnectorInfo> =
                    connectors.into_iter().map(Into::into).collect();
                Some(StaticRoutingAlgorithm::Priority(converted))
            }
            EuclidAlgorithm::VolumeSplit(splits) => {
                let converted: Vec<VolumeSplit<ConnectorInfo>> =
                    splits.into_iter().map(Into::into).collect();
                Some(StaticRoutingAlgorithm::VolumeSplit(converted))
            }
            EuclidAlgorithm::ThreeDsDecisionRule(_) => {
                router_env::logger::error!(
                    "decision_engine_euclid: ThreeDsDecisionRules are not yet implemented"
                );
                None
            }
        };

        if let Some(static_algorithm) = maybe_static_algorithm {
            let routing_rule = RoutingRule {
                rule_id: Some(algorithm_id.clone().get_string_repr().to_owned()),
                name: name.clone(),
                description: Some(description.clone()),
                created_by: profile_id.get_string_repr().to_string(),
                algorithm: static_algorithm,
                algorithm_for: transaction_type.into(),
                metadata: Some(RoutingMetadata {
                    kind: algorithm.get_kind().foreign_into(),
                }),
            };

            match create_de_euclid_routing_algo(&state, &routing_rule).await {
                Ok(id) => {
                    decision_engine_routing_id = Some(id);
                }
                Err(e)
                    if matches!(
                        e.current_context(),
                        errors::RoutingError::DecisionEngineValidationError(_)
                    ) =>
                {
                    if let errors::RoutingError::DecisionEngineValidationError(msg) =
                        e.current_context()
                    {
                        router_env::logger::error!(
                            decision_engine_euclid_error = ?msg,
                            decision_engine_euclid_request = ?routing_rule,
                            "failed to create rule in decision_engine with validation error"
                        );
                    }
                }
                Err(e) => {
                    router_env::logger::error!(
                        decision_engine_euclid_error = ?e,
                        decision_engine_euclid_request = ?routing_rule,
                        "failed to create rule in decision_engine"
                    );
                }
            }
        }
    }

    if decision_engine_routing_id.is_some() {
        router_env::logger::info!(routing_flow=?"create_euclid_routing_algorithm", is_equal=?"true", "decision_engine_euclid");
    } else {
        router_env::logger::info!(routing_flow=?"create_euclid_routing_algorithm", is_equal=?"false", "decision_engine_euclid");
    }

    let timestamp = common_utils::date_time::now();
    let algo = RoutingAlgorithm {
        algorithm_id: algorithm_id.clone(),
        profile_id,
        merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
        name: name.clone(),
        description: Some(description.clone()),
        kind: algorithm.get_kind().foreign_into(),
        algorithm_data: serde_json::json!(algorithm),
        created_at: timestamp,
        modified_at: timestamp,
        algorithm_for: transaction_type.to_owned(),
        decision_engine_routing_id,
    };
    let record = db
        .insert_routing_algorithm(algo)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let new_record = record.foreign_into();

    metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(new_record))
}

#[cfg(feature = "v2")]
pub async fn link_routing_config_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    algorithm_id: common_utils::id_type::RoutingId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_LINK_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let routing_algorithm = RoutingAlgorithmUpdate::fetch_routing_algo(
        merchant_context.get_merchant_account().get_id(),
        &algorithm_id,
        db,
    )
    .await?;

    utils::when(routing_algorithm.0.profile_id != profile_id, || {
        Err(errors::ApiErrorResponse::PreconditionFailed {
            message: "Profile Id is invalid for the routing config".to_string(),
        })
    })?;

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    utils::when(
        routing_algorithm.0.algorithm_for != *transaction_type,
        || {
            Err(errors::ApiErrorResponse::PreconditionFailed {
                message: format!(
                    "Cannot use {}'s routing algorithm for {} operation",
                    routing_algorithm.0.algorithm_for, transaction_type
                ),
            })
        },
    )?;

    utils::when(
        business_profile.routing_algorithm_id == Some(algorithm_id.clone())
            || business_profile.payout_routing_algorithm_id == Some(algorithm_id.clone()),
        || {
            Err(errors::ApiErrorResponse::PreconditionFailed {
                message: "Algorithm is already active".to_string(),
            })
        },
    )?;
    admin::ProfileWrapper::new(business_profile)
        .update_profile_and_invalidate_routing_config_for_active_algorithm_id_update(
            db,
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            algorithm_id,
            transaction_type,
        )
        .await?;

    metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_algorithm.0.foreign_into(),
    ))
}

#[cfg(feature = "v1")]
pub async fn link_routing_config(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    algorithm_id: common_utils::id_type::RoutingId,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_LINK_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let routing_algorithm = db
        .find_routing_algorithm_by_algorithm_id_merchant_id(
            &algorithm_id,
            merchant_context.get_merchant_account().get_id(),
        )
        .await
        .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&routing_algorithm.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: routing_algorithm.profile_id.get_string_repr().to_owned(),
    })?;

    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;

    match routing_algorithm.kind {
        diesel_models::enums::RoutingAlgorithmKind::Dynamic => {
            let mut dynamic_routing_ref: routing_types::DynamicRoutingAlgorithmRef =
                business_profile
                    .dynamic_routing_algorithm
                    .clone()
                    .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
                    .transpose()
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "unable to deserialize Dynamic routing algorithm ref from business profile",
                    )?
                    .unwrap_or_default();

            utils::when(
                matches!(
                    dynamic_routing_ref.success_based_algorithm,
                    Some(routing::SuccessBasedAlgorithm {
                        algorithm_id_with_timestamp:
                        routing_types::DynamicAlgorithmWithTimestamp {
                            algorithm_id: Some(ref id),
                            timestamp: _
                        },
                        enabled_feature: _
                    }) if id == &algorithm_id
                ) || matches!(
                    dynamic_routing_ref.elimination_routing_algorithm,
                    Some(routing::EliminationRoutingAlgorithm {
                        algorithm_id_with_timestamp:
                        routing_types::DynamicAlgorithmWithTimestamp {
                            algorithm_id: Some(ref id),
                            timestamp: _
                        },
                        enabled_feature: _
                    }) if id == &algorithm_id
                ) || matches!(
                    dynamic_routing_ref.contract_based_routing,
                    Some(routing::ContractRoutingAlgorithm {
                        algorithm_id_with_timestamp:
                        routing_types::DynamicAlgorithmWithTimestamp {
                            algorithm_id: Some(ref id),
                            timestamp: _
                        },
                        enabled_feature: _
                    }) if id == &algorithm_id
                ),
                || {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Algorithm is already active".to_string(),
                    })
                },
            )?;

            if routing_algorithm.name == helpers::SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM {
                dynamic_routing_ref.update_algorithm_id(
                algorithm_id,
                dynamic_routing_ref
                    .success_based_algorithm
                    .clone()
                    .ok_or(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "missing success_based_algorithm in dynamic_algorithm_ref from business_profile table",
                    )?
                    .enabled_feature,
                routing_types::DynamicRoutingType::SuccessRateBasedRouting,
            );

                // Call to DE here to update SR configs
                #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                {
                    if state.conf.open_router.dynamic_routing_enabled {
                        let existing_config = helpers::get_decision_engine_active_dynamic_routing_algorithm(
                        &state,
                        business_profile.get_id(),
                        api_models::open_router::DecisionEngineDynamicAlgorithmType::SuccessRate,
                    )
                    .await;

                        if let Ok(Some(_config)) = existing_config {
                            update_decision_engine_dynamic_routing_setup(
                            &state,
                            business_profile.get_id(),
                            routing_algorithm.algorithm_data.clone(),
                            routing_types::DynamicRoutingType::SuccessRateBasedRouting,
                            &mut dynamic_routing_ref,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "Failed to update the success rate routing config in Decision Engine",
                        )?;
                        } else {
                            let data: routing_types::SuccessBasedRoutingConfig =
                            routing_algorithm.algorithm_data
                                .clone()
                                .parse_value("SuccessBasedRoutingConfig")
                                .change_context(errors::ApiErrorResponse::InternalServerError)
                                .attach_printable(
                                    "unable to deserialize SuccessBasedRoutingConfig from routing algorithm data",
                                )?;

                            enable_decision_engine_dynamic_routing_setup(
                            &state,
                            business_profile.get_id(),
                            routing_types::DynamicRoutingType::SuccessRateBasedRouting,
                            &mut dynamic_routing_ref,
                            Some(routing_types::DynamicRoutingPayload::SuccessBasedRoutingPayload(data)),
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Unable to setup decision engine dynamic routing")?;
                        }
                    }
                }
            } else if routing_algorithm.name == helpers::ELIMINATION_BASED_DYNAMIC_ROUTING_ALGORITHM
            {
                dynamic_routing_ref.update_algorithm_id(
                algorithm_id,
                dynamic_routing_ref
                    .elimination_routing_algorithm
                    .clone()
                    .ok_or(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "missing elimination_routing_algorithm in dynamic_algorithm_ref from business_profile table",
                    )?
                    .enabled_feature,
                routing_types::DynamicRoutingType::EliminationRouting,
            );
                #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                {
                    if state.conf.open_router.dynamic_routing_enabled {
                        let existing_config = helpers::get_decision_engine_active_dynamic_routing_algorithm(
                            &state,
                            business_profile.get_id(),
                            api_models::open_router::DecisionEngineDynamicAlgorithmType::Elimination,
                        )
                        .await;

                        if let Ok(Some(_config)) = existing_config {
                            update_decision_engine_dynamic_routing_setup(
                                &state,
                                business_profile.get_id(),
                                routing_algorithm.algorithm_data.clone(),
                                routing_types::DynamicRoutingType::EliminationRouting,
                                &mut dynamic_routing_ref,
                            )
                            .await
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable(
                                "Failed to update the elimination routing config in Decision Engine",
                            )?;
                        } else {
                            let data: routing_types::EliminationRoutingConfig =
                                routing_algorithm.algorithm_data
                                    .clone()
                                    .parse_value("EliminationRoutingConfig")
                                    .change_context(errors::ApiErrorResponse::InternalServerError)
                                    .attach_printable(
                                        "unable to deserialize EliminationRoutingConfig from routing algorithm data",
                                    )?;

                            enable_decision_engine_dynamic_routing_setup(
                                &state,
                                business_profile.get_id(),
                                routing_types::DynamicRoutingType::EliminationRouting,
                                &mut dynamic_routing_ref,
                                Some(
                                    routing_types::DynamicRoutingPayload::EliminationRoutingPayload(
                                        data,
                                    ),
                                ),
                            )
                            .await
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Unable to setup decision engine dynamic routing")?;
                        }
                    }
                }
            } else if routing_algorithm.name == helpers::CONTRACT_BASED_DYNAMIC_ROUTING_ALGORITHM {
                dynamic_routing_ref.update_algorithm_id(
                algorithm_id,
                dynamic_routing_ref
                    .contract_based_routing
                    .clone()
                    .ok_or(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "missing contract_based_routing in dynamic_algorithm_ref from business_profile table",
                    )?
                    .enabled_feature,
                routing_types::DynamicRoutingType::ContractBasedRouting,
            );
            }

            helpers::update_business_profile_active_dynamic_algorithm_ref(
                db,
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                business_profile.clone(),
                dynamic_routing_ref,
            )
            .await?;
        }
        diesel_models::enums::RoutingAlgorithmKind::Single
        | diesel_models::enums::RoutingAlgorithmKind::Priority
        | diesel_models::enums::RoutingAlgorithmKind::Advanced
        | diesel_models::enums::RoutingAlgorithmKind::VolumeSplit
        | diesel_models::enums::RoutingAlgorithmKind::ThreeDsDecisionRule => {
            let mut routing_ref: routing_types::RoutingAlgorithmRef = business_profile
                .routing_algorithm
                .clone()
                .map(|val| val.parse_value("RoutingAlgorithmRef"))
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "unable to deserialize routing algorithm ref from business profile",
                )?
                .unwrap_or_default();

            utils::when(routing_algorithm.algorithm_for != transaction_type, || {
                Err(errors::ApiErrorResponse::PreconditionFailed {
                    message: format!(
                        "Cannot use {}'s routing algorithm for {} operation",
                        routing_algorithm.algorithm_for, transaction_type
                    ),
                })
            })?;

            utils::when(
                routing_ref.algorithm_id == Some(algorithm_id.clone()),
                || {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Algorithm is already active".to_string(),
                    })
                },
            )?;
            routing_ref.update_algorithm_id(algorithm_id);
            helpers::update_profile_active_algorithm_ref(
                db,
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                business_profile.clone(),
                routing_ref,
                &transaction_type,
            )
            .await?;
        }
    };
    if let Some(euclid_routing_id) = routing_algorithm.decision_engine_routing_id.clone() {
        let routing_algo = ActivateRoutingConfigRequest {
            created_by: business_profile.get_id().get_string_repr().to_string(),
            routing_algorithm_id: euclid_routing_id,
        };
        let link_result = link_de_euclid_routing_algorithm(&state, routing_algo).await;
        match link_result {
            Ok(_) => {
                router_env::logger::info!(
                    routing_flow=?"link_routing_algorithm",
                    is_equal=?true,
                    "decision_engine_euclid"
                );
            }
            Err(e) => {
                router_env::logger::info!(
                    routing_flow=?"link_routing_algorithm",
                    is_equal=?false,
                    error=?e,
                    "decision_engine_euclid"
                );
            }
        }
    }
    metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_algorithm.foreign_into(),
    ))
}

#[cfg(feature = "v2")]
pub async fn retrieve_routing_algorithm_from_algorithm_id(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    algorithm_id: common_utils::id_type::RoutingId,
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
    metrics::ROUTING_RETRIEVE_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let routing_algorithm = RoutingAlgorithmUpdate::fetch_routing_algo(
        merchant_context.get_merchant_account().get_id(),
        &algorithm_id,
        db,
    )
    .await?;
    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&routing_algorithm.0.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;

    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;

    let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm.0)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("unable to parse routing algorithm")?;

    metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(response))
}

#[cfg(feature = "v1")]
pub async fn retrieve_routing_algorithm_from_algorithm_id(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    algorithm_id: common_utils::id_type::RoutingId,
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
    metrics::ROUTING_RETRIEVE_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let routing_algorithm = db
        .find_routing_algorithm_by_algorithm_id_merchant_id(
            &algorithm_id,
            merchant_context.get_merchant_account().get_id(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&routing_algorithm.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;

    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;

    let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("unable to parse routing algorithm")?;

    metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(response))
}

#[cfg(feature = "v2")]
pub async fn unlink_routing_config_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_UNLINK_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    let routing_algo_id = match transaction_type {
        enums::TransactionType::Payment => business_profile.routing_algorithm_id.clone(),
        #[cfg(feature = "payouts")]
        enums::TransactionType::Payout => business_profile.payout_routing_algorithm_id.clone(),
        // TODO: Handle ThreeDsAuthentication Transaction Type for Three DS Decision Rule Algorithm configuration
        enums::TransactionType::ThreeDsAuthentication => todo!(),
    };

    if let Some(algorithm_id) = routing_algo_id {
        let record = RoutingAlgorithmUpdate::fetch_routing_algo(
            merchant_context.get_merchant_account().get_id(),
            &algorithm_id,
            db,
        )
        .await?;
        let response = record.0.foreign_into();
        admin::ProfileWrapper::new(business_profile)
            .update_profile_and_invalidate_routing_config_for_active_algorithm_id_update(
                db,
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                algorithm_id,
                transaction_type,
            )
            .await?;
        metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
        Ok(service_api::ApplicationResponse::Json(response))
    } else {
        Err(errors::ApiErrorResponse::PreconditionFailed {
            message: "Algorithm is already inactive".to_string(),
        })?
    }
}

#[cfg(feature = "v1")]
pub async fn unlink_routing_config(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    request: routing_types::RoutingConfigRequest,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_UNLINK_CONFIG.add(1, &[]);

    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let profile_id = request
        .profile_id
        .get_required_value("profile_id")
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "profile_id",
        })
        .attach_printable("Profile_id not provided")?;

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?;

    match business_profile {
        Some(business_profile) => {
            core_utils::validate_profile_id_from_auth_layer(
                authentication_profile_id,
                &business_profile,
            )?;
            let routing_algo_ref: routing_types::RoutingAlgorithmRef = match transaction_type {
                enums::TransactionType::Payment => business_profile.routing_algorithm.clone(),
                #[cfg(feature = "payouts")]
                enums::TransactionType::Payout => business_profile.payout_routing_algorithm.clone(),
                enums::TransactionType::ThreeDsAuthentication => {
                    business_profile.three_ds_decision_rule_algorithm.clone()
                }
            }


// Implementation: impl PayoutAttemptInterface for for KVRouterStore
// File: crates/storage_impl/src/kv_router_store.rs
// Module: storage_impl
// Methods: 0 total (0 public)

impl PayoutAttemptInterface for for KVRouterStore


// Struct: RefundSuccessRate
// File: crates/api_models/src/analytics/refunds.rs
// Module: api_models
// Implementations: 0

pub struct RefundSuccessRate


// Implementation: impl Theme
// File: crates/diesel_models/src/query/user/theme.rs
// Module: diesel_models
// Methods: 9 total (0 public)

impl Theme


// Function: log_event
// File: crates/router/src/events/event_logger.rs
// Module: router

pub fn log_event<T: KafkaMessage>(&self, event: &T)


// Implementation: impl Responder
// File: crates/router/src/routes/payments.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


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

impl api::PaymentVoid for for Tokenio


// Implementation: impl common_utils::events::ApiEventMetric for for ThreeDsDecisionRuleExecuteResponse
// File: crates/api_models/src/three_ds_decision_rule.rs
// Module: api_models
// Methods: 1 total (0 public)

impl common_utils::events::ApiEventMetric for for ThreeDsDecisionRuleExecuteResponse


// Implementation: impl api::Payouts for for Nomupay
// File: crates/hyperswitch_connectors/src/connectors/nomupay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payouts for for Nomupay


// Function: get_payment_intent_filter_for_dimension
// File: crates/analytics/src/payment_intents/filters.rs
// Module: analytics

pub fn get_payment_intent_filter_for_dimension<T>(
    dimension: PaymentIntentDimensions,
    merchant_id: &common_utils::id_type::MerchantId,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<PaymentIntentFilterRow>>
where
    T: AnalyticsDataSource + PaymentIntentFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,


// Module Structure
// File: crates/router/src/compatibility/stripe/customers.rs
// Module: router

// Public submodules:
pub mod types;


// Struct: SignifydRefund
// File: crates/hyperswitch_connectors/src/connectors/signifyd/transformers/api.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SignifydRefund


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

impl api::PaymentVoid for for Bambora


// Implementation: impl ThreeDSDecision
// File: crates/common_types/src/three_ds_decision_rule_engine.rs
// Module: common_types
// Methods: 1 total (1 public)

impl ThreeDSDecision


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

// Documentation: Get the entity_type from the lineage

pub fn entity_type(&self) -> EntityType


// Function: get_message
// File: crates/hyperswitch_connectors/src/connectors/tokenio/transformers.rs
// Module: hyperswitch_connectors

pub fn get_message(&self) -> String


// Function: insert
// File: crates/diesel_models/src/query/role.rs
// Module: diesel_models

pub fn insert(self, conn: &PgPooledConn) -> StorageResult<Role>


// Implementation: impl TraceUrlAssert
// File: crates/router_env/src/logger/setup.rs
// Module: router_env
// Methods: 1 total (0 public)

impl TraceUrlAssert


// File: crates/hyperswitch_domain_models/src/merchant_context.rs
// Module: hyperswitch_domain_models
// Public functions: 2
// Public structs: 1

pub use crate::{merchant_account::MerchantAccount, merchant_key_store::MerchantKeyStore};

/// `MerchantContext` represents the authentication and operational context for a merchant.
///
/// This enum encapsulates the merchant's account information and cryptographic keys
/// needed for secure operations. Currently supports only normal merchant operations,
/// but the enum structure allows for future expansion to different merchant types for example a
/// **platform** context.
#[derive(Clone, Debug)]
pub enum MerchantContext {
    /// Represents a normal operation merchant context.
    NormalMerchant(Box<Context>),
}
/// `Context` holds the merchant account details and cryptographic key store.
#[derive(Clone, Debug)]
pub struct Context(pub MerchantAccount, pub MerchantKeyStore);

impl MerchantContext {
    pub fn get_merchant_account(&self) -> &MerchantAccount {
        match self {
            Self::NormalMerchant(merchant_account) => &merchant_account.0,
        }
    }

    pub fn get_merchant_key_store(&self) -> &MerchantKeyStore {
        match self {
            Self::NormalMerchant(merchant_account) => &merchant_account.1,
        }
    }
}


// Struct: RoutingVolumeSplit
// File: crates/api_models/src/routing.rs
// Module: api_models
// Implementations: 0

pub struct RoutingVolumeSplit


// Implementation: impl api::PaymentSession for for Cashtocode
// File: crates/hyperswitch_connectors/src/connectors/cashtocode.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Cashtocode


// Function: payment_complete
// File: crates/router/src/routes/dummy_connector/core.rs
// Module: router

pub fn payment_complete(
    state: SessionState,
    req: types::DummyConnectorPaymentCompleteRequest,
) -> types::DummyConnectorResponse<()>


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

impl Cache


// Struct: PlaidLinkTokenResponse
// File: crates/hyperswitch_connectors/src/connectors/plaid/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PlaidLinkTokenResponse


// Function: retrieve_routing_algorithm_from_algorithm_id
// File: crates/router/src/core/routing.rs
// Module: router

pub fn retrieve_routing_algorithm_from_algorithm_id(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    algorithm_id: common_utils::id_type::RoutingId,
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm>