// File: crates/hyperswitch_connectors/src/connectors/hipay/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 14

use std::collections::HashMap;

use common_enums::{enums, CardNetwork};
use common_utils::{
    pii::{self},
    request::Method,
    types::StringMajorUnit,
};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{
        AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
        ErrorResponse, PaymentMethodToken, RouterData,
    },
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{BrowserInformation, PaymentsAuthorizeData, ResponseId},
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundsRouterData, TokenizationRouterData,
    },
};
use hyperswitch_interfaces::{
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    errors,
};
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{
    types::{
        PaymentsCancelResponseRouterData, PaymentsCaptureResponseRouterData,
        PaymentsSyncResponseRouterData, RefundsResponseRouterData, ResponseRouterData,
    },
    unimplemented_payment_method,
    utils::{self, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, RouterData as _},
};

pub struct HipayRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}

impl<T> From<(StringMajorUnit, T)> for HipayRouterData<T> {
    fn from((amount, item): (StringMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Operation {
    Authorization,
    Sale,
    Capture,
    Refund,
    Cancel,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HipayBrowserInfo {
    java_enabled: Option<bool>,
    javascript_enabled: Option<bool>,
    ipaddr: Option<std::net::IpAddr>,
    http_accept: String,
    http_user_agent: Option<String>,
    language: Option<String>,
    color_depth: Option<u8>,
    screen_height: Option<u32>,
    screen_width: Option<u32>,
    timezone: Option<i32>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HipayPaymentsRequest {
    operation: Operation,
    authentication_indicator: u8,
    cardtoken: Secret<String>,
    orderid: String,
    currency: enums::Currency,
    payment_product: String,
    amount: StringMajorUnit,
    description: String,
    decline_url: Option<String>,
    pending_url: Option<String>,
    cancel_url: Option<String>,
    accept_url: Option<String>,
    notify_url: Option<String>,
    #[serde(flatten)]
    #[serde(skip_serializing_if = "Option::is_none")]
    three_ds_data: Option<ThreeDSPaymentData>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ThreeDSPaymentData {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub firstname: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lastname: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<pii::Email>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub streetaddress: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub city: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub zipcode: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<enums::CountryAlpha2>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub browser_info: Option<HipayBrowserInfo>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HipayMaintenanceRequest {
    operation: Operation,
    currency: Option<enums::Currency>,
    amount: Option<StringMajorUnit>,
}
impl From<BrowserInformation> for HipayBrowserInfo {
    fn from(browser_info: BrowserInformation) -> Self {
        Self {
            java_enabled: browser_info.java_enabled,
            javascript_enabled: browser_info.java_script_enabled,
            ipaddr: browser_info.ip_address,
            http_accept: "*/*".to_string(),
            http_user_agent: browser_info.user_agent,
            language: browser_info.language,
            color_depth: browser_info.color_depth,
            screen_height: browser_info.screen_height,
            screen_width: browser_info.screen_width,
            timezone: browser_info.time_zone,
        }
    }
}

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct HiPayTokenRequest {
    pub card_number: cards::CardNumber,
    pub card_expiry_month: Secret<String>,
    pub card_expiry_year: Secret<String>,
    pub card_holder: Secret<String>,
    pub cvc: Secret<String>,
}
impl TryFrom<&HipayRouterData<&PaymentsAuthorizeRouterData>> for HipayPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &HipayRouterData<&PaymentsAuthorizeRouterData>) -> Result<Self, Self::Error> {
        let (domestic_card_network, domestic_network) = item
            .router_data
            .connector_response
            .clone()
            .and_then(|response| match response.additional_payment_method_data {
                Some(AdditionalPaymentMethodConnectorResponse::Card {
                    card_network,
                    domestic_network,
                    ..
                }) => Some((card_network, domestic_network)),
                _ => None,
            })
            .unwrap_or_default();

        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => Ok(Self {
                operation: if item.router_data.request.is_auto_capture()? {
                    Operation::Sale
                } else {
                    Operation::Authorization
                },
                authentication_indicator: if item.router_data.is_three_ds() { 2 } else { 0 },
                cardtoken: match item.router_data.get_payment_method_token()? {
                    PaymentMethodToken::Token(token) => token,
                    PaymentMethodToken::ApplePayDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Apple Pay", "Hipay").into());
                    }
                    PaymentMethodToken::PazeDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Paze", "Hipay").into());
                    }
                    PaymentMethodToken::GooglePayDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Google Pay", "Hipay").into());
                    }
                },
                orderid: item.router_data.connector_request_reference_id.clone(),
                currency: item.router_data.request.currency,
                payment_product: match (domestic_network, domestic_card_network.as_deref()) {
                    (Some(domestic), _) => domestic,
                    (None, Some("VISA")) => "visa".to_string(),
                    (None, Some("MASTERCARD")) => "mastercard".to_string(),
                    (None, Some("MAESTRO")) => "maestro".to_string(),
                    (None, Some("AMERICAN EXPRESS")) => "american-express".to_string(),
                    (None, Some("CB")) => "cb".to_string(),
                    (None, Some("BCMC")) => "bcmc".to_string(),
                    (None, _) => match req_card.card_network {
                        Some(CardNetwork::Visa) => "visa".to_string(),
                        Some(CardNetwork::Mastercard) => "mastercard".to_string(),
                        Some(CardNetwork::AmericanExpress) => "american-express".to_string(),
                        Some(CardNetwork::JCB) => "jcb".to_string(),
                        Some(CardNetwork::DinersClub) => "diners".to_string(),
                        Some(CardNetwork::Discover) => "discover".to_string(),
                        Some(CardNetwork::CartesBancaires) => "cb".to_string(),
                        Some(CardNetwork::UnionPay) => "unionpay".to_string(),
                        Some(CardNetwork::Interac) => "interac".to_string(),
                        Some(CardNetwork::RuPay) => "rupay".to_string(),
                        Some(CardNetwork::Maestro) => "maestro".to_string(),
                        Some(CardNetwork::Star)
                        | Some(CardNetwork::Accel)
                        | Some(CardNetwork::Pulse)
                        | Some(CardNetwork::Nyce)
                        | None => "".to_string(),
                    },
                },
                amount: item.amount.clone(),
                description: item
                    .router_data
                    .get_description()
                    .map(|s| s.to_string())
                    .unwrap_or("Short Description".to_string()),
                decline_url: item.router_data.request.router_return_url.clone(),
                pending_url: item.router_data.request.router_return_url.clone(),
                cancel_url: item.router_data.request.router_return_url.clone(),
                accept_url: item.router_data.request.router_return_url.clone(),
                notify_url: item.router_data.request.router_return_url.clone(),
                three_ds_data: if item.router_data.is_three_ds() {
                    let billing_address = item.router_data.get_billing_address()?;
                    Some(ThreeDSPaymentData {
                        firstname: billing_address.get_optional_first_name(),
                        lastname: billing_address.get_optional_last_name(),
                        email: Some(
                            item.router_data
                                .get_billing_email()
                                .or(item.router_data.request.get_email())?,
                        ),
                        city: billing_address.get_optional_city(),
                        streetaddress: billing_address.get_optional_line1(),
                        zipcode: billing_address.get_optional_zip(),
                        state: billing_address.get_optional_state(),
                        country: billing_address.get_optional_country(),
                        browser_info: Some(HipayBrowserInfo::from(
                            item.router_data.request.get_browser_info()?,
                        )),
                    })
                } else {
                    None
                },
            }),
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}
impl TryFrom<&TokenizationRouterData> for HiPayTokenRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &TokenizationRouterData) -> Result<Self, Self::Error> {
        match item.request.payment_method_data.clone() {
            PaymentMethodData::Card(card_data) => Ok(Self {
                card_number: card_data.card_number.clone(),
                card_expiry_month: card_data.card_exp_month.clone(),
                card_expiry_year: card_data.get_expiry_year_4_digit(),
                card_holder: item.get_billing_full_name()?,
                cvc: card_data.card_cvc,
            }),
            _ => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Hipay"),
            )
            .into()),
        }
    }
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct HipayTokenResponse {
    token: Secret<String>,
    brand: String,
    domestic_network: Option<String>,
}

impl From<&HipayTokenResponse> for AdditionalPaymentMethodConnectorResponse {
    fn from(hipay_token_response: &HipayTokenResponse) -> Self {
        Self::Card {
            authentication_data: None,
            payment_checks: None,
            card_network: Some(hipay_token_response.brand.clone()),
            domestic_network: hipay_token_response.domestic_network.clone(),
        }
    }
}

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

