// File: crates/hyperswitch_connectors/src/connectors/cryptopay/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 8

use common_enums::enums;
use common_utils::{
    pii,
    types::{MinorUnit, StringMajorUnit},
};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RedirectForm},
    types,
};
use hyperswitch_interfaces::{consts, errors};
use masking::Secret;
use reqwest::Url;
use serde::{Deserialize, Serialize};

use crate::{
    types::ResponseRouterData,
    utils::{self, CryptoData, ForeignTryFrom, PaymentsAuthorizeRequestData},
};

#[derive(Debug, Serialize)]
pub struct CryptopayRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}

impl<T> From<(StringMajorUnit, T)> for CryptopayRouterData<T> {
    fn from((amount, item): (StringMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}

#[derive(Default, Debug, Serialize)]
pub struct CryptopayPaymentsRequest {
    price_amount: StringMajorUnit,
    price_currency: enums::Currency,
    pay_currency: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    network: Option<String>,
    success_redirect_url: Option<String>,
    unsuccess_redirect_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    metadata: Option<pii::SecretSerdeValue>,
    custom_id: String,
}

impl TryFrom<&CryptopayRouterData<&types::PaymentsAuthorizeRouterData>>
    for CryptopayPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CryptopayRouterData<&types::PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let cryptopay_request = match item.router_data.request.payment_method_data {
            PaymentMethodData::Crypto(ref cryptodata) => {
                let pay_currency = cryptodata.get_pay_currency()?;
                Ok(Self {
                    price_amount: item.amount.clone(),
                    price_currency: item.router_data.request.currency,
                    pay_currency,
                    network: cryptodata.network.to_owned(),
                    success_redirect_url: item.router_data.request.router_return_url.clone(),
                    unsuccess_redirect_url: item.router_data.request.router_return_url.clone(),
                    //Cryptopay only accepts metadata as Object. If any other type, payment will fail with error.
                    metadata: item.router_data.request.get_metadata_as_object(),
                    custom_id: item.router_data.connector_request_reference_id.clone(),
                })
            }
            PaymentMethodData::Card(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("CryptoPay"),
                ))
            }
        }?;
        Ok(cryptopay_request)
    }
}

// Auth Struct
pub struct CryptopayAuthType {
    pub(super) api_key: Secret<String>,
    pub(super) api_secret: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for CryptopayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        if let ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
            Ok(Self {
                api_key: api_key.to_owned(),
                api_secret: key1.to_owned(),
            })
        } else {
            Err(errors::ConnectorError::FailedToObtainAuthType.into())
        }
    }
}
// PaymentsResponse
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CryptopayPaymentStatus {
    New,
    Completed,
    Unresolved,
    Refunded,
    Cancelled,
}

