// File: crates/hyperswitch_connectors/src/connectors/facilitapay/responses.rs
// Module: hyperswitch_connectors
// Public structs: 16

use common_utils::{pii, types::StringMajorUnit};
use masking::Secret;
use serde::{Deserialize, Serialize};

use super::requests::DocumentType;

// Response body for POST /sign_in
#[derive(Debug, Deserialize, Serialize)]
pub struct FacilitapayAuthResponse {
    username: Secret<String>,
    name: Secret<String>,
    pub jwt: Secret<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SubjectKycStatus {
    // Customer is able to send/receive money through the platform. No action is needed on your side.
    Approved,

    // Customer is required to upload documents or uploaded documents have been rejected by KYC.
    Reproved,

    // Customer has uploaded KYC documents but awaiting analysis from the backoffice. No action is needed on your side.
    WaitingApproval,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct FacilitapaySubject {
    pub social_name: Secret<String>,
    pub document_type: DocumentType,
    pub document_number: Secret<String>,
    // In documentation, both CountryAlpha2 and String are used. We cannot rely on CountryAlpha2.
    pub fiscal_country: String,
    pub updated_at: Option<String>,
    pub status: SubjectKycStatus,
    #[serde(rename = "id")]
    pub customer_id: Secret<String>,
    pub birth_date: Option<time::Date>,
    pub email: Option<pii::Email>,
    pub phone_country_code: Option<Secret<String>>,
    pub phone_area_code: Option<Secret<String>>,
    pub phone_number: Option<Secret<String>>,
    pub address_street: Option<Secret<String>>,
    pub address_number: Option<Secret<String>>,
    pub address_complement: Option<Secret<String>>,
    pub address_city: Option<String>,
    pub address_state: Option<String>,
    pub address_postal_code: Option<Secret<String>>,
    pub address_country: Option<String>,
    pub address_neighborhood: Option<Secret<String>>,
    pub net_monthly_average_income: Option<StringMajorUnit>,
    pub clearance_level: Option<i32>,
    pub required_clearance_level: Option<i32>,
    pub inserted_at: Option<String>,
    pub references: Option<Vec<serde_json::Value>>,
    pub rfc_pf: Option<Secret<String>>, // 13-digit RFC, specific to Mexico users
    pub documents: Option<Vec<serde_json::Value>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct FacilitapayCustomerResponse {
    pub data: FacilitapaySubject,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PixInfo {
    #[serde(rename = "type")]
    pub key_type: String,
    pub key: Secret<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CreditCardResponseInfo {
    pub id: String,
    pub status: Option<String>,
    pub document_type: String,
    pub document_number: Secret<String>,
    pub birthdate: Option<String>,
    pub phone_country_code: Option<String>,
    pub phone_area_code: Option<String>,
    pub phone_number: Option<Secret<String>>,
    pub inserted_at: Option<String>,
}

// PaymentsResponse
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[derive(strum::Display)]
pub enum FacilitapayPaymentStatus {
    /// Transaction has been created but it is waiting for an incoming TED/Wire.
    /// This is the first recorded status in production mode.
    #[default]
    Pending,
    /// Incoming TED/Wire has been identified into Facilita´s bank account.
    /// When it is a deposit into an internal bank account and there is no
    /// conversion involved (BRL to BRL for instance), that is the final state.
    Identified,
    /// The conversion rate has been closed and therefore the exchanged value
    /// is defined - when it is a deposit into an internal bank account, that is the final state.
    Exchanged,
    /// The exchanged value has been wired to its destination (a real bank account) - that is also a final state.
    Wired,
    /// When for any reason the transaction cannot be concluded or need to be reversed, it is canceled.
    #[serde(rename = "canceled")]
    Cancelled,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FacilitapayPaymentsResponse {
    pub data: TransactionData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OwnerCompany {
    pub social_name: Option<Secret<String>>,
    #[serde(rename = "id")]
    pub company_id: Option<String>,
    pub document_type: DocumentType,
    pub document_number: Secret<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BankInfo {
    pub swift: Option<Secret<String>>,
    pub name: Option<String>,
    #[serde(rename = "id")]
    pub bank_id: Secret<String>,
    pub code: Option<Secret<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BankAccountDetail {
    pub routing_number: Option<Secret<String>>,
    pub pix_info: Option<PixInfo>,
    pub owner_name: Option<Secret<String>>,
    pub owner_document_type: Option<String>,
    pub owner_document_number: Option<Secret<String>>,
    pub owner_company: Option<OwnerCompany>,
    pub internal: Option<bool>,
    pub intermediary_bank_account: Option<Secret<String>>,
    pub intermediary_bank_account_id: Option<Secret<String>>,
    #[serde(rename = "id")]
    pub bank_account_id: Secret<String>,
    pub iban: Option<Secret<String>>,
    pub flow_type: Option<String>,
    pub currency: api_models::enums::Currency,
    pub branch_number: Option<Secret<String>>,
    pub branch_country: Option<String>,
    pub bank: Option<BankInfo>,
    pub account_type: Option<String>,
    pub account_number: Option<Secret<String>>,
    pub aba: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TransactionData {
    #[serde(rename = "id")]
    pub transaction_id: String,
    pub value: StringMajorUnit,
    pub status: FacilitapayPaymentStatus,
    pub currency: api_models::enums::Currency,
    pub exchange_currency: api_models::enums::Currency,

    // Details about the destination account (Required)
    pub to_bank_account: BankAccountDetail,

    // Details about the source - mutually exclusive
    pub from_credit_card: Option<CreditCardResponseInfo>,
    pub from_bank_account: Option<BankAccountDetail>, // Populated for PIX

    // Subject information (customer)
    pub subject_id: String,
    pub subject: Option<FacilitapaySubject>,
    pub subject_is_receiver: Option<bool>,

    // Source identification (potentially redundant with subject or card/bank info)
    pub source_name: Option<Secret<String>>,
    pub source_document_type: DocumentType,
    pub source_document_number: Secret<String>,

    // Timestamps and flags
    pub inserted_at: Option<String>,
    pub for_exchange: Option<bool>,
    pub exchange_under_request: Option<bool>,
    pub estimated_value_until_exchange: Option<bool>,
    pub cleared: Option<bool>,

    // PIX specific field
    pub dynamic_pix_code: Option<String>, // QR code string for PIX

    // Exchange details
    pub exchanged_value: Option<StringMajorUnit>,

    // Cancelation details
    #[serde(rename = "canceled_reason")]
    pub cancelled_reason: Option<String>,
    #[serde(rename = "canceled_at")]
    pub cancelled_at: Option<String>,

    // Other fields
    pub bank_transaction: Option<Secret<serde_json::Value>>,
    pub meta: Option<serde_json::Value>,
}

// Void response structures (for /refund endpoint)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoidBankTransaction {
    #[serde(rename = "id")]
    pub transaction_id: String,
    pub value: StringMajorUnit,
    pub currency: api_models::enums::Currency,
    pub iof_value: Option<StringMajorUnit>,
    pub fx_value: Option<StringMajorUnit>,
    pub exchange_rate: Option<StringMajorUnit>,
    pub exchange_currency: api_models::enums::Currency,
    pub exchanged_value: StringMajorUnit,
    pub exchange_approved: bool,
    pub wire_id: Option<String>,
    pub exchange_id: Option<String>,
    pub movement_date: String,
    pub source_name: Secret<String>,
    pub source_document_number: Secret<String>,
    pub source_document_type: String,
    pub source_id: String,
    pub source_type: String,
    pub source_description: String,
    pub source_bank: Option<String>,
    pub source_branch: Option<String>,
    pub source_account: Option<String>,
    pub source_bank_ispb: Option<String>,
    pub company_id: String,
    pub company_name: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoidData {
    #[serde(rename = "id")]
    pub void_id: String,
    pub reason: Option<String>,
    pub inserted_at: String,
    pub status: FacilitapayPaymentStatus,
    pub transaction_kind: String,
    pub bank_transaction: VoidBankTransaction,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FacilitapayVoidResponse {
    pub data: VoidData,
}

// Refund response uses the same TransactionData structure as payments
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FacilitapayRefundResponse {
    pub data: TransactionData,
}

// Webhook structures
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FacilitapayWebhookNotification {
    pub notification: FacilitapayWebhookBody,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct FacilitapayWebhookBody {
    #[serde(rename = "type")]
    pub event_type: FacilitapayWebhookEventType,
    pub secret: Secret<String>,
    #[serde(flatten)]
    pub data: FacilitapayWebhookData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum FacilitapayWebhookEventType {
    ExchangeCreated,
    Identified,
    PaymentApproved,
    PaymentExpired,
    PaymentFailed,
    PaymentRefunded,
    WireCreated,
    WireWaitingCorrection,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum FacilitapayWebhookErrorCode {
    /// Creditor account number invalid or missing (branch_number or account_number incorrect)
    Ac03,
    /// Creditor account type missing or invalid (account_type incorrect)
    Ac14,
    /// Value in Creditor Identifier is incorrect (owner_document_number incorrect)
    Ch11,
    /// Transaction type not supported/authorized on this account (account rejected the payment)
    Ag03,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum FacilitapayWebhookData {
    CardPayment {
        transaction_id: String,
        checkout_id: Option<String>,
    },
    Exchange {
        exchange_id: String,
        transaction_ids: Vec<String>,
    },
    Transaction {
        transaction_id: String,
    },
    Wire {
        wire_id: String,
        transaction_ids: Vec<String>,
    },
    WireError {
        error_code: FacilitapayWebhookErrorCode,
        error_description: String,
        bank_account_owner_id: String,
        bank_account_id: String,
        transaction_ids: Vec<String>,
        wire_id: String,
    },
}


// Struct: DataResponse
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DataResponse


// Struct: BamboraapacMandateResponse
// File: crates/hyperswitch_connectors/src/connectors/bamboraapac/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BamboraapacMandateResponse


// File: crates/external_services/src/http_client.rs
// Module: external_services
// Public functions: 1

use common_utils::{consts, errors::CustomResult, request::Request};
use hyperswitch_interfaces::{errors::HttpClientError, types::Proxy};
use request::{HeaderExt, RequestBuilderExt};
use router_env::{instrument, logger, tracing};
/// client module
pub mod client;
/// metrics module
pub mod metrics;
/// request module
pub mod request;
use std::{error::Error, time::Duration};

use common_utils::request::RequestContent;
pub use common_utils::request::{ContentType, Method, RequestBuilder};
use error_stack::ResultExt;

#[allow(missing_docs)]
#[instrument(skip_all)]
pub async fn send_request(
    client_proxy: &Proxy,
    request: Request,
    option_timeout_secs: Option<u64>,
) -> CustomResult<reqwest::Response, HttpClientError> {
    logger::info!(method=?request.method, headers=?request.headers, payload=?request.body, ?request);

    let url = url::Url::parse(&request.url).change_context(HttpClientError::UrlParsingFailed)?;

    let client = client::create_client(
        client_proxy,
        request.certificate,
        request.certificate_key,
        request.ca_certificate,
    )?;

    let headers = request.headers.construct_header_map()?;
    let metrics_tag = router_env::metric_attributes!((
        consts::METRICS_HOST_TAG_NAME,
        url.host_str().unwrap_or_default().to_owned()
    ));
    let request = {
        match request.method {
            Method::Get => client.get(url),
            Method::Post => {
                let client = client.post(url);
                match request.body {
                    Some(RequestContent::Json(payload)) => client.json(&payload),
                    Some(RequestContent::FormData(form)) => client.multipart(form),
                    Some(RequestContent::FormUrlEncoded(payload)) => client.form(&payload),
                    Some(RequestContent::Xml(payload)) => {
                        let body = quick_xml::se::to_string(&payload)
                            .change_context(HttpClientError::BodySerializationFailed)?;
                        client.body(body).header("Content-Type", "application/xml")
                    }
                    Some(RequestContent::RawBytes(payload)) => client.body(payload),
                    None => client,
                }
            }
            Method::Put => {
                let client = client.put(url);
                match request.body {
                    Some(RequestContent::Json(payload)) => client.json(&payload),
                    Some(RequestContent::FormData(form)) => client.multipart(form),
                    Some(RequestContent::FormUrlEncoded(payload)) => client.form(&payload),
                    Some(RequestContent::Xml(payload)) => {
                        let body = quick_xml::se::to_string(&payload)
                            .change_context(HttpClientError::BodySerializationFailed)?;
                        client.body(body).header("Content-Type", "application/xml")
                    }
                    Some(RequestContent::RawBytes(payload)) => client.body(payload),
                    None => client,
                }
            }
            Method::Patch => {
                let client = client.patch(url);
                match request.body {
                    Some(RequestContent::Json(payload)) => client.json(&payload),
                    Some(RequestContent::FormData(form)) => client.multipart(form),
                    Some(RequestContent::FormUrlEncoded(payload)) => client.form(&payload),
                    Some(RequestContent::Xml(payload)) => {
                        let body = quick_xml::se::to_string(&payload)
                            .change_context(HttpClientError::BodySerializationFailed)?;
                        client.body(body).header("Content-Type", "application/xml")
                    }
                    Some(RequestContent::RawBytes(payload)) => client.body(payload),
                    None => client,
                }
            }
            Method::Delete => client.delete(url),
        }
        .add_headers(headers)
        .timeout(Duration::from_secs(
            option_timeout_secs.unwrap_or(consts::REQUEST_TIME_OUT),
        ))
    };

    // We cannot clone the request type, because it has Form trait which is not cloneable. So we are cloning the request builder here.
    let cloned_send_request = request.try_clone().map(|cloned_request| async {
        cloned_request
            .send()
            .await
            .map_err(|error| match error {
                error if error.is_timeout() => {
                    metrics::REQUEST_BUILD_FAILURE.add(1, metrics_tag);
                    HttpClientError::RequestTimeoutReceived
                }
                error if is_connection_closed_before_message_could_complete(&error) => {
                    metrics::REQUEST_BUILD_FAILURE.add(1, metrics_tag);
                    HttpClientError::ConnectionClosedIncompleteMessage
                }
                _ => HttpClientError::RequestNotSent(error.to_string()),
            })
            .attach_printable("Unable to send request to connector")
    });

    let send_request = async {
        request
            .send()
            .await
            .map_err(|error| match error {
                error if error.is_timeout() => {
                    metrics::REQUEST_BUILD_FAILURE.add(1, metrics_tag);
                    HttpClientError::RequestTimeoutReceived
                }
                error if is_connection_closed_before_message_could_complete(&error) => {
                    metrics::REQUEST_BUILD_FAILURE.add(1, metrics_tag);
                    HttpClientError::ConnectionClosedIncompleteMessage
                }
                _ => HttpClientError::RequestNotSent(error.to_string()),
            })
            .attach_printable("Unable to send request to connector")
    };

    let response = common_utils::metrics::utils::record_operation_time(
        send_request,
        &metrics::EXTERNAL_REQUEST_TIME,
        metrics_tag,
    )
    .await;
    // Retry once if the response is connection closed.
    //
    // This is just due to the racy nature of networking.
    // hyper has a connection pool of idle connections, and it selected one to send your request.
    // Most of the time, hyper will receive the server’s FIN and drop the dead connection from its pool.
    // But occasionally, a connection will be selected from the pool
    // and written to at the same time the server is deciding to close the connection.
    // Since hyper already wrote some of the request,
    // it can’t really retry it automatically on a new connection, since the server may have acted already
    match response {
        Ok(response) => Ok(response),
        Err(error)
            if error.current_context() == &HttpClientError::ConnectionClosedIncompleteMessage =>
        {
            metrics::AUTO_RETRY_CONNECTION_CLOSED.add(1, metrics_tag);
            match cloned_send_request {
                Some(cloned_request) => {
                    logger::info!(
                        "Retrying request due to connection closed before message could complete"
                    );
                    common_utils::metrics::utils::record_operation_time(
                        cloned_request,
                        &metrics::EXTERNAL_REQUEST_TIME,
                        metrics_tag,
                    )
                    .await
                }
                None => {
                    logger::info!("Retrying request due to connection closed before message could complete failed as request is not cloneable");
                    Err(error)
                }
            }
        }
        err @ Err(_) => err,
    }
}

fn is_connection_closed_before_message_could_complete(error: &reqwest::Error) -> bool {
    let mut source = error.source();
    while let Some(err) = source {
        if let Some(hyper_err) = err.downcast_ref::<hyper::Error>() {
            if hyper_err.is_incomplete_message() {
                return true;
            }
        }
        source = err.source();
    }
    false
}


// Function: check_currency_country_filters
// File: crates/router/src/core/payout_link.rs
// Module: router

pub fn check_currency_country_filters(
    payout_method_filter: Option<&PaymentMethodFilters>,
    request_payout_method_type: &api_models::payment_methods::RequestPaymentMethodTypes,
    currency: common_enums::Currency,
    country: Option<&common_enums::CountryAlpha2>,
) -> errors::RouterResult<Option<bool>>


// Struct: TwoFactorAuthAttempts
// File: crates/api_models/src/user.rs
// Module: api_models
// Implementations: 0

pub struct TwoFactorAuthAttempts


// Function: filter_resources
// File: crates/storage_impl/src/kv_router_store.rs
// Module: storage_impl

pub fn filter_resources<D, R, M>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
        filter_resource_db_fut: R,
        filter_fn: impl Fn(&M) -> bool,
        FilterResourceParams


// File: crates/router/src/services/authentication.rs
// Module: router
// Public functions: 30
// Public structs: 44

use std::str::FromStr;

use actix_web::http::header::HeaderMap;
#[cfg(feature = "v2")]
use api_models::payment_methods::PaymentMethodIntentConfirm;
#[cfg(feature = "v1")]
use api_models::payment_methods::{PaymentMethodCreate, PaymentMethodListRequest};
use api_models::payments;
#[cfg(feature = "payouts")]
use api_models::payouts;
use async_trait::async_trait;
use common_enums::TokenPurpose;
use common_utils::{date_time, fp_utils, id_type};
#[cfg(feature = "v2")]
use diesel_models::ephemeral_key;
use error_stack::{report, ResultExt};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
#[cfg(feature = "v2")]
use masking::ExposeInterface;
use masking::PeekInterface;
use router_env::logger;
use serde::Serialize;

use self::blacklist::BlackList;
#[cfg(all(feature = "partial-auth", feature = "v1"))]
use self::detached::ExtractedPayload;
#[cfg(feature = "partial-auth")]
use self::detached::GetAuthType;
use super::authorization::{self, permissions::Permission};
#[cfg(feature = "olap")]
use super::jwt;
#[cfg(feature = "olap")]
use crate::configs::Settings;
#[cfg(feature = "olap")]
use crate::consts;
#[cfg(feature = "olap")]
use crate::core::errors::UserResult;
#[cfg(all(feature = "partial-auth", feature = "v1"))]
use crate::core::metrics;
use crate::{
    configs::settings,
    core::{
        api_keys,
        errors::{self, utils::StorageErrorExt, RouterResult},
    },
    headers,
    routes::app::SessionStateInfo,
    services::api,
    types::{domain, storage},
    utils::OptionExt,
};

pub mod blacklist;
pub mod cookies;
pub mod decision;

#[cfg(feature = "partial-auth")]
mod detached;

#[cfg(feature = "v1")]
#[derive(Clone, Debug)]
pub struct AuthenticationData {
    pub merchant_account: domain::MerchantAccount,
    pub platform_merchant_account: Option<domain::MerchantAccount>,
    pub key_store: domain::MerchantKeyStore,
    pub profile_id: Option<id_type::ProfileId>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug)]
pub struct AuthenticationData {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub profile: domain::Profile,
    pub platform_merchant_account: Option<domain::MerchantAccount>,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithoutProfile {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithMultipleProfiles {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub profile_id_list: Option<Vec<id_type::ProfileId>>,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithUser {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub user: storage::User,
    pub profile_id: id_type::ProfileId,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithOrg {
    pub organization_id: id_type::OrganizationId,
}

#[derive(Clone)]
pub struct UserFromTokenWithRoleInfo {
    pub user: UserFromToken,
    pub role_info: authorization::roles::RoleInfo,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(
    tag = "api_auth_type",
    content = "authentication_data",
    rename_all = "snake_case"
)]
pub enum AuthenticationType {
    ApiKey {
        merchant_id: id_type::MerchantId,
        key_id: id_type::ApiKeyId,
    },
    AdminApiKey,
    AdminApiAuthWithMerchantId {
        merchant_id: id_type::MerchantId,
    },
    OrganizationJwt {
        org_id: id_type::OrganizationId,
        user_id: String,
    },
    MerchantJwt {
        merchant_id: id_type::MerchantId,
        user_id: Option<String>,
    },
    MerchantJwtWithProfileId {
        merchant_id: id_type::MerchantId,
        profile_id: Option<id_type::ProfileId>,
        user_id: String,
    },
    UserJwt {
        user_id: String,
    },
    SinglePurposeJwt {
        user_id: String,
        purpose: TokenPurpose,
    },
    SinglePurposeOrLoginJwt {
        user_id: String,
        purpose: Option<TokenPurpose>,
        role_id: Option<String>,
    },
    MerchantId {
        merchant_id: id_type::MerchantId,
    },
    PublishableKey {
        merchant_id: id_type::MerchantId,
    },
    WebhookAuth {
        merchant_id: id_type::MerchantId,
    },
    InternalMerchantIdProfileId {
        merchant_id: id_type::MerchantId,
        profile_id: Option<id_type::ProfileId>,
    },
    NoAuth,
}

impl events::EventInfo for AuthenticationType {
    type Data = Self;
    fn data(&self) -> error_stack::Result<Self::Data, events::EventsError> {
        Ok(self.clone())
    }

    fn key(&self) -> String {
        "auth_info".to_string()
    }
}

impl AuthenticationType {
    pub fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        match self {
            Self::ApiKey {
                merchant_id,
                key_id: _,
            }
            | Self::AdminApiAuthWithMerchantId { merchant_id }
            | Self::MerchantId { merchant_id }
            | Self::PublishableKey { merchant_id }
            | Self::MerchantJwt {
                merchant_id,
                user_id: _,
            }
            | Self::MerchantJwtWithProfileId { merchant_id, .. }
            | Self::WebhookAuth { merchant_id }
            | Self::InternalMerchantIdProfileId { merchant_id, .. } => Some(merchant_id),
            Self::AdminApiKey
            | Self::OrganizationJwt { .. }
            | Self::UserJwt { .. }
            | Self::SinglePurposeJwt { .. }
            | Self::SinglePurposeOrLoginJwt { .. }
            | Self::NoAuth => None,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, serde::Deserialize, strum::Display)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ExternalServiceType {
    Hypersense,
}

#[cfg(feature = "olap")]
#[derive(Clone, Debug)]
pub struct UserFromSinglePurposeToken {
    pub user_id: String,
    pub origin: domain::Origin,
    pub path: Vec<TokenPurpose>,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SinglePurposeToken {
    pub user_id: String,
    pub purpose: TokenPurpose,
    pub origin: domain::Origin,
    pub path: Vec<TokenPurpose>,
    pub exp: u64,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
impl SinglePurposeToken {
    pub async fn new_token(
        user_id: String,
        purpose: TokenPurpose,
        origin: domain::Origin,
        settings: &Settings,
        path: Vec<TokenPurpose>,
        tenant_id: Option<id_type::TenantId>,
    ) -> UserResult<String> {
        let exp_duration =
            std::time::Duration::from_secs(consts::SINGLE_PURPOSE_TOKEN_TIME_IN_SECS);
        let exp = jwt::generate_exp(exp_duration)?.as_secs();
        let token_payload = Self {
            user_id,
            purpose,
            origin,
            exp,
            path,
            tenant_id,
        };
        jwt::generate_jwt(&token_payload, settings).await
    }
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AuthToken {
    pub user_id: String,
    pub merchant_id: id_type::MerchantId,
    pub role_id: String,
    pub exp: u64,
    pub org_id: id_type::OrganizationId,
    pub profile_id: id_type::ProfileId,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
impl AuthToken {
    pub async fn new_token(
        user_id: String,
        merchant_id: id_type::MerchantId,
        role_id: String,
        settings: &Settings,
        org_id: id_type::OrganizationId,
        profile_id: id_type::ProfileId,
        tenant_id: Option<id_type::TenantId>,
    ) -> UserResult<String> {
        let exp_duration = std::time::Duration::from_secs(consts::JWT_TOKEN_TIME_IN_SECS);
        let exp = jwt::generate_exp(exp_duration)?.as_secs();
        let token_payload = Self {
            user_id,
            merchant_id,
            role_id,
            exp,
            org_id,
            profile_id,
            tenant_id,
        };
        jwt::generate_jwt(&token_payload, settings).await
    }
}

#[derive(Clone)]
pub struct UserFromToken {
    pub user_id: String,
    pub merchant_id: id_type::MerchantId,
    pub role_id: String,
    pub org_id: id_type::OrganizationId,
    pub profile_id: id_type::ProfileId,
    pub tenant_id: Option<id_type::TenantId>,
}

pub struct UserIdFromAuth {
    pub user_id: String,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SinglePurposeOrLoginToken {
    pub user_id: String,
    pub role_id: Option<String>,
    pub purpose: Option<TokenPurpose>,
    pub exp: u64,
    pub tenant_id: Option<id_type::TenantId>,
}

pub trait AuthInfo {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId>;
}

impl AuthInfo for () {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        None
    }
}

#[cfg(feature = "v1")]
impl AuthInfo for AuthenticationData {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

#[cfg(feature = "v2")]
impl AuthInfo for AuthenticationData {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

impl AuthInfo for AuthenticationDataWithMultipleProfiles {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

#[async_trait]
pub trait AuthenticateAndFetch<T, A>
where
    A: SessionStateInfo,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(T, AuthenticationType)>;
}

#[derive(Debug, Default)]
pub struct ApiKeyAuth {
    pub is_connected_allowed: bool,
    pub is_platform_allowed: bool,
}

pub struct NoAuth;

#[cfg(feature = "partial-auth")]
impl GetAuthType for ApiKeyAuth {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::ApiKey
    }
}

//
// # Header Auth
//
// Header Auth is a feature that allows you to authenticate requests using custom headers. This is
// done by checking whether the request contains the specified headers.
// - `x-merchant-id` header is used to authenticate the merchant.
//
// ## Checksum
// - `x-auth-checksum` header is used to authenticate the request. The checksum is calculated using the
// above mentioned headers is generated by hashing the headers mentioned above concatenated with `:` and then hashed with the detached authentication key.
//
// When the [`partial-auth`] feature is disabled the implementation for [`AuthenticateAndFetch`]
// changes where the authentication is done by the [`I`] implementation.
//
pub struct HeaderAuth<I>(pub I);

#[async_trait]
impl<A> AuthenticateAndFetch<(), A> for NoAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        _request_headers: &HeaderMap,
        _state: &A,
    ) -> RouterResult<((), AuthenticationType)> {
        Ok(((), AuthenticationType::NoAuth))
    }
}

#[async_trait]
impl<A, T> AuthenticateAndFetch<Option<T>, A> for NoAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        _request_headers: &HeaderMap,
        _state: &A,
    ) -> RouterResult<(Option<T>, AuthenticationType)> {
        Ok((None, AuthenticationType::NoAuth))
    }
}

#[cfg(feature = "v2")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let profile_id = HeaderMapStruct::new(request_headers)
            .get_id_type_from_header::<id_type::ProfileId>(headers::X_PROFILE_ID)?;

        let api_key = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed
            .attach_printable("Failed to retrieve API key")?
            .ok_or(report!(errors::ApiErrorResponse::Unauthorized)) // If retrieve returned `None`
            .attach_printable("Merchant not authenticated")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        // Get connected merchant account if API call is done by Platform merchant account on behalf of connected merchant account
        let (merchant, platform_merchant_account) = if state.conf().platform.enabled {
            get_platform_merchant_account(state, request_headers, merchant).await?
        } else {
            (merchant, None)
        };

        if platform_merchant_account.is_some() && !self.is_platform_allowed {
            return Err(report!(
                errors::ApiErrorResponse::PlatformAccountAuthNotSupported
            ))
            .attach_printable("Platform not authorized to access the resource");
        }

        let key_store = if platform_merchant_account.is_some() {
            state
                .store()
                .get_merchant_key_store_by_merchant_id(
                    key_manager_state,
                    merchant.get_id(),
                    &state.store().get_master_key().to_vec().into(),
                )
                .await
                .change_context(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Failed to fetch merchant key store for the merchant id")?
        } else {
            key_store
        };

        let profile = state
            .store()
            .find_business_profile_by_profile_id(key_manager_state, &key_store, &profile_id)
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let auth = AuthenticationData {
            merchant_account: merchant,
            platform_merchant_account,
            key_store,
            profile,
        };
        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed
            .attach_printable("Failed to retrieve API key")?
            .ok_or(report!(errors::ApiErrorResponse::Unauthorized)) // If retrieve returned `None`
            .attach_printable("Merchant not authenticated")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let profile_id =
            get_header_value_by_key(headers::X_PROFILE_ID.to_string(), request_headers)?
                .map(id_type::ProfileId::from_str)
                .transpose()
                .change_context(errors::ValidationError::IncorrectValueProvided {
                    field_name: "X-Profile-Id",
                })
                .change_context(errors::ApiErrorResponse::Unauthorized)?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let (merchant, platform_merchant_account) = if state.conf().platform.enabled {
            get_platform_merchant_account(state, request_headers, merchant).await?
        } else {
            (merchant, None)
        };

        if platform_merchant_account.is_some() && !self.is_platform_allowed {
            return Err(report!(
                errors::ApiErrorResponse::PlatformAccountAuthNotSupported
            ))
            .attach_printable("Platform not authorized to access the resource");
        }

        let key_store = if platform_merchant_account.is_some() {
            state
                .store()
                .get_merchant_key_store_by_merchant_id(
                    key_manager_state,
                    merchant.get_id(),
                    &state.store().get_master_key().to_vec().into(),
                )
                .await
                .change_context(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Failed to fetch merchant key store for the merchant id")?
        } else {
            key_store
        };

        let auth = AuthenticationData {
            merchant_account: merchant,
            platform_merchant_account,
            key_store,
            profile_id,
        };
        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[derive(Debug)]
pub struct ApiKeyAuthWithMerchantIdFromRoute(pub id_type::MerchantId);

#[cfg(feature = "partial-auth")]
impl GetAuthType for ApiKeyAuthWithMerchantIdFromRoute {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::ApiKey
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuthWithMerchantIdFromRoute
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_auth = ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        };
        let (auth_data, auth_type) = api_auth
            .authenticate_and_fetch(request_headers, state)
            .await?;

        let merchant_id_from_route = self.0.clone();
        let merchant_id_from_api_key = auth_data.merchant_account.get_id();

        if merchant_id_from_route != *merchant_id_from_api_key {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)).attach_printable(
                "Merchant ID from route and Merchant ID from api-key in header do not match",
            );
        }

        Ok((auth_data, auth_type))
    }
}

#[derive(Debug, Default)]
pub struct PlatformOrgAdminAuth {
    pub is_admin_auth_allowed: bool,
    pub organization_id: Option<id_type::OrganizationId>,
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<Option<AuthenticationDataWithOrg>, A> for PlatformOrgAdminAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(Option<AuthenticationDataWithOrg>, AuthenticationType)> {
        // Step 1: Admin API Key and API Key Fallback (if allowed)
        if self.is_admin_auth_allowed {
            let admin_auth = AdminApiAuthWithApiKeyFallback {
                organization_id: self.organization_id.clone(),
            };
            match admin_auth
                .authenticate_and_fetch(request_headers, state)
                .await
            {
                Ok((auth, auth_type)) => {
                    return Ok((auth, auth_type));
                }
                Err(e) => {
                    logger::warn!("Admin API Auth failed: {:?}", e);
                }
            }
        }

        // Step 2: Try Platform Auth
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = state.conf().api_keys.get_inner().get_hash_key()?;
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant_account = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Merchant account not found")?;

        if !(state.conf().platform.enabled && merchant_account.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Platform authentication check failed"));
        }

        if let Some(ref organization_id) = self.organization_id {
            if organization_id != merchant_account.get_org_id() {
                return Err(report!(errors::ApiErrorResponse::Unauthorized))
                    .attach_printable("Organization ID does not match");
            }
        }

        Ok((
            Some(AuthenticationDataWithOrg {
                organization_id: merchant_account.get_org_id().clone(),
            }),
            AuthenticationType::ApiKey {
                merchant_id: merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for PlatformOrgAdminAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = state.conf().api_keys.get_inner().get_hash_key()?;
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant_account = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Merchant account not found")?;

        if !(state.conf().platform.enabled && merchant_account.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Platform authentication check failed"));
        }

        if let Some(ref organization_id) = self.organization_id {
            if organization_id != merchant_account.get_org_id() {
                return Err(report!(errors::ApiErrorResponse::Unauthorized))
                    .attach_printable("Organization ID does not match");
            }
        }

        let auth = AuthenticationData {
            merchant_account: merchant_account.clone(),
            platform_merchant_account: Some(merchant_account.clone()),
            key_store,
            profile_id: None,
        };

        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[derive(Debug)]
pub struct PlatformOrgAdminAuthWithMerchantIdFromRoute {
    pub merchant_id_from_route: id_type::MerchantId,
    pub is_admin_auth_allowed: bool,
}

#[cfg(feature = "v1")]
impl PlatformOrgAdminAuthWithMerchantIdFromRoute {
    async fn fetch_key_store_and_account<A: SessionStateInfo + Sync>(
        merchant_id: &id_type::MerchantId,
        state: &A,
    ) -> RouterResult<(domain::MerchantKeyStore, domain::MerchantAccount)> {
        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        Ok((key_store, merchant))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for PlatformOrgAdminAuthWithMerchantIdFromRoute
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let route_merchant_id = self.merchant_id_from_route.clone();

        // Step 1: Admin API Key and API Key Fallback (if allowed)
        if self.is_admin_auth_allowed {
            let admin_auth =
                AdminApiAuthWithApiKeyFallbackAndMerchantIdFromRoute(route_merchant_id.clone());

            match admin_auth
                .authenticate_and_fetch(request_headers, state)
                .await
            {
                Ok((auth_data, auth_type)) => return Ok((auth_data, auth_type)),
                Err(e) => {
                    logger::warn!("Admin API Auth failed: {:?}", e);
                }
            }
        }

        // Step 2: Platform authentication
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let (_, platform_merchant) =
            Self::fetch_key_store_and_account(&stored_api_key.merchant_id, state).await?;

        if !(state.conf().platform.enabled && platform_merchant.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("Platform authentication check failed");
        }

        let (route_key_store, route_merchant) =
            Self::fetch_key_store_and_account(&route_merchant_id, state).await?;

        if platform_merchant.get_org_id() != route_merchant.get_org_id() {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("Route merchant not under same org as platform merchant");
        }

        let auth = AuthenticationData {
            merchant_account: route_merchant,
            platform_merchant_account: Some(platform_merchant.clone()),
            key_store: route_key_store,
            profile_id: None,
        };

        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: platform_merchant.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(not(feature = "partial-auth"))]
#[async_trait]
impl<A, I> AuthenticateAndFetch<AuthenticationData, A> for HeaderAuth<I>
where
    A: SessionStateInfo + Send + Sync,
    I: AuthenticateAndFetch<AuthenticationData, A> + Sync + Send,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        self.0.authenticate_and_fetch(request_headers, state).await
    }
}

#[cfg(all(feature = "partial-auth", feature = "v1"))]
#[async_trait]
impl<A, I> AuthenticateAndFetch<AuthenticationData, A> for HeaderAuth<I>
where
    A: SessionStateInfo + Sync,
    I: AuthenticateAndFetch<AuthenticationData, A> + GetAuthType + Sync + Send,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let enable_partial_auth = state.conf().api_keys.get_inner().enable_partial_auth;

        // This is a early return if partial auth is disabled
        // Preventing the need to go through the header extraction process
        if !enable_partial_auth {
            return self.0.authenticate_and_fetch(request_headers, state).await;
        }

        let report_failure = || {
            metrics::PARTIAL_AUTH_FAILURE.add(1, &[]);
        };

        let profile_id = HeaderMapStruct::new(request_headers)
            .get_id_type_from_header_if_present::<id_type::ProfileId>(headers::X_PROFILE_ID)
            .change_context(errors::ValidationError::IncorrectValueProvided {
                field_name: "X-Profile-Id",
            })
            .change_context(errors::ApiErrorResponse::Unauthorized)?;

        let payload = ExtractedPayload::from_headers(request_headers)
            .and_then(|value| {
                let (algo, secret) = state.get_detached_auth()?;

                Ok(value
                    .verify_checksum(request_headers, algo, secret)
                    .then_some(value))
            })
            .map(|inner_payload| {
                inner_payload.and_then(|inner| {
                    (inner.payload_type == self.0.get_auth_type()).then_some(inner)
                })
            });

        match payload {
            Ok(Some(data)) => match data {
                ExtractedPayload {
                    payload_type: detached::PayloadType::ApiKey,
                    merchant_id: Some(merchant_id),
                    key_id: Some(key_id),
                } => {
                    let auth = construct_authentication_data(
                        state,
                        &merchant_id,
                        request_headers,
                        profile_id,
                    )
                    .await?;
                    Ok((
                        auth.clone(),
                        AuthenticationType::ApiKey {
                            merchant_id: auth.merchant_account.get_id().clone(),
                            key_id,
                        },
                    ))
                }
                ExtractedPayload {
                    payload_type: detached::PayloadType::PublishableKey,
                    merchant_id: Some(merchant_id),
                    key_id: None,
                } => {
                    let auth = construct_authentication_data(
                        state,
                        &merchant_id,
                        request_headers,
                        profile_id,
                    )
                    .await?;
                    Ok((
                        auth.clone(),
                        AuthenticationType::PublishableKey {
                            merchant_id: auth.merchant_account.get_id().clone(),
                        },
                    ))
                }
                _ => {
                    report_failure();
                    self.0.authenticate_and_fetch(request_headers, state).await
                }
            },
            Ok(None) => {
                report_failure();
                self.0.authenticate_and_fetch(request_headers, state).await
            }
            Err(error) => {
                logger::error!(%error, "Failed to extract payload from headers");
                report_failure();


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

pub struct CoinbaseWebhookDetails


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

impl api::PaymentAuthorize for for Breadpay


// File: crates/external_services/src/hashicorp_vault.rs
// Module: external_services

//! Interactions with the HashiCorp Vault

pub mod core;

pub mod implementers;


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

pub struct RefundResponse


// Struct: DisputePayload
// File: crates/hyperswitch_interfaces/src/disputes.rs
// Module: hyperswitch_interfaces
// Implementations: 0

pub struct DisputePayload


// Implementation: impl UserRole
// File: crates/diesel_models/src/query/user_role.rs
// Module: diesel_models
// Methods: 7 total (0 public)

impl UserRole


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

impl AddressUpdateInternal


// Implementation: impl PaymentDistributionAccumulator for for ErrorDistributionAccumulator
// File: crates/analytics/src/payments/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl PaymentDistributionAccumulator for for ErrorDistributionAccumulator


// Struct: GlobepayErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GlobepayErrorResponse


// Module Structure
// File: crates/router/src/core/payments.rs
// Module: router

// Public submodules:
pub mod access_token;
pub mod conditional_configs;
pub mod customers;
pub mod flows;
pub mod helpers;
pub mod operations;
pub mod retry;
pub mod routing;
pub mod session_operation;
pub mod tokenization;
pub mod transformers;
pub mod types;
pub mod vault_session;
pub mod payment_methods;

// Public exports:
pub use common_enums::enums::{CallConnectorAction, GatewaySystem};
pub use hyperswitch_domain_models::{
    mandates::MandateData,
    payment_address::PaymentAddress,
    payments::{self as domain_payments, HeaderPayload},
    router_data::{PaymentMethodToken, RouterData},
    router_request_types::CustomerDetails,
};
pub use session_operation::payments_session_core;
pub use self::operations::{
    PaymentApprove, PaymentCancel, PaymentCancelPostCapture, PaymentCapture, PaymentConfirm,
    PaymentCreate, PaymentIncrementalAuthorization, PaymentPostSessionTokens, PaymentReject,
    PaymentSession, PaymentSessionUpdate, PaymentStatus, PaymentUpdate, PaymentUpdateMetadata,
};


// Function: log_payment_intent
// File: crates/router/src/services/kafka.rs
// Module: router

pub fn log_payment_intent(
        &self,
        intent: &PaymentIntent,
        old_intent: Option<PaymentIntent>,
        tenant_id: TenantID,
        infra_values: Option<Value>,
    ) -> MQResult<()>


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

pub struct Stax

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


// Implementation: impl ConnectorCommon for for Nmi
// File: crates/hyperswitch_connectors/src/connectors/nmi.rs
// Module: hyperswitch_connectors
// Methods: 4 total (0 public)

impl ConnectorCommon for for Nmi


// File: crates/api_models/src/events/payment.rs
// Module: api_models

use common_utils::events::{ApiEventMetric, ApiEventsType};

#[cfg(feature = "v2")]
use super::{
    PaymentAttemptListRequest, PaymentAttemptListResponse, PaymentStartRedirectionRequest,
    PaymentsCreateIntentRequest, PaymentsGetIntentRequest, PaymentsIntentResponse, PaymentsRequest,
    RecoveryPaymentsCreate, RecoveryPaymentsResponse,
};
#[cfg(feature = "v2")]
use crate::payment_methods::{
    ListMethodsForPaymentMethodsRequest, PaymentMethodListResponseForSession,
};
use crate::{
    payment_methods::{
        self, ListCountriesCurrenciesRequest, ListCountriesCurrenciesResponse,
        PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest,
        PaymentMethodCollectLinkResponse, PaymentMethodMigrateResponse, PaymentMethodResponse,
        PaymentMethodUpdate,
    },
    payments::{
        self, PaymentListConstraints, PaymentListFilters, PaymentListFiltersV2,
        PaymentListResponse, PaymentsAggregateResponse, PaymentsSessionResponse,
        RedirectionResponse,
    },
};
#[cfg(feature = "v1")]
use crate::{
    payment_methods::{PaymentMethodListRequest, PaymentMethodListResponse},
    payments::{
        ExtendedCardInfoResponse, PaymentIdType, PaymentListFilterConstraints,
        PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelPostCaptureRequest,
        PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
        PaymentsDynamicTaxCalculationRequest, PaymentsDynamicTaxCalculationResponse,
        PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse,
        PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest,
        PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest,
        PaymentsPostSessionTokensResponse, PaymentsRejectRequest, PaymentsRetrieveRequest,
        PaymentsStartRequest, PaymentsUpdateMetadataRequest, PaymentsUpdateMetadataResponse,
    },
};

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsRetrieveRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        match self.resource_id {
            PaymentIdType::PaymentIntentId(ref id) => Some(ApiEventsType::Payment {
                payment_id: id.clone(),
            }),
            _ => None,
        }
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsStartRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCaptureRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.to_owned(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCompleteAuthorizeRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsDynamicTaxCalculationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsPostSessionTokensRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsUpdateMetadataRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsUpdateMetadataResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsPostSessionTokensResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsDynamicTaxCalculationResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCancelRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCancelPostCaptureRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsApproveRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsRejectRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        match self.payment_id {
            Some(PaymentIdType::PaymentIntentId(ref id)) => Some(ApiEventsType::Payment {
                payment_id: id.clone(),
            }),
            _ => None,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsCreateIntentRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::GiftCardBalanceCheckResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsGetIntentRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentAttemptListRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_intent_id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentAttemptListResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsIntentResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsCancelRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsCancelResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentMethodResponse {
    #[cfg(feature = "v1")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: self.payment_method,
            payment_method_type: self.payment_method_type,
        })
    }

    #[cfg(feature = "v2")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.id.clone(),
            payment_method_type: self.payment_method_type,
            payment_method_subtype: self.payment_method_subtype,
        })
    }
}

impl ApiEventMetric for PaymentMethodMigrateResponse {
    #[cfg(feature = "v1")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_response.payment_method_id.clone(),
            payment_method: self.payment_method_response.payment_method,
            payment_method_type: self.payment_method_response.payment_method_type,
        })
    }

    #[cfg(feature = "v2")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_response.id.clone(),
            payment_method_type: self.payment_method_response.payment_method_type,
            payment_method_subtype: self.payment_method_response.payment_method_subtype,
        })
    }
}

impl ApiEventMetric for PaymentMethodUpdate {}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::DefaultPaymentMethod {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: None,
            payment_method_type: None,
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payment_methods::PaymentMethodDeleteResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.id.clone(),
            payment_method_type: None,
            payment_method_subtype: None,
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::PaymentMethodDeleteResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: None,
            payment_method_type: None,
        })
    }
}

impl ApiEventMetric for payment_methods::CustomerPaymentMethodsListResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentMethodListRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodList {
            payment_id: self
                .client_secret
                .as_ref()
                .and_then(|cs| cs.rsplit_once("_secret_"))
                .map(|(pid, _)| pid.to_string()),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for ListMethodsForPaymentMethodsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodList {
            payment_id: self
                .client_secret
                .as_ref()
                .and_then(|cs| cs.rsplit_once("_secret_"))
                .map(|(pid, _)| pid.to_string()),
        })
    }
}

impl ApiEventMetric for ListCountriesCurrenciesRequest {}

impl ApiEventMetric for ListCountriesCurrenciesResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentMethodListResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::CustomerDefaultPaymentMethodResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.default_payment_method_id.clone().unwrap_or_default(),
            payment_method: Some(self.payment_method),
            payment_method_type: self.payment_method_type,
        })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        self.pm_collect_link_id
            .as_ref()
            .map(|id| ApiEventsType::PaymentMethodCollectLink {
                link_id: id.clone(),
            })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkRenderRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodCollectLink {
            link_id: self.pm_collect_link_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodCollectLink {
            link_id: self.pm_collect_link_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListFilterConstraints {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListFilters {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}
impl ApiEventMetric for PaymentListFiltersV2 {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListConstraints {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for RecoveryPaymentsCreate {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for RecoveryPaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListResponseV2 {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}
impl ApiEventMetric for PaymentsAggregateResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for RedirectionResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsIncrementalAuthorizationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsExternalAuthenticationResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsExternalAuthenticationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for ExtendedCardInfoResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsManualUpdateRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsManualUpdateResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentsSessionResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentStartRedirectionRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentMethodListResponseForPayments {
    // Payment id would be populated by the request
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}
#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentMethodListResponseForSession {}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsCaptureResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}


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

impl Helcim


// Struct: TesouroErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/tesouro/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TesouroErrorResponse


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

impl api::PaymentSync for for Barclaycard


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

pub struct Archipel3DS


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

pub struct MandateCard


// Function: api_key_retrieve
// File: crates/openapi/src/routes/api_keys.rs
// Module: openapi

pub fn api_key_retrieve()


// Struct: CardRange
// File: crates/hyperswitch_connectors/src/connectors/netcetera/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct CardRange


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

impl Responder


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

// Public submodules:
pub mod transformers;


// Module Structure
// File: crates/hyperswitch_domain_models/src/lib.rs
// Module: hyperswitch_domain_models

// Public submodules:
pub mod address;
pub mod api;
pub mod authentication;
pub mod behaviour;
pub mod bulk_tokenization;
pub mod business_profile;
pub mod callback_mapper;
pub mod card_testing_guard_data;
pub mod cards_info;
pub mod chat;
pub mod connector_endpoints;
pub mod consts;
pub mod customer;
pub mod disputes;
pub mod errors;
// ... and 27 more


// Function: internal_sync_refund_with_gateway
// File: crates/router/src/core/refunds_v2.rs
// Module: router

pub fn internal_sync_refund_with_gateway(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    refund: &diesel_refund::Refund,
    merchant_connector_details: common_types::domain::MerchantConnectorAuthDetails,
) -> errors::RouterResult<diesel_refund::Refund>


// Function: create_finish_redirection_url
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models

// Documentation: This is the url to which the customer will be redirected to, after completing the redirection flow

pub fn create_finish_redirection_url(
        &self,
        base_url: &str,
        publishable_key: &str,
    ) -> CustomResult<url::Url, errors::api_error_response::ApiErrorResponse>


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

impl Poll


// Struct: PollConfig
// File: crates/router/src/types.rs
// Module: router
// Implementations: 2
// Traits: Default

pub struct PollConfig


// File: crates/router/src/services/email.rs
// Module: router

pub mod types;


// Implementation: impl std::ops::Deref for for Handler
// File: crates/drainer/src/handler.rs
// Module: drainer
// Methods: 1 total (0 public)

impl std::ops::Deref for for Handler


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

impl ConnectorCommon for for Trustpay


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

pub struct MerchantRiskIndicator


// File: crates/scheduler/src/flow.rs
// Module: scheduler

#[derive(Copy, Clone, Debug, strum::Display, strum::EnumString)]
#[strum(serialize_all = "snake_case")]
pub enum SchedulerFlow {
    Producer,
    Consumer,
    Cleaner,
}


// Function: insert_role_in_blacklist
// File: crates/router/src/services/authentication/blacklist.rs
// Module: router

pub fn insert_role_in_blacklist(state: &SessionState, role_id: &str) -> UserResult<()>


// Function: rust_locker_migration
// File: crates/router/src/routes/locker_migration.rs
// Module: router

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


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

impl api::PaymentVoid for for Nexinets


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

pub struct Purchase


// File: crates/hyperswitch_domain_models/src/router_flow_types/unified_authentication_service.rs
// Module: hyperswitch_domain_models
// Public structs: 4

#[derive(Debug, Clone)]
pub struct PreAuthenticate;

#[derive(Debug, Clone)]
pub struct PostAuthenticate;

#[derive(Debug, Clone)]
pub struct AuthenticationConfirmation;

#[derive(Debug, Clone)]
pub struct Authenticate;


// Implementation: impl api::PaymentPostSessionTokens for for Paypal
// File: crates/hyperswitch_connectors/src/connectors/paypal.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentPostSessionTokens for for Paypal


// Struct: JpmorganValidationErrors
// File: crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct JpmorganValidationErrors


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

pub struct SuccessfulSmartRetries


// File: crates/analytics/src/core.rs
// Module: analytics
// Public functions: 1

use api_models::analytics::GetInfoResponse;

use crate::{types::AnalyticsDomain, utils};

pub async fn get_domain_info(
    domain: AnalyticsDomain,
) -> crate::errors::AnalyticsResult<GetInfoResponse> {
    let info = match domain {
        AnalyticsDomain::Payments => GetInfoResponse {
            metrics: utils::get_payment_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_payment_dimensions(),
        },
        AnalyticsDomain::PaymentIntents => GetInfoResponse {
            metrics: utils::get_payment_intent_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_payment_intent_dimensions(),
        },
        AnalyticsDomain::Refunds => GetInfoResponse {
            metrics: utils::get_refund_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_refund_dimensions(),
        },
        AnalyticsDomain::Frm => GetInfoResponse {
            metrics: utils::get_frm_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_frm_dimensions(),
        },
        AnalyticsDomain::SdkEvents => GetInfoResponse {
            metrics: utils::get_sdk_event_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_sdk_event_dimensions(),
        },
        AnalyticsDomain::AuthEvents => GetInfoResponse {
            metrics: utils::get_auth_event_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_auth_event_dimensions(),
        },
        AnalyticsDomain::ApiEvents => GetInfoResponse {
            metrics: utils::get_api_event_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_api_event_dimensions(),
        },
        AnalyticsDomain::Dispute => GetInfoResponse {
            metrics: utils::get_dispute_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_dispute_dimensions(),
        },
        AnalyticsDomain::Routing => GetInfoResponse {
            metrics: utils::get_payment_metrics_info(),
            download_dimensions: None,
            dimensions: utils::get_payment_dimensions(),
        },
    };
    Ok(info)
}


// Struct: FraudDetails
// File: crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FraudDetails


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

impl api::PaymentSync for for Dlocal


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

pub fn payments_manual_update(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<payment_types::PaymentsManualUpdateRequest>,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> impl Responder


// Struct: WorldpayPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WorldpayPaymentsResponse


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

impl api::RefundExecute for for Globalpay


// Struct: SiftAuthType
// File: crates/hyperswitch_connectors/src/connectors/sift/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SiftAuthType


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

pub struct PaymentsMetricsResponse<T>


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

pub fn set_stored_token_response(
        self,
        store_token_response: &'a StoreLockerResponse,
    ) -> NetworkTokenizationBuilder<'a, CardTokenStored>


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

impl ConnectorCommon for for Hyperwallet


// File: crates/hyperswitch_interfaces/src/api/payouts_v2.rs
// Module: hyperswitch_interfaces

//! Payouts V2 interface
use hyperswitch_domain_models::{
    router_data_v2::flow_common_types::PayoutFlowData,
    router_flow_types::payouts::{
        PoCancel, PoCreate, PoEligibility, PoFulfill, PoQuote, PoRecipient, PoRecipientAccount,
        PoSync,
    },
    router_request_types::PayoutsData,
    router_response_types::PayoutsResponseData,
};

use super::ConnectorCommon;
use crate::api::ConnectorIntegrationV2;

/// trait PayoutCancelV2
pub trait PayoutCancelV2:
    ConnectorIntegrationV2<PoCancel, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutCreateV2
pub trait PayoutCreateV2:
    ConnectorIntegrationV2<PoCreate, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutEligibilityV2
pub trait PayoutEligibilityV2:
    ConnectorIntegrationV2<PoEligibility, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutFulfillV2
pub trait PayoutFulfillV2:
    ConnectorIntegrationV2<PoFulfill, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutQuoteV2
pub trait PayoutQuoteV2:
    ConnectorIntegrationV2<PoQuote, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutRecipientV2
pub trait PayoutRecipientV2:
    ConnectorIntegrationV2<PoRecipient, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutRecipientAccountV2
pub trait PayoutRecipientAccountV2:
    ConnectorIntegrationV2<PoRecipientAccount, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

/// trait PayoutSyncV2
pub trait PayoutSyncV2:
    ConnectorIntegrationV2<PoSync, PayoutFlowData, PayoutsData, PayoutsResponseData>
{
}

#[cfg(feature = "payouts")]
/// trait Payouts
pub trait PayoutsV2:
    ConnectorCommon
    + PayoutCancelV2
    + PayoutCreateV2
    + PayoutEligibilityV2
    + PayoutFulfillV2
    + PayoutQuoteV2
    + PayoutRecipientV2
    + PayoutRecipientAccountV2
    + PayoutSyncV2
{
}

/// Empty trait for when payouts feature is disabled
#[cfg(not(feature = "payouts"))]
pub trait PayoutsV2 {}