impl<F, T> TryFrom<ResponseRouterData<F, HipayTokenResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, HipayTokenResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PaymentsResponseData::TokenizationResponse {
                token: item.response.token.clone().expose(),
            }),
            connector_response: Some(ConnectorResponseData::with_additional_payment_method_data(
                AdditionalPaymentMethodConnectorResponse::from(&item.response),
            )),
            ..item.data
        })
    }
}

pub struct HipayAuthType {
    pub(super) api_key: Secret<String>,
    pub(super) key1: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for HipayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                api_key: api_key.clone(),
                key1: key1.clone(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HipayPaymentsResponse {
    status: HipayPaymentStatus,
    message: String,
    order: PaymentOrder,
    forward_url: String,
    transaction_reference: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaymentOrder {
    id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HipayMaintenanceResponse<S> {
    status: S,
    message: String,
    transaction_reference: String,
}
impl<F>
    TryFrom<
        ResponseRouterData<F, HipayPaymentsResponse, PaymentsAuthorizeData, PaymentsResponseData>,
    > for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            HipayPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let status = common_enums::AttemptStatus::from(item.response.status);
        let response = if status == enums::AttemptStatus::Failure {
            Err(ErrorResponse {
                code: NO_ERROR_CODE.to_string(),
                message: item.response.message.clone(),
                reason: Some(item.response.message.clone()),
                attempt_status: None,
                connector_transaction_id: Some(item.response.transaction_reference),
                status_code: item.http_code,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference,
                ),
                redirection_data: match item.data.is_three_ds() {
                    true => Box::new(Some(RedirectForm::Form {
                        endpoint: item.response.forward_url,
                        method: Method::Get,
                        form_fields: HashMap::new(),
                    })),
                    false => Box::new(None),
                },
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            })
        };
        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

impl<F> TryFrom<&HipayRouterData<&RefundsRouterData<F>>> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &HipayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            operation: Operation::Refund,
            currency: Some(item.router_data.request.currency),
        })
    }
}
impl TryFrom<&PaymentsCancelRouterData> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            operation: Operation::Cancel,
            currency: item.request.currency,
            amount: None,
        })
    }
}
impl TryFrom<&HipayRouterData<&PaymentsCaptureRouterData>> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &HipayRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            operation: Operation::Capture,
            currency: Some(item.router_data.request.currency),
        })
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum RefundStatus {
    #[serde(rename = "124")]
    RefundRequested,
    #[serde(rename = "125")]
    Refunded,
    #[serde(rename = "126")]
    PartiallyRefunded,
    #[serde(rename = "165")]
    RefundRefused,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::RefundRequested => Self::Pending,
            RefundStatus::Refunded | RefundStatus::PartiallyRefunded => Self::Success,
            RefundStatus::RefundRefused => Self::Failure,
        }
    }
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum HipayPaymentStatus {
    #[serde(rename = "109")]
    AuthenticationFailed,
    #[serde(rename = "110")]
    Blocked,
    #[serde(rename = "111")]
    Denied,
    #[serde(rename = "112")]
    AuthorizedAndPending,
    #[serde(rename = "113")]
    Refused,
    #[serde(rename = "114")]
    Expired,
    #[serde(rename = "115")]
    Cancelled,
    #[serde(rename = "116")]
    Authorized,
    #[serde(rename = "117")]
    CaptureRequested,
    #[serde(rename = "118")]
    Captured,
    #[serde(rename = "119")]
    PartiallyCaptured,
    #[serde(rename = "129")]
    ChargedBack,
    #[serde(rename = "173")]
    CaptureRefused,
    #[serde(rename = "174")]
    AwaitingTerminal,
    #[serde(rename = "175")]
    AuthorizationCancellationRequested,
    #[serde(rename = "177")]
    ChallengeRequested,
    #[serde(rename = "178")]
    SoftDeclined,
    #[serde(rename = "200")]
    PendingPayment,
    #[serde(rename = "101")]
    Created,
    #[serde(rename = "105")]
    UnableToAuthenticate,
    #[serde(rename = "106")]
    CardholderAuthenticated,
    #[serde(rename = "107")]
    AuthenticationAttempted,
    #[serde(rename = "108")]
    CouldNotAuthenticate,
    #[serde(rename = "120")]
    Collected,
    #[serde(rename = "121")]
    PartiallyCollected,
    #[serde(rename = "122")]
    Settled,
    #[serde(rename = "123")]
    PartiallySettled,
    #[serde(rename = "140")]
    AuthenticationRequested,
    #[serde(rename = "141")]
    Authenticated,
    #[serde(rename = "151")]
    AcquirerNotFound,
    #[serde(rename = "161")]
    RiskAccepted,
    #[serde(rename = "163")]
    AuthorizationRefused,
}
impl From<HipayPaymentStatus> for common_enums::AttemptStatus {
    fn from(status: HipayPaymentStatus) -> Self {
        match status {
            HipayPaymentStatus::AuthenticationFailed => Self::AuthenticationFailed,
            HipayPaymentStatus::Blocked
            | HipayPaymentStatus::Refused
            | HipayPaymentStatus::Expired
            | HipayPaymentStatus::Denied => Self::Failure,
            HipayPaymentStatus::AuthorizedAndPending => Self::Pending,
            HipayPaymentStatus::Cancelled => Self::Voided,
            HipayPaymentStatus::Authorized => Self::Authorized,
            HipayPaymentStatus::CaptureRequested => Self::CaptureInitiated,
            HipayPaymentStatus::Captured => Self::Charged,
            HipayPaymentStatus::PartiallyCaptured => Self::PartialCharged,
            HipayPaymentStatus::CaptureRefused => Self::CaptureFailed,
            HipayPaymentStatus::AwaitingTerminal => Self::Pending,
            HipayPaymentStatus::AuthorizationCancellationRequested => Self::VoidInitiated,
            HipayPaymentStatus::ChallengeRequested => Self::AuthenticationPending,
            HipayPaymentStatus::SoftDeclined => Self::Failure,
            HipayPaymentStatus::PendingPayment => Self::Pending,
            HipayPaymentStatus::ChargedBack => Self::Failure,
            HipayPaymentStatus::Created => Self::Started,
            HipayPaymentStatus::UnableToAuthenticate | HipayPaymentStatus::CouldNotAuthenticate => {
                Self::AuthenticationFailed
            }
            HipayPaymentStatus::CardholderAuthenticated => Self::Pending,
            HipayPaymentStatus::AuthenticationAttempted => Self::AuthenticationPending,
            HipayPaymentStatus::Collected
            | HipayPaymentStatus::PartiallySettled
            | HipayPaymentStatus::PartiallyCollected
            | HipayPaymentStatus::Settled => Self::Charged,
            HipayPaymentStatus::AuthenticationRequested => Self::AuthenticationPending,
            HipayPaymentStatus::Authenticated => Self::AuthenticationSuccessful,
            HipayPaymentStatus::AcquirerNotFound => Self::Failure,
            HipayPaymentStatus::RiskAccepted => Self::Pending,
            HipayPaymentStatus::AuthorizationRefused => Self::Failure,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
    id: u64,
    status: u16,
}

impl TryFrom<RefundsResponseRouterData<Execute, HipayMaintenanceResponse<RefundStatus>>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, HipayMaintenanceResponse<RefundStatus>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.transaction_reference,
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: match item.response.status {
                    25 | 26 => enums::RefundStatus::Success,
                    65 => enums::RefundStatus::Failure,
                    24 => enums::RefundStatus::Pending,
                    _ => enums::RefundStatus::Pending,
                },
            }),
            ..item.data
        })
    }
}

impl TryFrom<PaymentsCaptureResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>>
    for PaymentsCaptureRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCaptureResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference.clone().to_string(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}