impl From<CryptopayPaymentStatus> for enums::AttemptStatus {
    fn from(item: CryptopayPaymentStatus) -> Self {
        match item {
            CryptopayPaymentStatus::New => Self::AuthenticationPending,
            CryptopayPaymentStatus::Completed => Self::Charged,
            CryptopayPaymentStatus::Cancelled => Self::Failure,
            CryptopayPaymentStatus::Unresolved | CryptopayPaymentStatus::Refunded => {
                Self::Unresolved
            } //mapped refunded to Unresolved because refund api is not available, also merchant has done the action on the connector dashboard.
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CryptopayPaymentsResponse {
    pub data: CryptopayPaymentResponseData,
}

impl<F, T>
    ForeignTryFrom<(
        ResponseRouterData<F, CryptopayPaymentsResponse, T, PaymentsResponseData>,
        Option<MinorUnit>,
    )> for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(
        (item, amount_captured_in_minor_units): (
            ResponseRouterData<F, CryptopayPaymentsResponse, T, PaymentsResponseData>,
            Option<MinorUnit>,
        ),
    ) -> Result<Self, Self::Error> {
        let status = enums::AttemptStatus::from(item.response.data.status.clone());
        let response = if utils::is_payment_failure(status) {
            let payment_response = &item.response.data;
            Err(ErrorResponse {
                code: payment_response
                    .name
                    .clone()
                    .unwrap_or(consts::NO_ERROR_CODE.to_string()),
                message: payment_response
                    .status_context
                    .clone()
                    .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
                reason: payment_response.status_context.clone(),
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: Some(payment_response.id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            let redirection_data = item
                .response
                .data
                .hosted_page_url
                .map(|x| RedirectForm::from((x, common_utils::request::Method::Get)));
            Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.data.id.clone()),
                redirection_data: Box::new(redirection_data),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: item
                    .response
                    .data
                    .custom_id
                    .or(Some(item.response.data.id)),
                incremental_authorization_allowed: None,
                charges: None,
            })
        };
        match amount_captured_in_minor_units {
            Some(minor_amount) => {
                let amount_captured = Some(minor_amount.get_amount_as_i64());
                Ok(Self {
                    status,
                    response,
                    amount_captured,
                    minor_amount_captured: amount_captured_in_minor_units,
                    ..item.data
                })
            }
            None => Ok(Self {
                status,
                response,
                ..item.data
            }),
        }
    }
}

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct CryptopayErrorData {
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct CryptopayErrorResponse {
    pub error: CryptopayErrorData,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CryptopayPaymentResponseData {
    pub id: String,
    pub custom_id: Option<String>,
    pub customer_id: Option<String>,
    pub status: CryptopayPaymentStatus,
    pub status_context: Option<String>,
    pub address: Option<Secret<String>>,
    pub network: Option<String>,
    pub uri: Option<String>,
    pub price_amount: Option<StringMajorUnit>,
    pub price_currency: Option<String>,
    pub pay_amount: Option<StringMajorUnit>,
    pub pay_currency: Option<String>,
    pub fee: Option<String>,
    pub fee_currency: Option<String>,
    pub paid_amount: Option<String>,
    pub name: Option<String>,
    pub description: Option<String>,
    pub success_redirect_url: Option<String>,
    pub unsuccess_redirect_url: Option<String>,
    pub hosted_page_url: Option<Url>,
    pub created_at: Option<String>,
    pub expires_at: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CryptopayWebhookDetails {
    #[serde(rename = "type")]
    pub service_type: String,
    pub event: WebhookEvent,
    pub data: CryptopayPaymentResponseData,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebhookEvent {
    TransactionCreated,
    TransactionConfirmed,
    StatusChanged,
}


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

pub fn update_default_fallback_routing(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    updated_list_of_connectors: Vec<routing_types::RoutableConnectorChoice>,
) -> RouterResponse<Vec<routing_types::RoutableConnectorChoice>>


// File: crates/router/src/services/openidconnect.rs
// Module: router
// Public functions: 2

use common_utils::errors::ErrorSwitch;
use error_stack::ResultExt;
use external_services::http_client::client;
use masking::{ExposeInterface, Secret};
use oidc::TokenResponse;
use openidconnect::{self as oidc, core as oidc_core};
use redis_interface::RedisConnectionPool;
use storage_impl::errors::ApiClientError;

use crate::{
    consts,
    core::errors::{UserErrors, UserResult},
    routes::SessionState,
    types::domain::user::UserEmail,
};

pub async fn get_authorization_url(
    state: SessionState,
    redirect_url: String,
    redirect_state: Secret<String>,
    base_url: Secret<String>,
    client_id: Secret<String>,
) -> UserResult<url::Url> {
    let discovery_document = get_discovery_document(base_url, &state).await?;

    let (auth_url, csrf_token, nonce) =
        get_oidc_core_client(discovery_document, client_id, None, redirect_url)?
            .authorize_url(
                oidc_core::CoreAuthenticationFlow::AuthorizationCode,
                || oidc::CsrfToken::new(redirect_state.expose()),
                oidc::Nonce::new_random,
            )
            .add_scope(oidc::Scope::new("email".to_string()))
            .url();

    // Save csrf & nonce as key value respectively
    let key = get_oidc_redis_key(csrf_token.secret());
    get_redis_connection_for_global_tenant(&state)?
        .set_key_with_expiry(&key.into(), nonce.secret(), consts::user::REDIS_SSO_TTL)
        .await
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to save csrf-nonce in redis")?;

    Ok(auth_url)
}

pub async fn get_user_email_from_oidc_provider(
    state: &SessionState,
    redirect_url: String,
    redirect_state: Secret<String>,
    base_url: Secret<String>,
    client_id: Secret<String>,
    authorization_code: Secret<String>,
    client_secret: Secret<String>,
) -> UserResult<UserEmail> {
    let nonce = get_nonce_from_redis(state, &redirect_state).await?;
    let discovery_document = get_discovery_document(base_url, state).await?;
    let client = get_oidc_core_client(
        discovery_document,
        client_id,
        Some(client_secret),
        redirect_url,
    )?;

    let nonce_clone = nonce.clone();
    client
        .authorize_url(
            oidc_core::CoreAuthenticationFlow::AuthorizationCode,
            || oidc::CsrfToken::new(redirect_state.expose()),
            || nonce_clone,
        )
        .add_scope(oidc::Scope::new("email".to_string()));

    // Send request to OpenId provider with authorization code
    let token_response = client
        .exchange_code(oidc::AuthorizationCode::new(authorization_code.expose()))
        .request_async(|req| get_oidc_reqwest_client(state, req))
        .await
        .map_err(|e| match e {
            oidc::RequestTokenError::ServerResponse(resp)
                if resp.error() == &oidc_core::CoreErrorResponseType::InvalidGrant =>
            {
                UserErrors::SSOFailed
            }
            _ => UserErrors::InternalServerError,
        })
        .attach_printable("Failed to exchange code and fetch oidc token")?;

    // Fetch id token from response
    let id_token = token_response
        .id_token()
        .ok_or(UserErrors::InternalServerError)
        .attach_printable("Id Token not provided in token response")?;

    // Verify id token
    let id_token_claims = id_token
        .claims(&client.id_token_verifier(), &nonce)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to verify id token")?;

    // Get email from token
    let email_from_token = id_token_claims
        .email()
        .map(|email| email.to_string())
        .ok_or(UserErrors::InternalServerError)
        .attach_printable("OpenID Provider Didnt provide email")?;

    UserEmail::new(Secret::new(email_from_token))
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to create email type")
}

// TODO: Cache Discovery Document
async fn get_discovery_document(
    base_url: Secret<String>,
    state: &SessionState,
) -> UserResult<oidc_core::CoreProviderMetadata> {
    let issuer_url =
        oidc::IssuerUrl::new(base_url.expose()).change_context(UserErrors::InternalServerError)?;
    oidc_core::CoreProviderMetadata::discover_async(issuer_url, |req| {
        get_oidc_reqwest_client(state, req)
    })
    .await
    .change_context(UserErrors::InternalServerError)
}

fn get_oidc_core_client(
    discovery_document: oidc_core::CoreProviderMetadata,
    client_id: Secret<String>,
    client_secret: Option<Secret<String>>,
    redirect_url: String,
) -> UserResult<oidc_core::CoreClient> {
    let client_id = oidc::ClientId::new(client_id.expose());
    let client_secret = client_secret.map(|secret| oidc::ClientSecret::new(secret.expose()));
    let redirect_url = oidc::RedirectUrl::new(redirect_url)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error creating redirect URL type")?;

    Ok(
        oidc_core::CoreClient::from_provider_metadata(discovery_document, client_id, client_secret)
            .set_redirect_uri(redirect_url),
    )
}

async fn get_nonce_from_redis(
    state: &SessionState,
    redirect_state: &Secret<String>,
) -> UserResult<oidc::Nonce> {
    let redis_connection = get_redis_connection_for_global_tenant(state)?;
    let redirect_state = redirect_state.clone().expose();
    let key = get_oidc_redis_key(&redirect_state);
    redis_connection
        .get_key::<Option<String>>(&key.into())
        .await
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Fetching CSRF from redis")?
        .map(oidc::Nonce::new)
        .ok_or(UserErrors::SSOFailed)
        .attach_printable("Cannot find csrf in redis. Csrf invalid or expired")
}

async fn get_oidc_reqwest_client(
    state: &SessionState,
    request: oidc::HttpRequest,
) -> Result<oidc::HttpResponse, ApiClientError> {
    let client = client::create_client(&state.conf.proxy, None, None, None)
        .map_err(|e| e.current_context().switch())?;

    let mut request_builder = client
        .request(request.method, request.url)
        .body(request.body);
    for (name, value) in &request.headers {
        request_builder = request_builder.header(name.as_str(), value.as_bytes());
    }

    let request = request_builder
        .build()
        .map_err(|_| ApiClientError::ClientConstructionFailed)?;
    let response = client
        .execute(request)
        .await
        .map_err(|_| ApiClientError::RequestNotSent("OpenIDConnect".to_string()))?;

    Ok(oidc::HttpResponse {
        status_code: response.status(),
        headers: response.headers().to_owned(),
        body: response
            .bytes()
            .await
            .map_err(|_| ApiClientError::ResponseDecodingFailed)?
            .to_vec(),
    })
}

fn get_oidc_redis_key(csrf: &str) -> String {
    format!("{}OIDC_{}", consts::user::REDIS_SSO_PREFIX, csrf)
}

fn get_redis_connection_for_global_tenant(
    state: &SessionState,
) -> UserResult<std::sync::Arc<RedisConnectionPool>> {
    state
        .global_store
        .get_redis_conn()
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to get redis connection")
}


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

pub fn mk_basilisk_req(
    jwekey: &settings::Jwekey,
    jws: &str,
    locker_choice: api_enums::LockerChoice,
) -> CustomResult<encryption::JweBody, errors::VaultError>


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

pub struct AveragePaymentTime


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

impl api::Payment for for Payload


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

pub fn store_card_in_locker(
        &self,
        card: &domain::CardDetail,
        customer_id: &id_type::CustomerId,
    ) -> RouterResult<pm_transformers::StoreCardRespPayload>


        payment_data,
        req,
        customer,
        connector_http_status_code,
        external_latency,
    ))
}

#[cfg(feature = "v1")]
// This function is intended for use when the feature being implemented is not aligned with the
// core payment operations.
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[instrument(skip_all, fields(payment_id, merchant_id))]
pub async fn proxy_for_payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile_id_from_auth_layer: Option<id_type::ProfileId>,
    operation: Op,
    req: Req,
    call_connector_action: CallConnectorAction,
    auth_flow: services::AuthFlow,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(D, Req, Option<domain::Customer>, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Authenticate + Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
    FData: Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    tracing::Span::current().record(
        "merchant_id",
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
    );
    let (operation, validate_result) = operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    tracing::Span::current().record("payment_id", format!("{}", validate_result.payment_id));

    let operations::GetTrackerResponse {
        operation,
        customer_details: _,
        mut payment_data,
        business_profile,
        mandate_type: _,
    } = operation
        .to_get_tracker()?
        .get_trackers(
            state,
            &validate_result.payment_id,
            &req,
            &merchant_context,
            auth_flow,
            &header_payload,
        )
        .await?;

    core_utils::validate_profile_id_from_auth_layer(
        profile_id_from_auth_layer,
        &payment_data.get_payment_intent().clone(),
    )?;

    common_utils::fp_utils::when(!should_call_connector(&operation, &payment_data), || {
        Err(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration).attach_printable(format!(
            "Nti and card details based mit flow is not support for this {operation:?} payment operation"
        ))
    })?;

    let connector_choice = operation
        .to_domain()?
        .get_connector(
            &merchant_context,
            &state.clone(),
            &req,
            payment_data.get_payment_intent(),
        )
        .await?;

    let connector = set_eligible_connector_for_nti_in_payment_data(
        state,
        &business_profile,
        merchant_context.get_merchant_key_store(),
        &mut payment_data,
        connector_choice,
    )
    .await?;

    let should_add_task_to_process_tracker = should_add_task_to_process_tracker(&payment_data);

    let locale = header_payload.locale.clone();

    let schedule_time = if should_add_task_to_process_tracker {
        payment_sync::get_sync_process_schedule_time(
            &*state.store,
            connector.connector.id(),
            merchant_context.get_merchant_account().get_id(),
            0,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while getting process schedule time")?
    } else {
        None
    };

    let (router_data, mca) = proxy_for_call_connector_service(
        state,
        req_state.clone(),
        &merchant_context,
        connector.clone(),
        &operation,
        &mut payment_data,
        &None,
        call_connector_action.clone(),
        &validate_result,
        schedule_time,
        header_payload.clone(),
        &business_profile,
        return_raw_connector_response,
    )
    .await?;

    let op_ref = &operation;
    let should_trigger_post_processing_flows = is_operation_confirm(&operation);

    let operation = Box::new(PaymentResponse);

    let connector_http_status_code = router_data.connector_http_status_code;
    let external_latency = router_data.external_latency;

    add_connector_http_status_code_metrics(connector_http_status_code);

    #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
    let routable_connectors =
        convert_connector_data_to_routable_connectors(&[connector.clone().into()])
            .map_err(|e| logger::error!(routable_connector_error=?e))
            .unwrap_or_default();

    let mut payment_data = operation
        .to_post_update_tracker()?
        .update_tracker(
            state,
            payment_data,
            router_data,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
            &locale,
            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
            routable_connectors,
            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
            &business_profile,
        )
        .await?;

    if should_trigger_post_processing_flows {
        complete_postprocessing_steps_if_required(
            state,
            &merchant_context,
            &None,
            &mca,
            &connector,
            &mut payment_data,
            op_ref,
            Some(header_payload.clone()),
        )
        .await?;
    }

    let cloned_payment_data = payment_data.clone();

    utils::trigger_payments_webhook(
        merchant_context.clone(),
        business_profile,
        cloned_payment_data,
        None,
        state,
        operation,
    )
    .await
    .map_err(|error| logger::warn!(payments_outgoing_webhook_error=?error))
    .ok();

    Ok((
        payment_data,
        req,
        None,
        connector_http_status_code,
        external_latency,
    ))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[instrument(skip_all, fields(payment_id, merchant_id))]
pub async fn proxy_for_payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    get_tracker_response: operations::GetTrackerResponse<D>,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(D, Req, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
    FData: Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    // Get the trackers related to track the state of the payment
    let operations::GetTrackerResponse { mut payment_data } = get_tracker_response;
    // consume the req merchant_connector_id and set it in the payment_data
    let connector = operation
        .to_domain()?
        .perform_routing(&merchant_context, &profile, state, &mut payment_data)
        .await?;

    let payment_data = match connector {
        ConnectorCallType::PreDetermined(connector_data) => {
            let router_data = proxy_for_call_connector_service(
                state,
                req_state.clone(),
                &merchant_context,
                connector_data.connector_data.clone(),
                &operation,
                &mut payment_data,
                call_connector_action.clone(),
                header_payload.clone(),
                &profile,
                return_raw_connector_response,
            )
            .await?;

            let payments_response_operation = Box::new(PaymentResponse);

            payments_response_operation
                .to_post_update_tracker()?
                .update_tracker(
                    state,
                    payment_data,
                    router_data,
                    merchant_context.get_merchant_key_store(),
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await?
        }
        ConnectorCallType::Retryable(vec) => todo!(),
        ConnectorCallType::SessionMultiple(vec) => todo!(),
        ConnectorCallType::Skip => payment_data,
    };

    Ok((payment_data, req, None, None))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[instrument(skip_all, fields(payment_id, merchant_id))]
pub async fn external_vault_proxy_for_payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    get_tracker_response: operations::GetTrackerResponse<D>,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(D, Req, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
    FData: Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    // Get the trackers related to track the state of the payment
    let operations::GetTrackerResponse { mut payment_data } = get_tracker_response;

    let (_operation, customer) = operation
        .to_domain()?
        .get_customer_details(
            state,
            &mut payment_data,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
        .attach_printable("Failed while fetching/creating customer")?;

    operation
        .to_domain()?
        .create_or_fetch_payment_method(state, &merchant_context, &profile, &mut payment_data)
        .await?;

    // consume the req merchant_connector_id and set it in the payment_data
    let connector = operation
        .to_domain()?
        .perform_routing(&merchant_context, &profile, state, &mut payment_data)
        .await?;

    let payment_data = match connector {
        ConnectorCallType::PreDetermined(connector_data) => {
            let (mca_type_details, external_vault_mca_type_details, updated_customer, router_data) =
                call_connector_service_prerequisites_for_external_vault_proxy(
                    state,
                    req_state.clone(),
                    &merchant_context,
                    connector_data.connector_data.clone(),
                    &operation,
                    &mut payment_data,
                    &customer,
                    call_connector_action.clone(),
                    None,
                    header_payload.clone(),
                    None,
                    &profile,
                    false,
                    false, //should_retry_with_pan is set to false in case of PreDetermined ConnectorCallType
                    req.should_return_raw_response(),
                )
                .await?;

            let router_data = call_unified_connector_service_for_external_proxy(
                state,
                req_state.clone(),
                &merchant_context,
                connector_data.connector_data.clone(),
                &operation,
                &mut payment_data,
                &customer,
                call_connector_action.clone(),
                None, // schedule_time is not used in PreDetermined ConnectorCallType
                header_payload.clone(),
                #[cfg(feature = "frm")]
                None,
                &profile,
                false,
                false, //should_retry_with_pan is set to false in case of PreDetermined ConnectorCallType
                req.should_return_raw_response(),
                mca_type_details,
                external_vault_mca_type_details,
                router_data,
                updated_customer,
            )
            .await?;

            // update payment method if its a successful transaction
            if router_data.status.is_success() {
                operation
                    .to_domain()?
                    .update_payment_method(state, &merchant_context, &mut payment_data)
                    .await;
            }

            let payments_response_operation = Box::new(PaymentResponse);

            payments_response_operation
                .to_post_update_tracker()?
                .update_tracker(
                    state,
                    payment_data,
                    router_data,
                    merchant_context.get_merchant_key_store(),
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await?
        }
        ConnectorCallType::Retryable(_) => todo!(),
        ConnectorCallType::SessionMultiple(_) => todo!(),
        ConnectorCallType::Skip => payment_data,
    };

    Ok((payment_data, req, None, None))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[instrument(skip_all, fields(payment_id, merchant_id))]
pub async fn payments_intent_operation_core<F, Req, Op, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResult<(D, Req, Option<domain::Customer>)>
where
    F: Send + Clone + Sync,
    Req: Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    tracing::Span::current().record(
        "merchant_id",
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
    );

    let _validate_result = operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    tracing::Span::current().record("global_payment_id", payment_id.get_string_repr());

    let operations::GetTrackerResponse { mut payment_data } = operation
        .to_get_tracker()?
        .get_trackers(
            state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;

    let (_operation, customer) = operation
        .to_domain()?
        .get_customer_details(
            state,
            &mut payment_data,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
        .attach_printable("Failed while fetching/creating customer")?;

    let (_operation, payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data,
            customer.clone(),
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None,
            header_payload,
        )
        .await?;

    Ok((payment_data, req, customer))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[instrument(skip_all, fields(payment_id, merchant_id))]
pub async fn payments_attempt_operation_core<F, Req, Op, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResult<(D, Req, Option<domain::Customer>)>
where
    F: Send + Clone + Sync,
    Req: Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    tracing::Span::current().record(
        "merchant_id",
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
    );

    let _validate_result = operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    tracing::Span::current().record("global_payment_id", payment_id.get_string_repr());

    let operations::GetTrackerResponse { mut payment_data } = operation
        .to_get_tracker()?
        .get_trackers(
            state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;

    let (_operation, customer) = operation
        .to_domain()?
        .get_customer_details(
            state,
            &mut payment_data,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
        .attach_printable("Failed while fetching/creating customer")?;

    let (_operation, payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data,
            customer.clone(),
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None,
            header_payload,
        )
        .await?;

    Ok((payment_data, req, customer))
}

#[instrument(skip_all)]
#[cfg(feature = "v1")]
pub async fn call_decision_manager<F, D>(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    _business_profile: &domain::Profile,
    payment_data: &D,
) -> RouterResult<Option<enums::AuthenticationType>>
where
    F: Clone,
    D: OperationSessionGetters<F>,
{
    let setup_mandate = payment_data.get_setup_mandate();
    let payment_method_data = payment_data.get_payment_method_data();
    let payment_dsl_data = core_routing::PaymentsDslInput::new(
        setup_mandate,
        payment_data.get_payment_attempt(),
        payment_data.get_payment_intent(),
        payment_method_data,
        payment_data.get_address(),
        payment_data.get_recurring_details(),
        payment_data.get_currency(),
    );
    let algorithm_ref: api::routing::RoutingAlgorithmRef = merchant_context
        .get_merchant_account()
        .routing_algorithm
        .clone()
        .map(|val| val.parse_value("routing algorithm"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not decode the routing algorithm")?
        .unwrap_or_default();

    let output = perform_decision_management(
        state,
        algorithm_ref,
        merchant_context.get_merchant_account().get_id(),
        &payment_dsl_data,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Could not decode the conditional config")?;
    Ok(payment_dsl_data
        .payment_attempt
        .authentication_type
        .or(output.override_3ds))
}

// TODO: Move to business profile surcharge column
#[instrument(skip_all)]
#[cfg(feature = "v2")]
pub fn call_decision_manager<F>(
    state: &SessionState,
    record: common_types::payments::DecisionManagerRecord,
    payment_data: &PaymentConfirmData<F>,
) -> RouterResult<Option<enums::AuthenticationType>>
where
    F: Clone,
{
    let payment_method_data = payment_data.get_payment_method_data();
    let payment_dsl_data = core_routing::PaymentsDslInput::new(
        None,
        payment_data.get_payment_attempt(),
        payment_data.get_payment_intent(),
        payment_method_data,
        payment_data.get_address(),
        None,
        payment_data.get_currency(),
    );

    let output = perform_decision_management(record, &payment_dsl_data)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not decode the conditional config")?;

    Ok(output.override_3ds)
}

#[cfg(feature = "v2")]
#[instrument(skip_all)]
async fn populate_surcharge_details<F>(
    state: &SessionState,
    payment_data: &mut PaymentData<F>,
) -> RouterResult<()>
where
    F: Send + Clone,
{
    todo!()
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
async fn populate_surcharge_details<F>(
    state: &SessionState,
    payment_data: &mut PaymentData<F>,
) -> RouterResult<()>
where
    F: Send + Clone,
{
    if payment_data
        .payment_intent
        .surcharge_applicable
        .unwrap_or(false)
    {
        logger::debug!("payment_intent.surcharge_applicable = true");
        if let Some(surcharge_details) = payment_data.payment_attempt.get_surcharge_details() {
            // if retry payment, surcharge would have been populated from the previous attempt. Use the same surcharge
            let surcharge_details =
                types::SurchargeDetails::from((&surcharge_details, &payment_data.payment_attempt));
            payment_data.surcharge_details = Some(surcharge_details);
            return Ok(());
        }
        let raw_card_key = payment_data
            .payment_method_data
            .as_ref()
            .and_then(helpers::get_key_params_for_surcharge_details)
            .map(|(payment_method, payment_method_type, card_network)| {
                types::SurchargeKey::PaymentMethodData(
                    payment_method,
                    payment_method_type,
                    card_network,
                )
            });
        let saved_card_key = payment_data.token.clone().map(types::SurchargeKey::Token);

        let surcharge_key = raw_card_key
            .or(saved_card_key)
            .get_required_value("payment_method_data or payment_token")?;
        logger::debug!(surcharge_key_confirm =? surcharge_key);

        let calculated_surcharge_details =
            match types::SurchargeMetadata::get_individual_surcharge_detail_from_redis(
                state,
                surcharge_key,
                &payment_data.payment_attempt.attempt_id,
            )
            .await
            {
                Ok(surcharge_details) => Some(surcharge_details),
                Err(err) if err.current_context() == &RedisError::NotFound => None,
                Err(err) => {
                    Err(err).change_context(errors::ApiErrorResponse::InternalServerError)?
                }
            };

        payment_data.surcharge_details = calculated_surcharge_details.clone();

        //Update payment_attempt net_amount with surcharge details
        payment_data
            .payment_attempt
            .net_amount
            .set_surcharge_details(calculated_surcharge_details);
    } else {
        let surcharge_details =
            payment_data
                .payment_attempt
                .get_surcharge_details()
                .map(|surcharge_details| {
                    logger::debug!("surcharge sent in payments create request");
                    types::SurchargeDetails::from((
                        &surcharge_details,
                        &payment_data.payment_attempt,
                    ))
                });
        payment_data.surcharge_details = surcharge_details;
    }
    Ok(())
}

#[inline]
pub fn get_connector_data(
    connectors: &mut IntoIter<api::ConnectorRoutingData>,
) -> RouterResult<api::ConnectorRoutingData> {
    connectors
        .next()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Connector not found in connectors iterator")
}

#[cfg(feature = "v1")]
pub fn get_connector_with_networks(
    connectors: &mut IntoIter<api::ConnectorRoutingData>,
) -> Option<(api::ConnectorData, enums::CardNetwork)> {
    connectors.find_map(|connector| {
        connector
            .network
            .map(|network| (connector.connector_data, network))
    })
}

#[cfg(feature = "v1")]
fn get_connector_data_with_routing_decision(
    connectors: &mut IntoIter<api::ConnectorRoutingData>,
    business_profile: &domain::Profile,
    debit_routing_output_optional: Option<api_models::open_router::DebitRoutingOutput>,
) -> RouterResult<(
    api::ConnectorData,
    Option<routing_helpers::RoutingDecisionData>,
)> {
    if business_profile.is_debit_routing_enabled && debit_routing_output_optional.is_some() {
        if let Some((data, card_network)) = get_connector_with_networks(connectors) {
            let debit_routing_output =
                debit_routing_output_optional.get_required_value("debit routing output")?;
            let routing_decision =
                routing_helpers::RoutingDecisionData::get_debit_routing_decision_data(
                    card_network,
                    Some(debit_routing_output),
                );
            return Ok((data, Some(routing_decision)));
        }
    }

    Ok((get_connector_data(connectors)?.connector_data, None))
}

#[cfg(feature = "v2")]
#[instrument(skip_all)]
pub async fn call_surcharge_decision_management_for_session_flow(
    _state: &SessionState,
    _merchant_context: &domain::MerchantContext,
    _payment_attempt: &storage::PaymentAttempt,
    _payment_intent: &storage::PaymentIntent,
    _billing_address: Option<hyperswitch_domain_models::address::Address>,
    _session_connector_data: &[api::SessionConnectorData],
) -> RouterResult<Option<api::SessionSurchargeDetails>> {
    todo!()
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn call_surcharge_decision_management_for_session_flow(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    _business_profile: &domain::Profile,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    billing_address: Option<hyperswitch_domain_models::address::Address>,
    session_connector_data: &api::SessionConnectorDatas,
) -> RouterResult<Option<api::SessionSurchargeDetails>> {
    if let Some(surcharge_amount) = payment_attempt.net_amount.get_surcharge_amount() {
        Ok(Some(api::SessionSurchargeDetails::PreDetermined(
            types::SurchargeDetails {
                original_amount: payment_attempt.net_amount.get_order_amount(),
                surcharge: Surcharge::Fixed(surcharge_amount),
                tax_on_surcharge: None,
                surcharge_amount,
                tax_on_surcharge_amount: payment_attempt
                    .net_amount
                    .get_tax_on_surcharge()
                    .unwrap_or_default(),
            },
        )))
    } else {
        let payment_method_type_list = session_connector_data
            .iter()
            .map(|session_connector_data| session_connector_data.payment_method_sub_type)
            .collect();

        #[cfg(feature = "v1")]
        let algorithm_ref: api::routing::RoutingAlgorithmRef = merchant_context
            .get_merchant_account()
            .routing_algorithm
            .clone()
            .map(|val| val.parse_value("routing algorithm"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Could not decode the routing algorithm")?
            .unwrap_or_default();

        // TODO: Move to business profile surcharge column
        #[cfg(feature = "v2")]
        let algorithm_ref: api::routing::RoutingAlgorithmRef = todo!();

        let surcharge_results =
            surcharge_decision_configs::perform_surcharge_decision_management_for_session_flow(
                state,
                algorithm_ref,
                payment_attempt,
                payment_intent,
                billing_address,
                &payment_method_type_list,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("error performing surcharge decision operation")?;

        Ok(if surcharge_results.is_empty_result() {
            None
        } else {
            Some(api::SessionSurchargeDetails::Calculated(surcharge_results))
        })
    }
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn payments_core<F, Res, Req, Op, FData, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<id_type::ProfileId>,
    operation: Op,
    req: Req,
    auth_flow: services::AuthFlow,
    call_connector_action: CallConnectorAction,
    eligible_connectors: Option<Vec<enums::Connector>>,
    header_payload: HeaderPayload,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    FData: Send + Sync + Clone + router_types::Capturable,
    Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
    Req: Debug + Authenticate + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
    Res: transformers::ToResponse<F, D, Op>,
    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
{
    let eligible_routable_connectors = eligible_connectors.map(|connectors| {
        connectors
            .into_iter()
            .flat_map(|c| c.foreign_try_into())
            .collect()
    });
    let (payment_data, _req, customer, connector_http_status_code, external_latency) =
        payments_operation_core::<_, _, _, _, _>(
            &state,
            req_state,
            &merchant_context,
            profile_id,
            operation.clone(),
            req,
            call_connector_action,
            auth_flow,
            eligible_routable_connectors,
            header_payload.clone(),
        )
        .await?;

    Res::generate_response(
        payment_data,
        customer,
        auth_flow,
        &state.base_url,
        operation,
        &state.conf.connector_request_reference_id_config,
        connector_http_status_code,
        external_latency,
        header_payload.x_hs_latency,
    )
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn proxy_for_payments_core<F, Res, Req, Op, FData, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<id_type::ProfileId>,
    operation: Op,
    req: Req,
    auth_flow: services::AuthFlow,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    FData: Send + Sync + Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
    Req: Debug + Authenticate + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
    Res: transformers::ToResponse<F, D, Op>,
    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
{
    let (payment_data, _req, customer, connector_http_status_code, external_latency) =
        proxy_for_payments_operation_core::<_, _, _, _, _>(
            &state,
            req_state,
            merchant_context,
            profile_id,
            operation.clone(),
            req,
            call_connector_action,
            auth_flow,
            header_payload.clone(),
            return_raw_connector_response,
        )
        .await?;

    Res::generate_response(
        payment_data,
        customer,
        auth_flow,
        &state.base_url,
        operation,
        &state.conf.connector_request_reference_id_config,
        connector_http_status_code,
        external_latency,
        header_payload.x_hs_latency,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn proxy_for_payments_core<F, Res, Req, Op, FData, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    FData: Send + Sync + Clone,
    Op: Operation<F, Req, Data = D> + ValidateStatusForOperation + Send + Sync + Clone,
    Req: Debug,
    D: OperationSessionGetters<F>
        + OperationSessionSetters<F>
        + transformers::GenerateResponse<Res>
        + Send
        + Sync
        + Clone,
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    PaymentResponse: Operation<F, FData, Data = D>,

    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,
{
    operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    let get_tracker_response = operation
        .to_get_tracker()?
        .get_trackers(
            &state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;

    let (payment_data, _req, connector_http_status_code, external_latency) =
        proxy_for_payments_operation_core::<_, _, _, _, _>(
            &state,
            req_state,
            merchant_context.clone(),
            profile.clone(),
            operation.clone(),
            req,
            get_tracker_response,
            call_connector_action,
            header_payload.clone(),
            return_raw_connector_response,
        )
        .await?;

    payment_data.generate_response(
        &state,
        connector_http_status_code,
        external_latency,
        header_payload.x_hs_latency,
        &merchant_context,
        &profile,
        None,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn external_vault_proxy_for_payments_core<F, Res, Req, Op, FData, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    FData: Send + Sync + Clone,
    Op: Operation<F, Req, Data = D> + ValidateStatusForOperation + Send + Sync + Clone,
    Req: Debug,
    D: OperationSessionGetters<F>
        + OperationSessionSetters<F>
        + transformers::GenerateResponse<Res>
        + Send
        + Sync
        + Clone,
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,


// Struct: ConnectorAuthentication
// File: crates/test_utils/src/connector_auth.rs
// Module: test_utils
// Implementations: 2
// Traits: Default

pub struct ConnectorAuthentication


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

impl Responder


// Implementation: impl FlattenedPaymentMethodsEnabled
// File: crates/router/src/core/payments/payment_methods.rs
// Module: router
// Methods: 1 total (0 public)

impl FlattenedPaymentMethodsEnabled


// Struct: SdkEventMetricsAccumulator
// File: crates/analytics/src/sdk_events/accumulator.rs
// Module: analytics
// Implementations: 1

pub struct SdkEventMetricsAccumulator


// Struct: MerchantAdvice
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MerchantAdvice


// Function: get_action_url
// File: crates/router/src/routes/connector_onboarding.rs
// Module: router

pub fn get_action_url(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<api_types::ActionUrlRequest>,
) -> HttpResponse


// Function: find_generic_link_by_link_id
// File: crates/diesel_models/src/query/generic_link.rs
// Module: diesel_models

pub fn find_generic_link_by_link_id(
        conn: &PgPooledConn,
        link_id: &str,
    ) -> StorageResult<GenericLinkState>


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

pub struct RefundResponse


// Function: create_payment_method_api
// File: crates/openapi/src/routes/payment_method.rs
// Module: openapi

pub fn create_payment_method_api()


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

impl ConnectorRedirectResponse for for ConnectorEnum


// Function: totp_update
// File: crates/router/src/routes/user.rs
// Module: router

pub fn totp_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_api::VerifyTotpRequest>,
) -> HttpResponse


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

// Documentation: Dummy handler for signals in windows (empty)

pub fn handle(&self) -> Self


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

pub fn new() -> &'static Self


// Module Structure
// File: crates/router/src/types/api/files.rs
// Module: router

// Public exports:
pub use hyperswitch_domain_models::router_flow_types::files::{Retrieve, Upload};
pub use hyperswitch_interfaces::api::files::{FilePurpose, FileUpload, RetrieveFile, UploadFile};
pub use super::files_v2::{FileUploadV2, RetrieveFileV2, UploadFileV2};


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

use std::str::FromStr;

crate::id_type!(
    ProfileId,
    "A type for profile_id that can be used for business profile ids"
);
crate::impl_id_type_methods!(ProfileId, "profile_id");

// This is to display the `ProfileId` as ProfileId(abcd)
crate::impl_debug_id_type!(ProfileId);
crate::impl_try_from_cow_str_id_type!(ProfileId, "profile_id");
crate::impl_generate_id_id_type!(ProfileId, "pro");
crate::impl_serializable_secret_id_type!(ProfileId);
crate::impl_queryable_id_type!(ProfileId);
crate::impl_to_sql_from_sql_id_type!(ProfileId);

impl crate::events::ApiEventMetric for ProfileId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::BusinessProfile {
            profile_id: self.clone(),
        })
    }
}

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

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

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


// Struct: ApplePayTokenizedCard
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApplePayTokenizedCard


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

impl api::PaymentAuthorize for for Moneris


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

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


// Struct: LockerMockUp
// File: crates/diesel_models/src/locker_mock_up.rs
// Module: diesel_models
// Implementations: 0

pub struct LockerMockUp


// Struct: ChargebeeInvoiceData
// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ChargebeeInvoiceData


// Struct: PaymentLinkFormData
// File: crates/hyperswitch_domain_models/src/api.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentLinkFormData


// Implementation: impl api::RefundExecute for for Bitpay
// File: crates/hyperswitch_connectors/src/connectors/bitpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Bitpay


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

pub fn new() -> &'static Self


// Function: validate
// File: crates/analytics/src/opensearch.rs
// Module: analytics

pub fn validate(&self) -> Result<(), ApplicationError>


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

pub struct CardPaymentInformation


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

impl api::Refund for for Payload


// Implementation: impl api::ConnectorValidation for for Wise
// File: crates/hyperswitch_connectors/src/connectors/wise.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorValidation for for Wise


// Function: delete_surcharge_decision_config
// File: crates/router/src/core/surcharge_decision_config.rs
// Module: router

pub fn delete_surcharge_decision_config(
    _state: SessionState,
    _merchant_context: domain::MerchantContext,
) -> RouterResponse<()>


// Function: evaluate_routing_rule
// File: crates/openapi/src/routes/routing.rs
// Module: openapi

pub fn evaluate_routing_rule()


// Struct: UserField
// File: crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct UserField


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

impl api::RefundSync for for Nexinets


                ApiError::new("IR", 4, format!("Missing required param: {field_name}"), None),
            ),
            Self::InvalidDataFormat {
                field_name,
                expected_format,
            } => AER::Unprocessable(ApiError::new(
                "IR",
                5,
                format!(
                    "{field_name} contains invalid data. Expected format is {expected_format}"
                ), None
            )),
            Self::InvalidRequestData { message } => {
                AER::Unprocessable(ApiError::new("IR", 6, message.to_string(), None))
            }
            Self::InvalidDataValue { field_name } => AER::BadRequest(ApiError::new(
                "IR",
                7,
                format!("Invalid value provided: {field_name}"), None
            )),
            Self::ClientSecretNotGiven => AER::BadRequest(ApiError::new(
                "IR",
                8,
                "client_secret was not provided", None
            )),
            Self::ClientSecretExpired => AER::BadRequest(ApiError::new(
                "IR",
                8,
                "The provided client_secret has expired", None
            )),
            Self::ClientSecretInvalid => {
                AER::BadRequest(ApiError::new("IR", 9, "The client_secret provided does not match the client_secret associated with the Payment", None))
            }
            Self::MandateActive => {
                AER::BadRequest(ApiError::new("IR", 10, "Customer has active mandate/subsciption", None))
            }
            Self::CustomerRedacted => {
                AER::BadRequest(ApiError::new("IR", 11, "Customer has already been redacted", None))
            }
            Self::MaximumRefundCount => AER::BadRequest(ApiError::new("IR", 12, "Reached maximum refund attempts", None)),
            Self::RefundAmountExceedsPaymentAmount => {
                AER::BadRequest(ApiError::new("IR", 13, "The refund amount exceeds the amount captured", None))
            }
            Self::PaymentUnexpectedState {
                current_flow,
                field_name,
                current_value,
                states,
            } => AER::BadRequest(ApiError::new("IR", 14, format!("This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}"), None)),
            Self::InvalidEphemeralKey => AER::Unauthorized(ApiError::new("IR", 15, "Invalid Ephemeral Key for the customer", None)),
            Self::PreconditionFailed { message } => {
                AER::BadRequest(ApiError::new("IR", 16, message.to_string(), None))
            }
            Self::InvalidJwtToken => AER::Unauthorized(ApiError::new("IR", 17, "Access forbidden, invalid JWT token was used", None)),
            Self::GenericUnauthorized { message } => {
                AER::Unauthorized(ApiError::new("IR", 18, message.to_string(), None))
            },
            Self::NotSupported { message } => {
                AER::BadRequest(ApiError::new("IR", 19, "Payment method type not supported", Some(Extra {reason: Some(message.to_owned()), ..Default::default()})))
            },
            Self::FlowNotSupported { flow, connector } => {
                AER::BadRequest(ApiError::new("IR", 20, format!("{flow} flow not supported"), Some(Extra {connector: Some(connector.to_owned()), ..Default::default()}))) //FIXME: error message
            }
            Self::MissingRequiredFields { field_names } => AER::BadRequest(
                ApiError::new("IR", 21, "Missing required params".to_string(), Some(Extra {data: Some(serde_json::json!(field_names)), ..Default::default() })),
            ),
            Self::AccessForbidden {resource} => {
                AER::ForbiddenCommonResource(ApiError::new("IR", 22, format!("Access forbidden. Not authorized to access this resource {resource}"), None))
            },
            Self::FileProviderNotSupported { message } => {
                AER::BadRequest(ApiError::new("IR", 23, message.to_string(), None))
            },
            Self::InvalidWalletToken { wallet_name} => AER::Unprocessable(ApiError::new(
                "IR",
                24,
                format!("Invalid {wallet_name} wallet token"), None
            )),
            Self::PaymentMethodDeleteFailed => {
                AER::BadRequest(ApiError::new("IR", 25, "Cannot delete the default payment method", None))
            }
            Self::InvalidCookie => {
                AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
            }
            Self::ExtendedCardInfoNotFound => {
                AER::NotFound(ApiError::new("IR", 27, "Extended card info does not exist", None))
            }
            Self::CurrencyNotSupported { message } => {
                AER::BadRequest(ApiError::new("IR", 28, message, None))
            }
            Self::UnprocessableEntity {message} => AER::Unprocessable(ApiError::new("IR", 29, message.to_string(), None)),
            Self::InvalidConnectorConfiguration {config} => {
                AER::BadRequest(ApiError::new("IR", 30, format!("Merchant connector account is configured with invalid {config}"), None))
            }
            Self::InvalidCardIin => AER::BadRequest(ApiError::new("IR", 31, "The provided card IIN does not exist", None)),
            Self::InvalidCardIinLength  => AER::BadRequest(ApiError::new("IR", 32, "The provided card IIN length is invalid, please provide an IIN with 6 digits", None)),
            Self::MissingFile => {
                AER::BadRequest(ApiError::new("IR", 33, "File not found in the request", None))
            }
            Self::MissingDisputeId => {
                AER::BadRequest(ApiError::new("IR", 34, "Dispute id not found in the request", None))
            }
            Self::MissingFilePurpose => {
                AER::BadRequest(ApiError::new("IR", 35, "File purpose not found in the request or is invalid", None))
            }
            Self::MissingFileContentType => {
                AER::BadRequest(ApiError::new("IR", 36, "File content type not found", None))
            }
            Self::GenericNotFoundError { message } => {
                AER::NotFound(ApiError::new("IR", 37, message, None))
            },
            Self::GenericDuplicateError { message } => {
                AER::BadRequest(ApiError::new("IR", 38, message, None))
            }
            Self::IncorrectPaymentMethodConfiguration => {
                AER::BadRequest(ApiError::new("IR", 39, "No eligible connector was found for the current payment method configuration", None))
            }
            Self::LinkConfigurationError { message } => {
                AER::BadRequest(ApiError::new("IR", 40, message, None))
            },
            Self::PayoutFailed { data } => {
                AER::BadRequest(ApiError::new("IR", 41, "Payout failed while processing with connector.", Some(Extra { data: data.clone(), ..Default::default()})))
            },
            Self::CookieNotFound => {
                AER::Unauthorized(ApiError::new("IR", 42, "Cookies are not found in the request", None))
            },
            Self::ExternalVaultFailed => {
                AER::BadRequest(ApiError::new("IR", 45, "External Vault failed while processing with connector.", None))
            },
            Self::MandatePaymentDataMismatch { fields} => {
                AER::BadRequest(ApiError::new("IR", 46, format!("Field {fields} doesn't match with the ones used during mandate creation"), Some(Extra {fields: Some(fields.to_owned()), ..Default::default()}))) //FIXME: error message
            }
            Self::MaxFieldLengthViolated { connector, field_name,  max_length, received_length} => {
                AER::BadRequest(ApiError::new("IR", 47, format!("Connector '{connector}' rejected field '{field_name}': length {received_length} exceeds maximum of {max_length}"), Some(Extra {connector: Some(connector.to_string()), ..Default::default()})))
            }
            Self::WebhookAuthenticationFailed => {
                AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
            }
            Self::WebhookBadRequest => {
                AER::BadRequest(ApiError::new("WE", 2, "Bad request body received", None))
            }
            Self::WebhookProcessingFailure => {
                AER::InternalServerError(ApiError::new("WE", 3, "There was an issue processing the webhook", None))
            },
            Self::WebhookResourceNotFound => {
                AER::NotFound(ApiError::new("WE", 4, "Webhook resource was not found", None))
            }
            Self::WebhookUnprocessableEntity => {
                AER::Unprocessable(ApiError::new("WE", 5, "There was an issue processing the webhook body", None))
            },
            Self::WebhookInvalidMerchantSecret => {
                AER::BadRequest(ApiError::new("WE", 6, "Merchant Secret set for webhook source verification is invalid", None))
            }
            Self::IntegrityCheckFailed {
                reason,
                field_names,
                connector_transaction_id
            } => AER::InternalServerError(ApiError::new(
                "IE",
                0,
                format!("{reason} as data mismatched for {field_names}"),
                Some(Extra {
                    connector_transaction_id: connector_transaction_id.to_owned(),
                    ..Default::default()
                })
            )),
            Self::PlatformAccountAuthNotSupported => {
                AER::BadRequest(ApiError::new("IR", 43, "API does not support platform operation", None))
            }
            Self::InvalidPlatformOperation => {
                AER::Unauthorized(ApiError::new("IR", 44, "Invalid platform account operation", None))
            }
            Self::TokenizationRecordNotFound{ id } => {
                AER::NotFound(ApiError::new("HE", 2, format!("Tokenization record not found for the given token_id '{id}' "), None))
            }
            Self::SubscriptionError { operation } => {
                AER::BadRequest(ApiError::new("CE", 9, format!("Subscription operation: {operation} failed with connector"), None))
            }
        }
    }
}

impl actix_web::ResponseError for ApiErrorResponse {
    fn status_code(&self) -> StatusCode {
        ErrorSwitch::<api_models::errors::types::ApiErrorResponse>::switch(self).status_code()
    }

    fn error_response(&self) -> actix_web::HttpResponse {
        ErrorSwitch::<api_models::errors::types::ApiErrorResponse>::switch(self).error_response()
    }
}

impl From<ApiErrorResponse> for router_data::ErrorResponse {
    fn from(error: ApiErrorResponse) -> Self {
        Self {
            code: error.error_code(),
            message: error.error_message(),
            reason: None,
            status_code: match error {
                ApiErrorResponse::ExternalConnectorError { status_code, .. } => status_code,
                _ => 500,
            },
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        }
    }
}


// File: crates/hyperswitch_interfaces/src/consts.rs
// Module: hyperswitch_interfaces

//! connector integration related const declarations

/// No error message string const
pub const NO_ERROR_MESSAGE: &str = "No error message";

/// No error code string const
pub const NO_ERROR_CODE: &str = "No error code";

/// Accepted format for request
pub const ACCEPT_HEADER: &str = "text/html,application/json";

/// User agent for request send from backend server
pub const USER_AGENT: &str = "Hyperswitch-Backend-Server";


// Function: is_overcapture_enabled
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models

pub fn is_overcapture_enabled(&self) -> Option<primitive_wrappers::OvercaptureEnabledBool>


// Implementation: impl PaymentAttempt
// File: crates/diesel_models/src/query/payment_attempt.rs
// Module: diesel_models
// Methods: 18 total (0 public)

impl PaymentAttempt


// Struct: EventListRequestInternal
// File: crates/api_models/src/webhook_events.rs
// Module: api_models
// Implementations: 1
// Traits: common_utils::events::ApiEventMetric

pub struct EventListRequestInternal


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

impl RefundSync for for DummyConnector


// Function: extract_merchant_details_url
// File: crates/router/src/types/api/connector_onboarding/paypal.rs
// Module: router

pub fn extract_merchant_details_url(self, paypal_base_url: &str) -> RouterResult<String>


// Function: validate
// File: crates/router_derive/src/macros/schema.rs
// Module: router_derive

pub fn validate(&self) -> Result<(), String>


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

impl Responder


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

// Public submodules:
pub mod transformers;


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

impl ConnectorCommon for for Cybersource


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

impl api::PaymentVoid for for Inespay


// Function: find_by_merchant_id_subscription_id
// File: crates/diesel_models/src/query/subscription.rs
// Module: diesel_models

pub fn find_by_merchant_id_subscription_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        id: String,
    ) -> StorageResult<Self>


// Implementation: impl api::MandateSetup for for Paysafe
// File: crates/hyperswitch_connectors/src/connectors/paysafe.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::MandateSetup for for Paysafe


// Implementation: impl api::PayoutCreate for for Stripe
// File: crates/hyperswitch_connectors/src/connectors/stripe.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PayoutCreate for for Stripe


// Struct: CoinbaseRefundRequest
// File: crates/hyperswitch_connectors/src/connectors/coinbase/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CoinbaseRefundRequest


// Struct: ConnectorParamsWithMoreUrls
// File: crates/hyperswitch_domain_models/src/connector_endpoints.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct ConnectorParamsWithMoreUrls


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

pub fn get_payment_method_create_request(
    payment_method_data: Option<&domain::PaymentMethodData>,
    payment_method: Option<storage_enums::PaymentMethod>,
    payment_method_type: Option<storage_enums::PaymentMethodType>,
    customer_id: &Option<id_type::CustomerId>,
    billing_name: Option<Secret<String>>,
    payment_method_billing_address: Option<&hyperswitch_domain_models::address::Address>,
) -> RouterResult<payment_methods::PaymentMethodCreate>


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

impl ConnectorValidation for for Trustpay


// Struct: BamboraCard
// File: crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BamboraCard


// Struct: SyncTransactionResponse
// File: crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SyncTransactionResponse


// Struct: Headers
// File: crates/api_models/src/proxy.rs
// Module: api_models
// Implementations: 1

pub struct Headers


// File: crates/router/src/db/callback_mapper.rs
// Module: router

use error_stack::report;
use hyperswitch_domain_models::callback_mapper as domain;
use router_env::{instrument, tracing};
use storage_impl::{DataModelExt, MockDb};

use super::Store;
use crate::{
    connection,
    core::errors::{self, CustomResult},
    types::storage,
};

#[async_trait::async_trait]
pub trait CallbackMapperInterface {
    async fn insert_call_back_mapper(
        &self,
        call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError>;

    async fn find_call_back_mapper_by_id(
        &self,
        id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError>;
}

#[async_trait::async_trait]
impl CallbackMapperInterface for Store {
    #[instrument(skip_all)]
    async fn insert_call_back_mapper(
        &self,
        call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        call_back_mapper
            .to_storage_model()
            .insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .map(domain::CallbackMapper::from_storage_model)
    }

    #[instrument(skip_all)]
    async fn find_call_back_mapper_by_id(
        &self,
        id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::CallbackMapper::find_by_id(&conn, id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .map(domain::CallbackMapper::from_storage_model)
    }
}

#[async_trait::async_trait]
impl CallbackMapperInterface for MockDb {
    #[instrument(skip_all)]
    async fn insert_call_back_mapper(
        &self,
        _call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        Err(errors::StorageError::MockDbError)?
    }

    #[instrument(skip_all)]
    async fn find_call_back_mapper_by_id(
        &self,
        _id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        Err(errors::StorageError::MockDbError)?
    }
}


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

impl api::Refund for for Coinbase


// Struct: CardholderAccount
// File: crates/hyperswitch_connectors/src/connectors/netcetera/netcetera_types.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardholderAccount


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

pub fn execute_card_tokenization(
    executor: tokenize::CardNetworkTokenizeExecutor<'_, domain::TokenizeCardRequest>,
    builder: tokenize::NetworkTokenizationBuilder<'_, tokenize::TokenizeWithCard>,
    req: &domain::TokenizeCardRequest,
) -> errors::RouterResult<api::CardNetworkTokenizeResponse>


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

pub struct ApiEventFilters


// Function: delete_user_role
// File: crates/router/src/routes/user_role.rs
// Module: router

pub fn delete_user_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<user_role_api::DeleteUserRoleRequest>,
) -> HttpResponse


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

impl Responder


// Struct: CheckoutLineItem
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutLineItem


// Implementation: impl ConnectorSpecifications for for Worldline
// File: crates/hyperswitch_connectors/src/connectors/worldline.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Worldline


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

pub struct Powertranz

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


// Struct: FacilitapayCredentials
// File: crates/hyperswitch_connectors/src/connectors/facilitapay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FacilitapayCredentials


// Function: files_create_core
// File: crates/router/src/core/files.rs
// Module: router

pub fn files_create_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    create_file_request: api::CreateFileRequest,
) -> RouterResponse<files::CreateFileResponse>


// Function: new
// File: crates/api_models/src/analytics/auth_events.rs
// Module: api_models

pub fn new(
        authentication_status: Option<AuthenticationStatus>,
        trans_status: Option<TransactionStatus>,
        authentication_type: Option<DecoupledAuthenticationType>,
        error_message: Option<String>,
        authentication_connector: Option<AuthenticationConnectors>,
        message_version: Option<String>,
        acs_reference_number: Option<String>,
        mcc: Option<String>,
        currency: Option<Currency>,
        merchant_country: Option<String>,
        billing_country: Option<String>,
        shipping_country: Option<String>,
        issuer_country: Option<String>,
        earliest_supported_version: Option<String>,
        latest_supported_version: Option<String>,
        whitelist_decision: Option<bool>,
        device_manufacturer: Option<String>,
        device_type: Option<String>,
        device_brand: Option<String>,
        device_os: Option<String>,
        device_display: Option<String>,
        browser_name: Option<String>,
        browser_version: Option<String>,
        issuer_id: Option<String>,
        scheme_name: Option<String>,
        exemption_requested: Option<bool>,
        exemption_accepted: Option<bool>,
        normalized_time_range: TimeRange,
    ) -> Self


// Function: delete_dispute_evidence
// File: crates/router/src/routes/disputes.rs
// Module: router

pub fn delete_dispute_evidence(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<dispute_models::DeleteEvidenceRequest>,
) -> HttpResponse


// Struct: HashedApiKey
// File: crates/diesel_models/src/api_keys.rs
// Module: diesel_models
// Implementations: 1

pub struct HashedApiKey


// File: crates/router_env/src/lib.rs
// Module: router_env

#![warn(missing_debug_implementations)]

//! Environment of payment router: logger, basic config, its environment awareness.

#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))]

/// Utilities to identify members of the current cargo workspace.
pub mod cargo_workspace;
pub mod env;
pub mod logger;
pub mod metrics;
/// `cargo` build instructions generation for obtaining information about the application
/// environment.
#[cfg(feature = "vergen")]
pub mod vergen;

// pub use literally;
#[doc(inline)]
pub use logger::*;
pub use opentelemetry;
pub use tracing;
#[cfg(feature = "actix_web")]
pub use tracing_actix_web;
pub use tracing_appender;

#[doc(inline)]
pub use self::env::*;


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

pub fn generic_list_roles_by_entity_type(
        conn: &PgPooledConn,
        payload: ListRolesByEntityPayload,
        is_lineage_data_required: bool,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
    ) -> StorageResult<Vec<Self>>


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

pub struct ActivePayments


// Struct: NexiCardDetails
// File: crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NexiCardDetails


// Implementation: impl FetchDisputes for for Worldpayvantiv
// File: crates/hyperswitch_connectors/src/connectors/worldpayvantiv.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl FetchDisputes for for Worldpayvantiv


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

impl api::PaymentCapture for for Blackhawknetwork