impl TryFrom<PaymentsCancelResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>>
    for PaymentsCancelRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCancelResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference.clone().to_string(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Reason {
    reason: Option<String>,
    code: Option<u64>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum HipaySyncResponse {
    Response { status: i32, reason: Reason },
    Error { message: String, code: u32 },
}
fn get_sync_status(state: i32) -> enums::AttemptStatus {
    match state {
        9 => enums::AttemptStatus::AuthenticationFailed,
        10 => enums::AttemptStatus::Failure,
        11 => enums::AttemptStatus::Failure,
        12 => enums::AttemptStatus::Pending,
        13 => enums::AttemptStatus::Failure,
        14 => enums::AttemptStatus::Failure,
        15 => enums::AttemptStatus::Voided,
        16 => enums::AttemptStatus::Authorized,
        17 => enums::AttemptStatus::CaptureInitiated,
        18 => enums::AttemptStatus::Charged,
        19 => enums::AttemptStatus::PartialCharged,
        29 => enums::AttemptStatus::Failure,
        73 => enums::AttemptStatus::CaptureFailed,
        74 => enums::AttemptStatus::Pending,
        75 => enums::AttemptStatus::VoidInitiated,
        77 => enums::AttemptStatus::AuthenticationPending,
        78 => enums::AttemptStatus::Failure,
        200 => enums::AttemptStatus::Pending,
        1 => enums::AttemptStatus::Started,
        5 => enums::AttemptStatus::AuthenticationFailed,
        6 => enums::AttemptStatus::Pending,
        7 => enums::AttemptStatus::AuthenticationPending,
        8 => enums::AttemptStatus::AuthenticationFailed,
        20 => enums::AttemptStatus::Charged,
        21 => enums::AttemptStatus::Charged,
        22 => enums::AttemptStatus::Charged,
        23 => enums::AttemptStatus::Charged,
        40 => enums::AttemptStatus::AuthenticationPending,
        41 => enums::AttemptStatus::AuthenticationSuccessful,
        51 => enums::AttemptStatus::Failure,
        61 => enums::AttemptStatus::Pending,
        63 => enums::AttemptStatus::Failure,
        _ => enums::AttemptStatus::Failure,
    }
}

impl TryFrom<PaymentsSyncResponseRouterData<HipaySyncResponse>> for PaymentsSyncRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: PaymentsSyncResponseRouterData<HipaySyncResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response {
            HipaySyncResponse::Error { message, code } => {
                let response = Err(ErrorResponse {
                    code: code.to_string(),
                    message: message.clone(),
                    reason: Some(message.clone()),
                    attempt_status: None,
                    connector_transaction_id: None,
                    status_code: item.http_code,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                });
                Ok(Self {
                    status: enums::AttemptStatus::Failure,
                    response,
                    ..item.data
                })
            }
            HipaySyncResponse::Response { status, reason } => {
                let status = get_sync_status(status);
                let response = if status == enums::AttemptStatus::Failure {
                    let error_code = reason
                        .code
                        .map_or(NO_ERROR_CODE.to_string(), |c| c.to_string());
                    let error_message = reason
                        .reason
                        .clone()
                        .unwrap_or_else(|| NO_ERROR_MESSAGE.to_owned());
                    Err(ErrorResponse {
                        code: error_code,
                        message: error_message.clone(),
                        reason: Some(error_message),
                        status_code: item.http_code,
                        attempt_status: None,
                        connector_transaction_id: None,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    })
                } else {
                    Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::NoResponseId,
                        redirection_data: Box::new(None),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        connector_response_reference_id: None,
                        incremental_authorization_allowed: None,
                        charges: None,
                    })
                };
                Ok(Self {
                    status,
                    response,
                    ..item.data
                })
            }
        }
    }
}


// Implementation: impl RoutingProfileMetadata
// File: crates/diesel_models/src/routing_algorithm.rs
// Module: diesel_models
// Methods: 1 total (1 public)

impl RoutingProfileMetadata


            Ok(())
        }
        Err(err) => {
            logger::error!("open_router_update_gateway_score_error: {:?}", err);

            Err(errors::RoutingError::OpenRouterError(
                "Failed to update gateway score in open_router".into(),
            ))
        }
    }?;

    Ok(())
}

/// success based dynamic routing
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
#[allow(clippy::too_many_arguments)]
pub async fn perform_success_based_routing<F, D>(
    state: &SessionState,
    routable_connectors: Vec<api_routing::RoutableConnectorChoice>,
    profile_id: &common_utils::id_type::ProfileId,
    merchant_id: &common_utils::id_type::MerchantId,
    payment_id: &common_utils::id_type::PaymentId,
    success_based_routing_config_params_interpolator: routing::helpers::DynamicRoutingConfigParamsInterpolator,
    success_based_algo_ref: api_routing::SuccessBasedAlgorithm,
    payment_data: &mut D,
) -> RoutingResult<Vec<api_routing::RoutableConnectorChoice>>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    if success_based_algo_ref.enabled_feature
        == api_routing::DynamicRoutingFeatures::DynamicConnectorSelection
    {
        logger::debug!(
            "performing success_based_routing for profile {}",
            profile_id.get_string_repr()
        );
        let client = &state
            .grpc_client
            .dynamic_routing
            .as_ref()
            .ok_or(errors::RoutingError::SuccessRateClientInitializationError)
            .attach_printable("dynamic routing gRPC client not found")?
            .success_rate_client;

        let success_based_routing_configs = routing::helpers::fetch_dynamic_routing_configs::<
            api_routing::SuccessBasedRoutingConfig,
        >(
            state,
            profile_id,
            success_based_algo_ref
                .algorithm_id_with_timestamp
                .algorithm_id
                .ok_or(errors::RoutingError::GenericNotFoundError {
                    field: "success_based_routing_algorithm_id".to_string(),
                })
                .attach_printable("success_based_routing_algorithm_id not found in profile_id")?,
        )
        .await
        .change_context(errors::RoutingError::SuccessBasedRoutingConfigError)
        .attach_printable("unable to fetch success_rate based dynamic routing configs")?;

        let success_based_routing_config_params = success_based_routing_config_params_interpolator
            .get_string_val(
                success_based_routing_configs
                    .params
                    .as_ref()
                    .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError)?,
            );

        let event_request = utils::CalSuccessRateEventRequest {
            id: profile_id.get_string_repr().to_string(),
            params: success_based_routing_config_params.clone(),
            labels: routable_connectors
                .iter()
                .map(|conn_choice| conn_choice.to_string())
                .collect::<Vec<_>>(),
            config: success_based_routing_configs
                .config
                .as_ref()
                .map(utils::CalSuccessRateConfigEventRequest::from),
        };

        let routing_events_wrapper = utils::RoutingEventsWrapper::new(
            state.tenant.tenant_id.clone(),
            state.request_id,
            payment_id.get_string_repr().to_string(),
            profile_id.to_owned(),
            merchant_id.to_owned(),
            "IntelligentRouter: CalculateSuccessRate".to_string(),
            Some(event_request.clone()),
            true,
            false,
        );

        let closure = || async {
            let success_based_connectors_result = client
                .calculate_success_rate(
                    profile_id.get_string_repr().into(),
                    success_based_routing_configs,
                    success_based_routing_config_params,
                    routable_connectors,
                    state.get_grpc_headers(),
                )
                .await
                .change_context(errors::RoutingError::SuccessRateCalculationError)
                .attach_printable(
                    "unable to calculate/fetch success rate from dynamic routing service",
                );

            match success_based_connectors_result {
                Ok(success_response) => {
                    let updated_resp = utils::CalSuccessRateEventResponse::try_from(
                        &success_response,
                    )
                    .change_context(errors::RoutingError::RoutingEventsError { message: "unable to convert SuccessBasedConnectors to CalSuccessRateEventResponse".to_string(), status_code: 500 })
                    .attach_printable(
                        "unable to convert SuccessBasedConnectors to CalSuccessRateEventResponse",
                    )?;

                    Ok(Some(updated_resp))
                }
                Err(e) => {
                    logger::error!(
                        "unable to calculate/fetch success rate from dynamic routing service: {:?}",
                        e.current_context()
                    );

                    Err(error_stack::report!(
                        errors::RoutingError::SuccessRateCalculationError
                    ))
                }
            }
        };

        let events_response = routing_events_wrapper
            .construct_event_builder(
                "SuccessRateCalculator.FetchSuccessRate".to_string(),
                RoutingEngine::IntelligentRouter,
                ApiMethod::Grpc,
            )?
            .trigger_event(state, closure)
            .await?;

        let success_based_connectors: utils::CalSuccessRateEventResponse = events_response
            .response
            .ok_or(errors::RoutingError::SuccessRateCalculationError)?;

        // Need to log error case
        let mut routing_event =
            events_response
                .event
                .ok_or(errors::RoutingError::RoutingEventsError {
                    message:
                        "SR-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                            .to_string(),
                    status_code: 500,
                })?;

        routing_event.set_routing_approach(success_based_connectors.routing_approach.to_string());
        payment_data.set_routing_approach_in_attempt(Some(common_enums::RoutingApproach::from(
            success_based_connectors.routing_approach,
        )));

        let mut connectors = Vec::with_capacity(success_based_connectors.labels_with_score.len());
        for label_with_score in success_based_connectors.labels_with_score {
            let (connector, merchant_connector_id) = label_with_score.label
                .split_once(':')
                .ok_or(errors::RoutingError::InvalidSuccessBasedConnectorLabel(label_with_score.label.to_string()))
                .attach_printable(
                    "unable to split connector_name and mca_id from the label obtained by the dynamic routing service",
                )?;
            connectors.push(api_routing::RoutableConnectorChoice {
                choice_kind: api_routing::RoutableChoiceKind::FullStruct,
                connector: common_enums::RoutableConnectors::from_str(connector)
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "RoutableConnectors".to_string(),
                    })
                    .attach_printable("unable to convert String to RoutableConnectors")?,
                merchant_connector_id: Some(
                    common_utils::id_type::MerchantConnectorAccountId::wrap(
                        merchant_connector_id.to_string(),
                    )
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "MerchantConnectorAccountId".to_string(),
                    })
                    .attach_printable("unable to convert MerchantConnectorAccountId from string")?,
                ),
            });
        }
        logger::debug!(success_based_routing_connectors=?connectors);

        routing_event.set_status_code(200);
        routing_event.set_routable_connectors(connectors.clone());
        state.event_handler().log_event(&routing_event);
        Ok(connectors)
    } else {
        Ok(routable_connectors)
    }
}

/// elimination dynamic routing
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn perform_elimination_routing(
    state: &SessionState,
    routable_connectors: Vec<api_routing::RoutableConnectorChoice>,
    profile_id: &common_utils::id_type::ProfileId,
    merchant_id: &common_utils::id_type::MerchantId,
    payment_id: &common_utils::id_type::PaymentId,
    elimination_routing_configs_params_interpolator: routing::helpers::DynamicRoutingConfigParamsInterpolator,
    elimination_algo_ref: api_routing::EliminationRoutingAlgorithm,
) -> RoutingResult<Vec<api_routing::RoutableConnectorChoice>> {
    if elimination_algo_ref.enabled_feature
        == api_routing::DynamicRoutingFeatures::DynamicConnectorSelection
    {
        logger::debug!(
            "performing elimination_routing for profile {}",
            profile_id.get_string_repr()
        );
        let client = &state
            .grpc_client
            .dynamic_routing
            .as_ref()
            .ok_or(errors::RoutingError::EliminationClientInitializationError)
            .attach_printable("dynamic routing gRPC client not found")?
            .elimination_based_client;

        let elimination_routing_config = routing::helpers::fetch_dynamic_routing_configs::<
            api_routing::EliminationRoutingConfig,
        >(
            state,
            profile_id,
            elimination_algo_ref
                .algorithm_id_with_timestamp
                .algorithm_id
                .ok_or(errors::RoutingError::GenericNotFoundError {
                    field: "elimination_routing_algorithm_id".to_string(),
                })
                .attach_printable(
                    "elimination_routing_algorithm_id not found in business_profile",
                )?,
        )
        .await
        .change_context(errors::RoutingError::EliminationRoutingConfigError)
        .attach_printable("unable to fetch elimination dynamic routing configs")?;

        let elimination_routing_config_params = elimination_routing_configs_params_interpolator
            .get_string_val(
                elimination_routing_config
                    .params
                    .as_ref()
                    .ok_or(errors::RoutingError::EliminationBasedRoutingParamsNotFoundError)?,
            );

        let event_request = utils::EliminationRoutingEventRequest {
            id: profile_id.get_string_repr().to_string(),
            params: elimination_routing_config_params.clone(),
            labels: routable_connectors
                .iter()
                .map(|conn_choice| conn_choice.to_string())
                .collect::<Vec<_>>(),
            config: elimination_routing_config
                .elimination_analyser_config
                .as_ref()
                .map(utils::EliminationRoutingEventBucketConfig::from),
        };

        let routing_events_wrapper = utils::RoutingEventsWrapper::new(
            state.tenant.tenant_id.clone(),
            state.request_id,
            payment_id.get_string_repr().to_string(),
            profile_id.to_owned(),
            merchant_id.to_owned(),
            "IntelligentRouter: PerformEliminationRouting".to_string(),
            Some(event_request.clone()),
            true,
            false,
        );

        let closure = || async {
            let elimination_based_connectors_result = client
                .perform_elimination_routing(
                    profile_id.get_string_repr().to_string(),
                    elimination_routing_config_params,
                    routable_connectors.clone(),
                    elimination_routing_config.elimination_analyser_config,
                    state.get_grpc_headers(),
                )
                .await
                .change_context(errors::RoutingError::EliminationRoutingCalculationError)
                .attach_printable(
                    "unable to analyze/fetch elimination routing from dynamic routing service",
                );

            match elimination_based_connectors_result {
                Ok(elimination_response) => Ok(Some(utils::EliminationEventResponse::from(
                    &elimination_response,
                ))),
                Err(e) => {
                    logger::error!(
                        "unable to analyze/fetch elimination routing from dynamic routing service: {:?}",
                        e.current_context()
                    );

                    Err(error_stack::report!(
                        errors::RoutingError::EliminationRoutingCalculationError
                    ))
                }
            }
        };

        let events_response = routing_events_wrapper
            .construct_event_builder(
                "EliminationAnalyser.GetEliminationStatus".to_string(),
                RoutingEngine::IntelligentRouter,
                ApiMethod::Grpc,
            )?
            .trigger_event(state, closure)
            .await?;

        let elimination_based_connectors: utils::EliminationEventResponse = events_response
            .response
            .ok_or(errors::RoutingError::EliminationRoutingCalculationError)?;

        let mut routing_event = events_response
            .event
            .ok_or(errors::RoutingError::RoutingEventsError {
            message:
                "Elimination-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                    .to_string(),
            status_code: 500,
        })?;

        routing_event.set_routing_approach(utils::RoutingApproach::Elimination.to_string());

        let mut connectors =
            Vec::with_capacity(elimination_based_connectors.labels_with_status.len());
        let mut eliminated_connectors =
            Vec::with_capacity(elimination_based_connectors.labels_with_status.len());
        let mut non_eliminated_connectors =
            Vec::with_capacity(elimination_based_connectors.labels_with_status.len());
        for labels_with_status in elimination_based_connectors.labels_with_status {
            let (connector, merchant_connector_id) = labels_with_status.label
                .split_once(':')
                .ok_or(errors::RoutingError::InvalidEliminationBasedConnectorLabel(labels_with_status.label.to_string()))
                .attach_printable(
                    "unable to split connector_name and mca_id from the label obtained by the elimination based dynamic routing service",
                )?;

            let routable_connector = api_routing::RoutableConnectorChoice {
                choice_kind: api_routing::RoutableChoiceKind::FullStruct,
                connector: common_enums::RoutableConnectors::from_str(connector)
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "RoutableConnectors".to_string(),
                    })
                    .attach_printable("unable to convert String to RoutableConnectors")?,
                merchant_connector_id: Some(
                    common_utils::id_type::MerchantConnectorAccountId::wrap(
                        merchant_connector_id.to_string(),
                    )
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "MerchantConnectorAccountId".to_string(),
                    })
                    .attach_printable("unable to convert MerchantConnectorAccountId from string")?,
                ),
            };

            if labels_with_status
                .elimination_information
                .is_some_and(|elimination_info| {
                    elimination_info
                        .entity
                        .is_some_and(|entity_info| entity_info.is_eliminated)
                })
            {
                eliminated_connectors.push(routable_connector);
            } else {
                non_eliminated_connectors.push(routable_connector);
            }
            connectors.extend(non_eliminated_connectors.clone());
            connectors.extend(eliminated_connectors.clone());
        }
        logger::debug!(dynamic_eliminated_connectors=?eliminated_connectors);
        logger::debug!(dynamic_elimination_based_routing_connectors=?connectors);

        routing_event.set_status_code(200);
        routing_event.set_routable_connectors(connectors.clone());
        state.event_handler().log_event(&routing_event);
        Ok(connectors)
    } else {
        Ok(routable_connectors)
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
#[allow(clippy::too_many_arguments)]
pub async fn perform_contract_based_routing<F, D>(
    state: &SessionState,
    routable_connectors: Vec<api_routing::RoutableConnectorChoice>,
    profile_id: &common_utils::id_type::ProfileId,
    merchant_id: &common_utils::id_type::MerchantId,
    payment_id: &common_utils::id_type::PaymentId,
    _dynamic_routing_config_params_interpolator: routing::helpers::DynamicRoutingConfigParamsInterpolator,
    contract_based_algo_ref: api_routing::ContractRoutingAlgorithm,
    payment_data: &mut D,
) -> RoutingResult<Vec<api_routing::RoutableConnectorChoice>>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    if contract_based_algo_ref.enabled_feature
        == api_routing::DynamicRoutingFeatures::DynamicConnectorSelection
    {
        logger::debug!(
            "performing contract_based_routing for profile {}",
            profile_id.get_string_repr()
        );
        let client = &state
            .grpc_client
            .dynamic_routing
            .as_ref()
            .ok_or(errors::RoutingError::ContractRoutingClientInitializationError)
            .attach_printable("dynamic routing gRPC client not found")?
            .contract_based_client;

        let contract_based_routing_configs = routing::helpers::fetch_dynamic_routing_configs::<
            api_routing::ContractBasedRoutingConfig,
        >(
            state,
            profile_id,
            contract_based_algo_ref
                .algorithm_id_with_timestamp
                .algorithm_id
                .ok_or(errors::RoutingError::GenericNotFoundError {
                    field: "contract_based_routing_algorithm_id".to_string(),
                })
                .attach_printable("contract_based_routing_algorithm_id not found in profile_id")?,
        )
        .await
        .change_context(errors::RoutingError::ContractBasedRoutingConfigError)
        .attach_printable("unable to fetch contract based dynamic routing configs")?;

        let label_info = contract_based_routing_configs
            .label_info
            .clone()
            .ok_or(errors::RoutingError::ContractBasedRoutingConfigError)
            .attach_printable("Label information not found in contract routing configs")?;

        let contract_based_connectors = routable_connectors
            .clone()
            .into_iter()
            .filter(|conn| {
                label_info
                    .iter()
                    .any(|info| Some(info.mca_id.clone()) == conn.merchant_connector_id.clone())
            })
            .collect::<Vec<_>>();

        let mut other_connectors = routable_connectors
            .into_iter()
            .filter(|conn| {
                label_info
                    .iter()
                    .all(|info| Some(info.mca_id.clone()) != conn.merchant_connector_id.clone())
            })
            .collect::<Vec<_>>();

        let event_request = utils::CalContractScoreEventRequest {
            id: profile_id.get_string_repr().to_string(),
            params: "".to_string(),
            labels: contract_based_connectors
                .iter()
                .map(|conn_choice| conn_choice.to_string())
                .collect::<Vec<_>>(),
            config: Some(contract_based_routing_configs.clone()),
        };

        let routing_events_wrapper = utils::RoutingEventsWrapper::new(
            state.tenant.tenant_id.clone(),
            state.request_id,
            payment_id.get_string_repr().to_string(),
            profile_id.to_owned(),
            merchant_id.to_owned(),
            "IntelligentRouter: PerformContractRouting".to_string(),
            Some(event_request.clone()),
            true,
            false,
        );

        let closure = || async {
            let contract_based_connectors_result = client
                .calculate_contract_score(
                    profile_id.get_string_repr().into(),
                    contract_based_routing_configs.clone(),
                    "".to_string(),
                    contract_based_connectors,
                    state.get_grpc_headers(),
                )
                .await
                .attach_printable(
                    "unable to calculate/fetch contract score from dynamic routing service",
                );

            let contract_based_connectors = match contract_based_connectors_result {
                Ok(resp) => Some(utils::CalContractScoreEventResponse::from(&resp)),
                Err(err) => match err.current_context() {
                    DynamicRoutingError::ContractNotFound => {
                        client
                            .update_contracts(
                                profile_id.get_string_repr().into(),
                                label_info,
                                "".to_string(),
                                vec![],
                                u64::default(),
                                state.get_grpc_headers(),
                            )
                            .await
                            .change_context(errors::RoutingError::ContractScoreUpdationError)
                            .attach_printable(
                                "unable to update contract based routing window in dynamic routing service",
                            )?;
                        return Err((errors::RoutingError::ContractScoreCalculationError {
                            err: err.to_string(),
                        })
                        .into());
                    }
                    _ => {
                        return Err((errors::RoutingError::ContractScoreCalculationError {
                            err: err.to_string(),
                        })
                        .into())
                    }
                },
            };

            Ok(contract_based_connectors)
        };

        let events_response = routing_events_wrapper
            .construct_event_builder(
                "ContractScoreCalculator.FetchContractScore".to_string(),
                RoutingEngine::IntelligentRouter,
                ApiMethod::Grpc,
            )?
            .trigger_event(state, closure)
            .await?;

        let contract_based_connectors: utils::CalContractScoreEventResponse = events_response
            .response
            .ok_or(errors::RoutingError::ContractScoreCalculationError {
                err: "CalContractScoreEventResponse not found".to_string(),
            })?;

        let mut routing_event = events_response
            .event
            .ok_or(errors::RoutingError::RoutingEventsError {
            message:
                "ContractRouting-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                    .to_string(),
            status_code: 500,
        })?;

        payment_data.set_routing_approach_in_attempt(Some(
            common_enums::RoutingApproach::ContractBasedRouting,
        ));

        let mut connectors = Vec::with_capacity(contract_based_connectors.labels_with_score.len());

        for label_with_score in contract_based_connectors.labels_with_score {
            let (connector, merchant_connector_id) = label_with_score.label
                .split_once(':')
                .ok_or(errors::RoutingError::InvalidContractBasedConnectorLabel(label_with_score.label.to_string()))
                .attach_printable(
                    "unable to split connector_name and mca_id from the label obtained by the dynamic routing service",
                )?;

            connectors.push(api_routing::RoutableConnectorChoice {
                choice_kind: api_routing::RoutableChoiceKind::FullStruct,
                connector: common_enums::RoutableConnectors::from_str(connector)
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "RoutableConnectors".to_string(),
                    })
                    .attach_printable("unable to convert String to RoutableConnectors")?,
                merchant_connector_id: Some(
                    common_utils::id_type::MerchantConnectorAccountId::wrap(
                        merchant_connector_id.to_string(),
                    )
                    .change_context(errors::RoutingError::GenericConversionError {
                        from: "String".to_string(),
                        to: "MerchantConnectorAccountId".to_string(),
                    })
                    .attach_printable("unable to convert MerchantConnectorAccountId from string")?,
                ),
            });
        }

        connectors.append(&mut other_connectors);

        logger::debug!(contract_based_routing_connectors=?connectors);

        routing_event.set_status_code(200);
        routing_event.set_routable_connectors(connectors.clone());
        routing_event.set_routing_approach(api_routing::RoutingApproach::ContractBased.to_string());
        state.event_handler().log_event(&routing_event);
        Ok(connectors)
    } else {
        Ok(routable_connectors)
    }
}


// Struct: AdyenPlatformConnectorMetadataObject
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AdyenPlatformConnectorMetadataObject


// Struct: NovalnetPaymentsRequestCustomer
// File: crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NovalnetPaymentsRequestCustomer


// Function: new
// File: crates/hyperswitch_connectors/src/connectors/mpgs.rs
// Module: hyperswitch_connectors

pub fn new() -> &'static Self


// Implementation: impl GetAuthType for for ApiKeyAuth
// File: crates/router/src/services/authentication.rs
// Module: router
// Methods: 1 total (0 public)

impl GetAuthType for for ApiKeyAuth


// Function: start_drainer
// File: crates/drainer/src/lib.rs
// Module: drainer

pub fn start_drainer(
    stores: HashMap<id_type::TenantId, Arc<Store>>,
    conf: DrainerSettings,
) -> errors::DrainerResult<()>


// Struct: ArchipelBillingAddress
// File: crates/hyperswitch_connectors/src/connectors/archipel/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ArchipelBillingAddress


// Implementation: impl api::PaymentCapture for for Juspaythreedsserver
// File: crates/hyperswitch_connectors/src/connectors/juspaythreedsserver.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Juspaythreedsserver


// File: crates/router/build.rs
// Module: router

fn main() {
    // Set thread stack size to 10 MiB for debug builds
    // Reference: https://doc.rust-lang.org/std/thread/#stack-size
    #[cfg(debug_assertions)]
    println!("cargo:rustc-env=RUST_MIN_STACK=10485760"); // 10 * 1024 * 1024 = 10 MiB

    #[cfg(feature = "vergen")]
    router_env::vergen::generate_cargo_instructions();
}


// Struct: FlattenedPaymentMethodsEnabled
// File: crates/hyperswitch_domain_models/src/merchant_connector_account.rs
// Module: hyperswitch_domain_models
// Implementations: 1

// Documentation: Holds the payment methods enabled for a connector

pub struct FlattenedPaymentMethodsEnabled


// File: crates/diesel_models/src/api_keys.rs
// Module: diesel_models
// Public functions: 1
// Public structs: 4

use diesel::{AsChangeset, AsExpression, Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;

use crate::schema::api_keys;

#[derive(
    serde::Serialize, serde::Deserialize, Debug, Clone, Identifiable, Queryable, Selectable,
)]
#[diesel(table_name = api_keys, primary_key(key_id), check_for_backend(diesel::pg::Pg))]
pub struct ApiKey {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: String,
    pub description: Option<String>,
    pub hashed_api_key: HashedApiKey,
    pub prefix: String,
    pub created_at: PrimitiveDateTime,
    pub expires_at: Option<PrimitiveDateTime>,
    pub last_used: Option<PrimitiveDateTime>,
}

#[derive(Debug, Insertable)]
#[diesel(table_name = api_keys)]
pub struct ApiKeyNew {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: String,
    pub description: Option<String>,
    pub hashed_api_key: HashedApiKey,
    pub prefix: String,
    pub created_at: PrimitiveDateTime,
    pub expires_at: Option<PrimitiveDateTime>,
    pub last_used: Option<PrimitiveDateTime>,
}

#[derive(Debug)]
pub enum ApiKeyUpdate {
    Update {
        name: Option<String>,
        description: Option<String>,
        expires_at: Option<Option<PrimitiveDateTime>>,
        last_used: Option<PrimitiveDateTime>,
    },
    LastUsedUpdate {
        last_used: PrimitiveDateTime,
    },
}

#[derive(Debug, AsChangeset)]
#[diesel(table_name = api_keys)]
pub(crate) struct ApiKeyUpdateInternal {
    pub name: Option<String>,
    pub description: Option<String>,
    pub expires_at: Option<Option<PrimitiveDateTime>>,
    pub last_used: Option<PrimitiveDateTime>,
}

impl From<ApiKeyUpdate> for ApiKeyUpdateInternal {
    fn from(api_key_update: ApiKeyUpdate) -> Self {
        match api_key_update {
            ApiKeyUpdate::Update {
                name,
                description,
                expires_at,
                last_used,
            } => Self {
                name,
                description,
                expires_at,
                last_used,
            },
            ApiKeyUpdate::LastUsedUpdate { last_used } => Self {
                last_used: Some(last_used),
                name: None,
                description: None,
                expires_at: None,
            },
        }
    }
}

#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, AsExpression, PartialEq)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct HashedApiKey(String);

impl HashedApiKey {
    pub fn into_inner(self) -> String {
        self.0
    }
}

impl From<String> for HashedApiKey {
    fn from(hashed_api_key: String) -> Self {
        Self(hashed_api_key)
    }
}

mod diesel_impl {
    use diesel::{
        backend::Backend,
        deserialize::FromSql,
        serialize::{Output, ToSql},
        sql_types::Text,
        Queryable,
    };

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

    impl<DB> FromSql<Text, DB> for super::HashedApiKey
    where
        DB: Backend,
        String: FromSql<Text, DB>,
    {
        fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            Ok(Self(String::from_sql(bytes)?))
        }
    }

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

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

// Tracking data by process_tracker
#[derive(Default, Debug, Deserialize, Serialize, Clone)]
pub struct ApiKeyExpiryTrackingData {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub api_key_name: String,
    pub prefix: String,
    pub api_key_expiry: Option<PrimitiveDateTime>,
    // Days on which email reminder about api_key expiry has to be sent, prior to it's expiry.
    pub expiry_reminder_days: Vec<u8>,
}


// Function: get_shipping_cost
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn get_shipping_cost(&self) -> Option<MinorUnit>


// Struct: ConnectorInfo
// File: crates/hyperswitch_domain_models/src/router_response_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct ConnectorInfo


// File: crates/router/src/types/api/admin.rs
// Module: router
// Public functions: 1
// Public structs: 1

use std::collections::HashMap;

#[cfg(feature = "v2")]
pub use api_models::admin;
pub use api_models::{
    admin::{
        MaskedHeaders, MerchantAccountCreate, MerchantAccountDeleteResponse,
        MerchantAccountResponse, MerchantAccountUpdate, MerchantConnectorCreate,
        MerchantConnectorDeleteResponse, MerchantConnectorDetails, MerchantConnectorDetailsWrap,
        MerchantConnectorId, MerchantConnectorResponse, MerchantDetails, MerchantId,
        PaymentMethodsEnabled, ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest,
        ToggleAllKVResponse, ToggleKVRequest, ToggleKVResponse, WebhookDetails,
    },
    organization::{
        OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
    },
};
use common_utils::{ext_traits::ValueExt, types::keymanager as km_types};
use diesel_models::{business_profile::CardTestingGuardConfig, organization::OrganizationBridge};
use error_stack::ResultExt;
use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore;
use masking::{ExposeInterface, PeekInterface, Secret};

use crate::{
    consts,
    core::errors,
    routes::SessionState,
    types::{
        domain::{
            self,
            types::{self as domain_types, AsyncLift},
        },
        transformers::{ForeignInto, ForeignTryFrom},
        ForeignFrom,
    },
    utils,
};

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ProfileAcquirerConfigs {
    pub acquirer_config_map: Option<common_types::domain::AcquirerConfigMap>,
    pub profile_id: common_utils::id_type::ProfileId,
}

impl From<ProfileAcquirerConfigs>
    for Option<Vec<api_models::profile_acquirer::ProfileAcquirerResponse>>
{
    fn from(item: ProfileAcquirerConfigs) -> Self {
        item.acquirer_config_map.map(|config_map_val| {
            let mut vec: Vec<_> = config_map_val.0.into_iter().collect();
            vec.sort_by_key(|k| k.0.clone());
            vec.into_iter()
                .map(|(profile_acquirer_id, acquirer_config)| {
                    api_models::profile_acquirer::ProfileAcquirerResponse::from((
                        profile_acquirer_id,
                        &item.profile_id,
                        &acquirer_config,
                    ))
                })
                .collect::<Vec<api_models::profile_acquirer::ProfileAcquirerResponse>>()
        })
    }
}

impl ForeignFrom<diesel_models::organization::Organization> for OrganizationResponse {
    fn foreign_from(org: diesel_models::organization::Organization) -> Self {
        Self {
            #[cfg(feature = "v2")]
            id: org.get_organization_id(),

            #[cfg(feature = "v1")]
            organization_id: org.get_organization_id(),
            organization_name: org.get_organization_name(),
            organization_details: org.organization_details,
            metadata: org.metadata,
            modified_at: org.modified_at,
            created_at: org.created_at,
            organization_type: org.organization_type,
        }
    }
}

#[cfg(feature = "v1")]
impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
    type Error = error_stack::Report<errors::ParsingError>;
    fn foreign_try_from(item: domain::MerchantAccount) -> Result<Self, Self::Error> {
        let merchant_id = item.get_id().to_owned();
        let primary_business_details: Vec<api_models::admin::PrimaryBusinessDetails> = item
            .primary_business_details
            .parse_value("primary_business_details")?;

        let pm_collect_link_config: Option<api_models::admin::BusinessCollectLinkConfig> = item
            .pm_collect_link_config
            .map(|config| config.parse_value("pm_collect_link_config"))
            .transpose()?;

        Ok(Self {
            merchant_id,
            merchant_name: item.merchant_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            merchant_details: item.merchant_details,
            webhook_details: item.webhook_details.clone().map(ForeignInto::foreign_into),
            routing_algorithm: item.routing_algorithm,
            sub_merchants_enabled: item.sub_merchants_enabled,
            parent_merchant_id: item.parent_merchant_id,
            publishable_key: Some(item.publishable_key),
            metadata: item.metadata,
            locker_id: item.locker_id,
            primary_business_details,
            frm_routing_algorithm: item.frm_routing_algorithm,
            #[cfg(feature = "payouts")]
            payout_routing_algorithm: item.payout_routing_algorithm,
            organization_id: item.organization_id,
            is_recon_enabled: item.is_recon_enabled,
            default_profile: item.default_profile,
            recon_status: item.recon_status,
            pm_collect_link_config,
            product_type: item.product_type,
            merchant_account_type: item.merchant_account_type,
        })
    }
}

#[cfg(feature = "v2")]
impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
    type Error = error_stack::Report<errors::ValidationError>;
    fn foreign_try_from(item: domain::MerchantAccount) -> Result<Self, Self::Error> {
        use common_utils::ext_traits::OptionExt;

        let id = item.get_id().to_owned();

        let merchant_name = item
            .merchant_name
            .get_required_value("merchant_name")?
            .into_inner();

        Ok(Self {
            id,
            merchant_name,
            merchant_details: item.merchant_details,
            publishable_key: item.publishable_key,
            metadata: item.metadata,
            organization_id: item.organization_id,
            recon_status: item.recon_status,
            product_type: item.product_type,
        })
    }
}
#[cfg(feature = "v1")]
impl ForeignTryFrom<domain::Profile> for ProfileResponse {
    type Error = error_stack::Report<errors::ParsingError>;

    fn foreign_try_from(item: domain::Profile) -> Result<Self, Self::Error> {
        let profile_id = item.get_id().to_owned();
        let outgoing_webhook_custom_http_headers = item
            .outgoing_webhook_custom_http_headers
            .map(|headers| {
                headers
                    .into_inner()
                    .expose()
                    .parse_value::<HashMap<String, Secret<String>>>(
                        "HashMap<String, Secret<String>>",
                    )
            })
            .transpose()?;
        let masked_outgoing_webhook_custom_http_headers =
            outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);

        let card_testing_guard_config = item
            .card_testing_guard_config
            .or(Some(CardTestingGuardConfig::default()));
        let (is_external_vault_enabled, external_vault_connector_details) =
            item.external_vault_details.into();

        Ok(Self {
            merchant_id: item.merchant_id,
            profile_id: profile_id.clone(),
            profile_name: item.profile_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            webhook_details: item.webhook_details.map(ForeignInto::foreign_into),
            metadata: item.metadata,
            routing_algorithm: item.routing_algorithm,
            intent_fulfillment_time: item.intent_fulfillment_time,
            frm_routing_algorithm: item.frm_routing_algorithm,
            #[cfg(feature = "payouts")]
            payout_routing_algorithm: item.payout_routing_algorithm,
            applepay_verified_domains: item.applepay_verified_domains,
            payment_link_config: item.payment_link_config.map(ForeignInto::foreign_into),
            session_expiry: item.session_expiry,
            authentication_connector_details: item
                .authentication_connector_details
                .map(ForeignInto::foreign_into),
            payout_link_config: item.payout_link_config.map(ForeignInto::foreign_into),
            use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
            extended_card_info_config: item
                .extended_card_info_config
                .map(|config| config.expose().parse_value("ExtendedCardInfoConfig"))
                .transpose()?,
            collect_shipping_details_from_wallet_connector: item
                .collect_shipping_details_from_wallet_connector,
            collect_billing_details_from_wallet_connector: item
                .collect_billing_details_from_wallet_connector,
            always_collect_billing_details_from_wallet_connector: item
                .always_collect_billing_details_from_wallet_connector,
            always_collect_shipping_details_from_wallet_connector: item
                .always_collect_shipping_details_from_wallet_connector,
            is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
            outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
            tax_connector_id: item.tax_connector_id,
            is_tax_connector_enabled: item.is_tax_connector_enabled,
            is_network_tokenization_enabled: item.is_network_tokenization_enabled,
            is_auto_retries_enabled: item.is_auto_retries_enabled,
            max_auto_retries_enabled: item.max_auto_retries_enabled,
            always_request_extended_authorization: item.always_request_extended_authorization,
            is_click_to_pay_enabled: item.is_click_to_pay_enabled,
            authentication_product_ids: item.authentication_product_ids,
            card_testing_guard_config: card_testing_guard_config.map(ForeignInto::foreign_into),
            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
            force_3ds_challenge: item.force_3ds_challenge,
            is_debit_routing_enabled: Some(item.is_debit_routing_enabled),
            merchant_business_country: item.merchant_business_country,
            is_pre_network_tokenization_enabled: item.is_pre_network_tokenization_enabled,
            acquirer_configs: ProfileAcquirerConfigs {
                acquirer_config_map: item.acquirer_config_map.clone(),
                profile_id: profile_id.clone(),
            }
            .into(),
            is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
            merchant_category_code: item.merchant_category_code,
            merchant_country_code: item.merchant_country_code,
            dispute_polling_interval: item.dispute_polling_interval,
            is_manual_retry_enabled: item.is_manual_retry_enabled,
            always_enable_overcapture: item.always_enable_overcapture,
            is_external_vault_enabled,
            external_vault_connector_details: external_vault_connector_details
                .map(ForeignFrom::foreign_from),
            billing_processor_id: item.billing_processor_id,
        })
    }
}

#[cfg(feature = "v2")]
impl ForeignTryFrom<domain::Profile> for ProfileResponse {
    type Error = error_stack::Report<errors::ParsingError>;

    fn foreign_try_from(item: domain::Profile) -> Result<Self, Self::Error> {
        let id = item.get_id().to_owned();

        let outgoing_webhook_custom_http_headers = item
            .outgoing_webhook_custom_http_headers
            .map(|headers| {
                headers
                    .into_inner()
                    .expose()
                    .parse_value::<HashMap<String, Secret<String>>>(
                        "HashMap<String, Secret<String>>",
                    )
            })
            .transpose()?;

        let order_fulfillment_time = item
            .order_fulfillment_time
            .map(admin::OrderFulfillmentTime::try_new)
            .transpose()
            .change_context(errors::ParsingError::IntegerOverflow)?;
        let masked_outgoing_webhook_custom_http_headers =
            outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);

        let card_testing_guard_config = item
            .card_testing_guard_config
            .or(Some(CardTestingGuardConfig::default()));

        Ok(Self {
            merchant_id: item.merchant_id,
            id,
            profile_name: item.profile_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            webhook_details: item.webhook_details.map(ForeignInto::foreign_into),
            metadata: item.metadata,
            applepay_verified_domains: item.applepay_verified_domains,
            payment_link_config: item.payment_link_config.map(ForeignInto::foreign_into),
            session_expiry: item.session_expiry,
            authentication_connector_details: item
                .authentication_connector_details
                .map(ForeignInto::foreign_into),
            payout_link_config: item.payout_link_config.map(ForeignInto::foreign_into),
            use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
            extended_card_info_config: item
                .extended_card_info_config
                .map(|config| config.expose().parse_value("ExtendedCardInfoConfig"))
                .transpose()?,
            collect_shipping_details_from_wallet_connector_if_required: item
                .collect_shipping_details_from_wallet_connector,
            collect_billing_details_from_wallet_connector_if_required: item
                .collect_billing_details_from_wallet_connector,
            always_collect_shipping_details_from_wallet_connector: item
                .always_collect_shipping_details_from_wallet_connector,
            always_collect_billing_details_from_wallet_connector: item
                .always_collect_billing_details_from_wallet_connector,
            is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
            outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
            order_fulfillment_time,
            order_fulfillment_time_origin: item.order_fulfillment_time_origin,
            should_collect_cvv_during_payment: item.should_collect_cvv_during_payment,
            tax_connector_id: item.tax_connector_id,
            is_tax_connector_enabled: item.is_tax_connector_enabled,
            is_network_tokenization_enabled: item.is_network_tokenization_enabled,
            is_click_to_pay_enabled: item.is_click_to_pay_enabled,
            authentication_product_ids: item.authentication_product_ids,
            card_testing_guard_config: card_testing_guard_config.map(ForeignInto::foreign_into),
            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
            is_debit_routing_enabled: Some(item.is_debit_routing_enabled),
            merchant_business_country: item.merchant_business_country,
            is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
            is_external_vault_enabled: item.is_external_vault_enabled,
            external_vault_connector_details: item
                .external_vault_connector_details
                .map(ForeignInto::foreign_into),
            merchant_category_code: item.merchant_category_code,
            merchant_country_code: item.merchant_country_code,
            split_txns_enabled: item.split_txns_enabled,
            revenue_recovery_retry_algorithm_type: item.revenue_recovery_retry_algorithm_type,
            billing_processor_id: item.billing_processor_id,
        })
    }
}

#[cfg(feature = "v1")]
pub async fn create_profile_from_merchant_account(
    state: &SessionState,
    merchant_account: domain::MerchantAccount,
    request: ProfileCreate,
    key_store: &MerchantKeyStore,
) -> Result<domain::Profile, error_stack::Report<errors::ApiErrorResponse>> {
    use common_utils::ext_traits::AsyncExt;
    use diesel_models::business_profile::CardTestingGuardConfig;

    use crate::core;

    // Generate a unique profile id
    let profile_id = common_utils::generate_profile_id_of_default_length();
    let merchant_id = merchant_account.get_id().to_owned();

    let current_time = common_utils::date_time::now();

    let webhook_details = request.webhook_details.map(ForeignInto::foreign_into);

    let payment_response_hash_key = request
        .payment_response_hash_key
        .or(merchant_account.payment_response_hash_key)
        .unwrap_or(common_utils::crypto::generate_cryptographically_secure_random_string(64));

    let payment_link_config = request.payment_link_config.map(ForeignInto::foreign_into);
    let key_manager_state = state.into();
    let outgoing_webhook_custom_http_headers = request
        .outgoing_webhook_custom_http_headers
        .async_map(|headers| {
            core::payment_methods::cards::create_encrypted_data(
                &key_manager_state,
                key_store,
                headers,
            )
        })
        .await
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?;

    let payout_link_config = request
        .payout_link_config
        .map(|payout_conf| match payout_conf.config.validate() {
            Ok(_) => Ok(payout_conf.foreign_into()),
            Err(e) => Err(error_stack::report!(
                errors::ApiErrorResponse::InvalidRequestData {
                    message: e.to_string()
                }
            )),
        })
        .transpose()?;

    let key = key_store.key.clone().into_inner();
    let key_manager_state = state.into();

    let card_testing_secret_key = Some(Secret::new(utils::generate_id(
        consts::FINGERPRINT_SECRET_LENGTH,
        "fs",
    )));

    let card_testing_guard_config = request
        .card_testing_guard_config
        .map(CardTestingGuardConfig::foreign_from)
        .or(Some(CardTestingGuardConfig::default()));

    Ok(domain::Profile::from(domain::ProfileSetter {
        profile_id,
        merchant_id,
        profile_name: request.profile_name.unwrap_or("default".to_string()),
        created_at: current_time,
        modified_at: current_time,
        return_url: request
            .return_url
            .map(|return_url| return_url.to_string())
            .or(merchant_account.return_url),
        enable_payment_response_hash: request
            .enable_payment_response_hash
            .unwrap_or(merchant_account.enable_payment_response_hash),
        payment_response_hash_key: Some(payment_response_hash_key),
        redirect_to_merchant_with_http_post: request
            .redirect_to_merchant_with_http_post
            .unwrap_or(merchant_account.redirect_to_merchant_with_http_post),
        webhook_details: webhook_details.or(merchant_account.webhook_details),
        metadata: request.metadata,
        routing_algorithm: None,
        intent_fulfillment_time: request
            .intent_fulfillment_time
            .map(i64::from)
            .or(merchant_account.intent_fulfillment_time)
            .or(Some(common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME)),
        frm_routing_algorithm: request
            .frm_routing_algorithm
            .or(merchant_account.frm_routing_algorithm),
        #[cfg(feature = "payouts")]
        payout_routing_algorithm: request
            .payout_routing_algorithm
            .or(merchant_account.payout_routing_algorithm),
        #[cfg(not(feature = "payouts"))]
        payout_routing_algorithm: None,
        is_recon_enabled: merchant_account.is_recon_enabled,
        applepay_verified_domains: request.applepay_verified_domains,
        payment_link_config,
        session_expiry: request
            .session_expiry
            .map(i64::from)
            .or(Some(common_utils::consts::DEFAULT_SESSION_EXPIRY)),
        authentication_connector_details: request
            .authentication_connector_details
            .map(ForeignInto::foreign_into),
        payout_link_config,
        is_connector_agnostic_mit_enabled: request.is_connector_agnostic_mit_enabled,
        is_extended_card_info_enabled: None,
        extended_card_info_config: None,
        use_billing_as_payment_method_billing: request
            .use_billing_as_payment_method_billing
            .or(Some(true)),
        collect_shipping_details_from_wallet_connector: request
            .collect_shipping_details_from_wallet_connector
            .or(Some(false)),
        collect_billing_details_from_wallet_connector: request
            .collect_billing_details_from_wallet_connector
            .or(Some(false)),
        always_collect_billing_details_from_wallet_connector: request
            .always_collect_billing_details_from_wallet_connector
            .or(Some(false)),
        always_collect_shipping_details_from_wallet_connector: request
            .always_collect_shipping_details_from_wallet_connector
            .or(Some(false)),
        outgoing_webhook_custom_http_headers,
        tax_connector_id: request.tax_connector_id,
        is_tax_connector_enabled: request.is_tax_connector_enabled,
        dynamic_routing_algorithm: None,
        is_network_tokenization_enabled: request.is_network_tokenization_enabled,
        is_auto_retries_enabled: request.is_auto_retries_enabled.unwrap_or_default(),
        max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from),
        always_request_extended_authorization: request.always_request_extended_authorization,
        is_click_to_pay_enabled: request.is_click_to_pay_enabled,
        authentication_product_ids: request.authentication_product_ids,
        card_testing_guard_config,
        card_testing_secret_key: card_testing_secret_key
            .async_lift(|inner| async {
                domain_types::crypto_operation(
                    &key_manager_state,
                    common_utils::type_name!(domain::Profile),
                    domain_types::CryptoOperation::EncryptOptional(inner),
                    km_types::Identifier::Merchant(key_store.merchant_id.clone()),
                    key.peek(),
                )
                .await
                .and_then(|val| val.try_into_optionaloperation())
            })
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("error while generating card testing secret key")?,
        is_clear_pan_retries_enabled: request.is_clear_pan_retries_enabled.unwrap_or_default(),
        force_3ds_challenge: request.force_3ds_challenge.unwrap_or_default(),
        is_debit_routing_enabled: request.is_debit_routing_enabled.unwrap_or_default(),
        merchant_business_country: request.merchant_business_country,
        is_iframe_redirection_enabled: request.is_iframe_redirection_enabled,
        is_pre_network_tokenization_enabled: request
            .is_pre_network_tokenization_enabled
            .unwrap_or_default(),
        merchant_category_code: request.merchant_category_code,
        merchant_country_code: request.merchant_country_code,
        dispute_polling_interval: request.dispute_polling_interval,
        is_manual_retry_enabled: request.is_manual_retry_enabled,
        always_enable_overcapture: request.always_enable_overcapture,
        external_vault_details: domain::ExternalVaultDetails::try_from((
            request.is_external_vault_enabled,
            request
                .external_vault_connector_details
                .map(ForeignInto::foreign_into),
        ))
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("error while generating external_vault_details")?,
        billing_processor_id: request.billing_processor_id,
    }))
}


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

impl api::PaymentAuthorize for for Bambora


// Implementation: impl api::Payment for for Boku
// File: crates/hyperswitch_connectors/src/connectors/boku.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Boku


// Struct: MpgsCard
// File: crates/hyperswitch_connectors/src/connectors/mpgs/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MpgsCard


// Function: convert_currency
// File: crates/router/src/utils/currency.rs
// Module: router

pub fn convert_currency(
    state: SessionState,
    amount: i64,
    to_currency: String,
    from_currency: String,
) -> CustomResult<api_models::currency::CurrencyConversionResponse, ForexError>


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

pub struct AuthEventFilterValue


// Function: pg_accounts_connection_read
// File: crates/router/src/connection.rs
// Module: router

pub fn pg_accounts_connection_read<T: storage_impl::DatabaseStore>(
    store: &T,
) -> errors::CustomResult<
    PooledConnection<'_, async_bb8_diesel::ConnectionManager<PgConnection>>,
    storage_errors::StorageError,
>


// Function: proxy_core
// File: crates/router/src/core/proxy.rs
// Module: router

pub fn proxy_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: proxy_api_models::ProxyRequest,
) -> RouterResponse<proxy_api_models::ProxyResponse>


// Struct: AddAcceptLanguageHeaderMiddleware
// File: crates/router/src/middleware.rs
// Module: router
// Implementations: 0

pub struct AddAcceptLanguageHeaderMiddleware<S>


// Implementation: impl Celero
// File: crates/hyperswitch_connectors/src/connectors/celero.rs
// Module: hyperswitch_connectors
// Methods: 1 total (1 public)

impl Celero


// Implementation: impl PaymentMethodsStorageInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 0 total (0 public)

impl PaymentMethodsStorageInterface for for KafkaStore


// Implementation: impl api::Payment for for Xendit
// File: crates/hyperswitch_connectors/src/connectors/xendit.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Xendit


// Struct: DigitalvirgoPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/digitalvirgo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DigitalvirgoPaymentsResponse