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

pub fn get_connector_choice(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector: Option<String>,
    routing_algorithm: Option<serde_json::Value>,
    payout_data: &mut PayoutData,
    eligible_connectors: Option<Vec<api_enums::PayoutConnectors>>,
) -> RouterResult<api::ConnectorCallType>


// Function: reset_totp
// File: crates/router/src/core/user.rs
// Module: router

pub fn reset_totp(
    state: SessionState,
    user_token: auth::UserFromToken,
) -> UserResponse<user_api::BeginTotpResponse>


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

pub fn create_payout_retrieve(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector_data: &api::ConnectorData,
    payout_data: &mut PayoutData,
) -> RouterResult<()>


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

impl api::PaymentCapture for for Gpayments


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

impl api::PaymentAuthorize for for Payeezy


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

impl api::PaymentVoid for for Worldline


// Struct: EncryptionTransferRequest
// File: crates/common_utils/src/types/keymanager.rs
// Module: common_utils
// Implementations: 0

pub struct EncryptionTransferRequest


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

use common_enums::enums as common_enums;
use common_types::callback_mapper::CallbackMapperData;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CallbackMapper {
    pub id: String,
    pub callback_mapper_id_type: common_enums::CallbackMapperIdType,
    pub data: CallbackMapperData,
    pub created_at: time::PrimitiveDateTime,
    pub last_modified_at: time::PrimitiveDateTime,
}

impl CallbackMapper {
    pub fn new(
        id: String,
        callback_mapper_id_type: common_enums::CallbackMapperIdType,
        data: CallbackMapperData,
        created_at: time::PrimitiveDateTime,
        last_modified_at: time::PrimitiveDateTime,
    ) -> Self {
        Self {
            id,
            callback_mapper_id_type,
            data,
            created_at,
            last_modified_at,
        }
    }
}


pub fn get_webhook_object_from_body(
    body: &[u8],
) -> CustomResult<GetnetWebhookNotificationResponseBody, errors::ConnectorError> {
    let body_bytes = bytes::Bytes::copy_from_slice(body);
    let parsed_param: GetnetWebhookNotificationResponse =
        parse_url_encoded_to_struct(body_bytes)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
    let response_base64 = &parsed_param.response_base64.peek();
    let decoded_response = BASE64_ENGINE
        .decode(response_base64)
        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

    let getnet_webhook_notification_response: GetnetWebhookNotificationResponseBody =
        match serde_json::from_slice::<GetnetWebhookNotificationResponseBody>(&decoded_response) {
            Ok(response) => response,
            Err(_e) => {
                return Err(errors::ConnectorError::WebhookBodyDecodingFailed)?;
            }
        };

    Ok(getnet_webhook_notification_response)
}

pub fn get_webhook_response(
    body: &[u8],
) -> CustomResult<GetnetWebhookNotificationResponse, errors::ConnectorError> {
    let body_bytes = bytes::Bytes::copy_from_slice(body);
    let parsed_param: GetnetWebhookNotificationResponse =
        parse_url_encoded_to_struct(body_bytes)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
    Ok(parsed_param)
}

pub fn get_incoming_webhook_event(
    transaction_type: GetnetTransactionType,
    transaction_status: GetnetPaymentStatus,
) -> IncomingWebhookEvent {
    match transaction_type {
        GetnetTransactionType::Purchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentProcessing,
        },

        GetnetTransactionType::Authorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentAuthorizationSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentAuthorizationFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentProcessing,
        },

        GetnetTransactionType::CaptureAuthorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCaptureSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCaptureFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCaptureFailure,
        },

        GetnetTransactionType::RefundPurchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::RefundSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::RefundFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::RefundFailure,
        },

        GetnetTransactionType::RefundCapture => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::RefundSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::RefundFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::RefundFailure,
        },

        GetnetTransactionType::VoidAuthorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCancelled,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCancelFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCancelFailure,
        },

        GetnetTransactionType::VoidPurchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCancelled,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCancelFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCancelFailure,
        },
    }
}


// Struct: CardInfoAdd
// File: crates/router/src/core/cards_info.rs
// Module: router
// Implementations: 1
// Traits: State

pub struct CardInfoAdd


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

impl common_utils::events::ApiEventMetric for for RelayRequest


// Function: refund_retrieve_core_with_internal_reference_id
// File: crates/router/src/core/refunds.rs
// Module: router

pub fn refund_retrieve_core_with_internal_reference_id(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<common_utils::id_type::ProfileId>,
    refund_internal_request_id: String,
    force_sync: Option<bool>,
) -> RouterResult<diesel_refund::Refund>


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

pub struct PayoutEnabledPaymentMethodsInfo


// Struct: RefundResponse
// File: crates/api_models/src/refunds.rs
// Module: api_models
// Implementations: 2

pub struct RefundResponse


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

pub struct BraintreeRedirectionResponse


    Ok((status, error, payment_response_data))
}

fn handle_bank_redirects_error_response(
    response: ErrorResponseBankRedirect,
    status_code: u16,
    previous_attempt_status: enums::AttemptStatus,
) -> CustomResult<
    (
        enums::AttemptStatus,
        Option<ErrorResponse>,
        PaymentsResponseData,
    ),
    errors::ConnectorError,
> {
    let status = if matches!(response.payment_result_info.result_code, 1132014 | 1132005) {
        previous_attempt_status
    } else {
        enums::AttemptStatus::AuthorizationFailed
    };
    let error = Some(ErrorResponse {
        code: response.payment_result_info.result_code.to_string(),
        // message vary for the same code, so relying on code alone as it is unique
        message: response.payment_result_info.result_code.to_string(),
        reason: response.payment_result_info.additional_info,
        status_code,
        attempt_status: Some(status),
        connector_transaction_id: None,
        network_advice_code: None,
        network_decline_code: None,
        network_error_message: None,
        connector_metadata: None,
    });
    let payment_response_data = PaymentsResponseData::TransactionResponse {
        resource_id: ResponseId::NoResponseId,
        redirection_data: Box::new(None),
        mandate_reference: Box::new(None),
        connector_metadata: None,
        network_txn_id: None,
        connector_response_reference_id: None,
        incremental_authorization_allowed: None,
        charges: None,
    };
    Ok((status, error, payment_response_data))
}

fn handle_bank_redirects_sync_response(
    response: SyncResponseBankRedirect,
    status_code: u16,
) -> CustomResult<
    (
        enums::AttemptStatus,
        Option<ErrorResponse>,
        PaymentsResponseData,
    ),
    errors::ConnectorError,
> {
    let status = enums::AttemptStatus::from(response.payment_information.status);
    let error = if utils::is_payment_failure(status) {
        let reason_info = response
            .payment_information
            .status_reason_information
            .unwrap_or_default();
        Some(ErrorResponse {
            code: reason_info
                .reason
                .code
                .clone()
                .unwrap_or(consts::NO_ERROR_CODE.to_string()),
            // message vary for the same code, so relying on code alone as it is unique
            message: reason_info
                .reason
                .code
                .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
            reason: reason_info.reason.reject_reason,
            status_code,
            attempt_status: None,
            connector_transaction_id: Some(
                response
                    .payment_information
                    .references
                    .payment_request_id
                    .clone(),
            ),
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let payment_response_data = PaymentsResponseData::TransactionResponse {
        resource_id: ResponseId::ConnectorTransactionId(
            response
                .payment_information
                .references
                .payment_request_id
                .clone(),
        ),
        redirection_data: Box::new(None),
        mandate_reference: Box::new(None),
        connector_metadata: None,
        network_txn_id: None,
        connector_response_reference_id: None,
        incremental_authorization_allowed: None,
        charges: None,
    };
    Ok((status, error, payment_response_data))
}

pub fn handle_webhook_response(
    payment_information: WebhookPaymentInformation,
    status_code: u16,
) -> CustomResult<
    (
        enums::AttemptStatus,
        Option<ErrorResponse>,
        PaymentsResponseData,
    ),
    errors::ConnectorError,
> {
    let status = enums::AttemptStatus::try_from(payment_information.status)?;
    let error = if utils::is_payment_failure(status) {
        let reason_info = payment_information
            .status_reason_information
            .unwrap_or_default();
        Some(ErrorResponse {
            code: reason_info
                .reason
                .code
                .clone()
                .unwrap_or(consts::NO_ERROR_CODE.to_string()),
            // message vary for the same code, so relying on code alone as it is unique
            message: reason_info
                .reason
                .code
                .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
            reason: reason_info.reason.reject_reason,
            status_code,
            attempt_status: None,
            connector_transaction_id: payment_information.references.payment_request_id.clone(),
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let payment_response_data = PaymentsResponseData::TransactionResponse {
        resource_id: ResponseId::NoResponseId,
        redirection_data: Box::new(None),
        mandate_reference: Box::new(None),
        connector_metadata: None,
        network_txn_id: None,
        connector_response_reference_id: None,
        incremental_authorization_allowed: None,
        charges: None,
    };
    Ok((status, error, payment_response_data))
}

pub fn get_trustpay_response(
    response: TrustpayPaymentsResponse,
    status_code: u16,
    previous_attempt_status: enums::AttemptStatus,
) -> CustomResult<
    (
        enums::AttemptStatus,
        Option<ErrorResponse>,
        PaymentsResponseData,
    ),
    errors::ConnectorError,
> {
    match response {
        TrustpayPaymentsResponse::CardsPayments(response) => {
            handle_cards_response(*response, status_code)
        }
        TrustpayPaymentsResponse::BankRedirectPayments(response) => {
            handle_bank_redirects_response(*response)
        }
        TrustpayPaymentsResponse::BankRedirectSync(response) => {
            handle_bank_redirects_sync_response(*response, status_code)
        }
        TrustpayPaymentsResponse::BankRedirectError(response) => {
            handle_bank_redirects_error_response(*response, status_code, previous_attempt_status)
        }
        TrustpayPaymentsResponse::WebhookResponse(response) => {
            handle_webhook_response(*response, status_code)
        }
    }
}

#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct TrustpayAuthUpdateRequest {
    pub grant_type: String,
}

impl TryFrom<&RefreshTokenRouterData> for TrustpayAuthUpdateRequest {
    type Error = Error;
    fn try_from(_item: &RefreshTokenRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            grant_type: "client_credentials".to_string(),
        })
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct ResultInfo {
    pub result_code: i64,
    pub additional_info: Option<String>,
    pub correlation_id: Option<String>,
}

#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct TrustpayAuthUpdateResponse {
    pub access_token: Option<Secret<String>>,
    pub token_type: Option<String>,
    pub expires_in: Option<i64>,
    #[serde(rename = "ResultInfo")]
    pub result_info: ResultInfo,
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct TrustpayAccessTokenErrorResponse {
    pub result_info: ResultInfo,
}

impl<F, T> TryFrom<ResponseRouterData<F, TrustpayAuthUpdateResponse, T, AccessToken>>
    for RouterData<F, T, AccessToken>
{
    type Error = Error;
    fn try_from(
        item: ResponseRouterData<F, TrustpayAuthUpdateResponse, T, AccessToken>,
    ) -> Result<Self, Self::Error> {
        match (item.response.access_token, item.response.expires_in) {
            (Some(access_token), Some(expires_in)) => Ok(Self {
                response: Ok(AccessToken {
                    token: access_token,
                    expires: expires_in,
                }),
                ..item.data
            }),
            _ => Ok(Self {
                response: Err(ErrorResponse {
                    code: item.response.result_info.result_code.to_string(),
                    // message vary for the same code, so relying on code alone as it is unique
                    message: item.response.result_info.result_code.to_string(),
                    reason: item.response.result_info.additional_info,
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayCreateIntentRequest {
    pub amount: StringMajorUnit,
    pub currency: String,
    // If true, Apple Pay will be initialized
    pub init_apple_pay: Option<bool>,
    // If true, Google pay will be initialized
    pub init_google_pay: Option<bool>,
    pub reference: String,
}

impl TryFrom<&TrustpayRouterData<&PaymentsPreProcessingRouterData>>
    for TrustpayCreateIntentRequest
{
    type Error = Error;
    fn try_from(
        item: &TrustpayRouterData<&PaymentsPreProcessingRouterData>,
    ) -> Result<Self, Self::Error> {
        let is_apple_pay = item
            .router_data
            .request
            .payment_method_type
            .as_ref()
            .map(|pmt| matches!(pmt, enums::PaymentMethodType::ApplePay));

        let is_google_pay = item
            .router_data
            .request
            .payment_method_type
            .as_ref()
            .map(|pmt| matches!(pmt, enums::PaymentMethodType::GooglePay));

        let currency = item.router_data.request.get_currency()?;
        let amount = item.amount.to_owned();

        Ok(Self {
            amount,
            currency: currency.to_string(),
            init_apple_pay: is_apple_pay,
            init_google_pay: is_google_pay,
            reference: item.router_data.connector_request_reference_id.clone(),
        })
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayCreateIntentResponse {
    // TrustPay's authorization secrets used by client
    pub secrets: SdkSecretInfo,
    // 	Data object to be used for Apple Pay or Google Pay
    #[serde(flatten)]
    pub init_result_data: InitResultData,
    // Unique operation/transaction identifier
    pub instance_id: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum InitResultData {
    AppleInitResultData(TrustpayApplePayResponse),
    GoogleInitResultData(TrustpayGooglePayResponse),
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GooglePayTransactionInfo {
    pub country_code: api_models::enums::CountryAlpha2,
    pub currency_code: api_models::enums::Currency,
    pub total_price_status: String,
    pub total_price: StringMajorUnit,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GooglePayMerchantInfo {
    pub merchant_name: Secret<String>,
    pub merchant_id: Secret<String>,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GooglePayAllowedPaymentMethods {
    #[serde(rename = "type")]
    pub payment_method_type: String,
    pub parameters: GpayAllowedMethodsParameters,
    pub tokenization_specification: GpayTokenizationSpecification,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GpayTokenParameters {
    pub gateway: String,
    pub gateway_merchant_id: Secret<String>,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GpayTokenizationSpecification {
    #[serde(rename = "type")]
    pub token_specification_type: String,
    pub parameters: GpayTokenParameters,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GpayAllowedMethodsParameters {
    pub allowed_auth_methods: Vec<String>,
    pub allowed_card_networks: Vec<String>,
    pub assurance_details_required: Option<bool>,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayGooglePayResponse {
    pub merchant_info: GooglePayMerchantInfo,
    pub allowed_payment_methods: Vec<GooglePayAllowedPaymentMethods>,
    pub transaction_info: GooglePayTransactionInfo,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SdkSecretInfo {
    pub display: Secret<String>,
    pub payment: Secret<String>,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayApplePayResponse {
    pub country_code: api_models::enums::CountryAlpha2,
    pub currency_code: api_models::enums::Currency,
    pub supported_networks: Vec<String>,
    pub merchant_capabilities: Vec<String>,
    pub total: ApplePayTotalInfo,
}

#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ApplePayTotalInfo {
    pub label: String,
    pub amount: StringMajorUnit,
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            TrustpayCreateIntentResponse,
            PaymentsPreProcessingData,
            PaymentsResponseData,
        >,
    > for RouterData<F, PaymentsPreProcessingData, PaymentsResponseData>
{
    type Error = Error;
    fn try_from(
        item: ResponseRouterData<
            F,
            TrustpayCreateIntentResponse,
            PaymentsPreProcessingData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let create_intent_response = item.response.init_result_data.to_owned();
        let secrets = item.response.secrets.to_owned();
        let instance_id = item.response.instance_id.to_owned();
        let pmt = PaymentsPreProcessingData::get_payment_method_type(&item.data.request)?;

        match (pmt, create_intent_response) {
            (
                enums::PaymentMethodType::ApplePay,
                InitResultData::AppleInitResultData(apple_pay_response),
            ) => get_apple_pay_session(instance_id, &secrets, apple_pay_response, item),
            (
                enums::PaymentMethodType::GooglePay,
                InitResultData::GoogleInitResultData(google_pay_response),
            ) => get_google_pay_session(instance_id, &secrets, google_pay_response, item),
            _ => Err(report!(errors::ConnectorError::InvalidWallet)),
        }
    }
}

pub(crate) fn get_apple_pay_session<F, T>(
    instance_id: String,
    secrets: &SdkSecretInfo,
    apple_pay_init_result: TrustpayApplePayResponse,
    item: ResponseRouterData<F, TrustpayCreateIntentResponse, T, PaymentsResponseData>,
) -> Result<RouterData<F, T, PaymentsResponseData>, error_stack::Report<errors::ConnectorError>> {
    Ok(RouterData {
        response: Ok(PaymentsResponseData::PreProcessingResponse {
            connector_metadata: None,
            pre_processing_id: PreprocessingResponseId::ConnectorTransactionId(instance_id),
            session_token: Some(SessionToken::ApplePay(Box::new(
                api_models::payments::ApplepaySessionTokenResponse {
                    session_token_data: Some(
                        api_models::payments::ApplePaySessionResponse::ThirdPartySdk(
                            api_models::payments::ThirdPartySdkSessionResponse {
                                secrets: secrets.to_owned().into(),
                            },
                        ),
                    ),
                    payment_request_data: Some(api_models::payments::ApplePayPaymentRequest {
                        country_code: apple_pay_init_result.country_code,
                        currency_code: apple_pay_init_result.currency_code,
                        supported_networks: Some(apple_pay_init_result.supported_networks.clone()),
                        merchant_capabilities: Some(
                            apple_pay_init_result.merchant_capabilities.clone(),
                        ),
                        total: apple_pay_init_result.total.into(),
                        merchant_identifier: None,
                        required_billing_contact_fields: None,
                        required_shipping_contact_fields: None,
                        recurring_payment_request: None,
                    }),
                    connector: "trustpay".to_string(),
                    delayed_session_token: true,
                    sdk_next_action: {
                        api_models::payments::SdkNextAction {
                            next_action: api_models::payments::NextActionCall::Sync,
                        }
                    },
                    connector_reference_id: None,
                    connector_sdk_public_key: None,
                    connector_merchant_id: None,
                },
            ))),
            connector_response_reference_id: None,
        }),
        // We don't get status from TrustPay but status should be AuthenticationPending by default for session response
        status: enums::AttemptStatus::AuthenticationPending,
        ..item.data
    })
}

pub(crate) fn get_google_pay_session<F, T>(
    instance_id: String,
    secrets: &SdkSecretInfo,
    google_pay_init_result: TrustpayGooglePayResponse,
    item: ResponseRouterData<F, TrustpayCreateIntentResponse, T, PaymentsResponseData>,
) -> Result<RouterData<F, T, PaymentsResponseData>, error_stack::Report<errors::ConnectorError>> {
    Ok(RouterData {
        response: Ok(PaymentsResponseData::PreProcessingResponse {
            connector_metadata: None,
            pre_processing_id: PreprocessingResponseId::ConnectorTransactionId(instance_id),
            session_token: Some(SessionToken::GooglePay(Box::new(
                api_models::payments::GpaySessionTokenResponse::GooglePaySession(
                    api_models::payments::GooglePaySessionResponse {
                        connector: "trustpay".to_string(),
                        delayed_session_token: true,
                        sdk_next_action: {
                            api_models::payments::SdkNextAction {
                                next_action: api_models::payments::NextActionCall::Sync,
                            }
                        },
                        merchant_info: google_pay_init_result.merchant_info.into(),
                        allowed_payment_methods: google_pay_init_result
                            .allowed_payment_methods
                            .into_iter()
                            .map(Into::into)
                            .collect(),
                        transaction_info: google_pay_init_result.transaction_info.into(),
                        secrets: Some((*secrets).clone().into()),
                        shipping_address_required: false,
                        email_required: false,
                        shipping_address_parameters:
                            api_models::payments::GpayShippingAddressParameters {
                                phone_number_required: false,
                            },
                    },
                ),
            ))),
            connector_response_reference_id: None,
        }),
        // We don't get status from TrustPay but status should be AuthenticationPending by default for session response
        status: enums::AttemptStatus::AuthenticationPending,
        ..item.data
    })
}

impl From<GooglePayTransactionInfo> for api_models::payments::GpayTransactionInfo {
    fn from(value: GooglePayTransactionInfo) -> Self {
        Self {
            country_code: value.country_code,
            currency_code: value.currency_code,
            total_price_status: value.total_price_status,
            total_price: value.total_price,
        }
    }
}

impl From<GooglePayMerchantInfo> for api_models::payments::GpayMerchantInfo {
    fn from(value: GooglePayMerchantInfo) -> Self {
        Self {
            merchant_id: Some(value.merchant_id.expose()),
            merchant_name: value.merchant_name.expose(),
        }
    }
}

impl From<GooglePayAllowedPaymentMethods> for api_models::payments::GpayAllowedPaymentMethods {
    fn from(value: GooglePayAllowedPaymentMethods) -> Self {
        Self {
            payment_method_type: value.payment_method_type,
            parameters: value.parameters.into(),
            tokenization_specification: value.tokenization_specification.into(),
        }
    }
}

impl From<GpayAllowedMethodsParameters> for api_models::payments::GpayAllowedMethodsParameters {
    fn from(value: GpayAllowedMethodsParameters) -> Self {
        Self {
            allowed_auth_methods: value.allowed_auth_methods,
            allowed_card_networks: value.allowed_card_networks,
            billing_address_required: None,
            billing_address_parameters: None,
            assurance_details_required: value.assurance_details_required,
        }
    }
}

impl From<GpayTokenizationSpecification> for api_models::payments::GpayTokenizationSpecification {
    fn from(value: GpayTokenizationSpecification) -> Self {
        Self {
            token_specification_type: value.token_specification_type,
            parameters: value.parameters.into(),
        }
    }
}

impl From<GpayTokenParameters> for api_models::payments::GpayTokenParameters {
    fn from(value: GpayTokenParameters) -> Self {
        Self {
            gateway: Some(value.gateway),
            gateway_merchant_id: Some(value.gateway_merchant_id.expose()),
            stripe_version: None,
            stripe_publishable_key: None,
            public_key: None,
            protocol_version: None,
        }
    }
}

impl From<SdkSecretInfo> for api_models::payments::SecretInfoToInitiateSdk {
    fn from(value: SdkSecretInfo) -> Self {
        Self {
            display: value.display,
            payment: value.payment,
        }
    }
}

impl From<ApplePayTotalInfo> for api_models::payments::AmountInfo {
    fn from(value: ApplePayTotalInfo) -> Self {
        Self {
            label: value.label,
            amount: value.amount,
            total_type: None,
        }
    }
}

#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayRefundRequestCards {
    instance_id: String,
    amount: StringMajorUnit,
    currency: String,
    reference: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayRefundRequestBankRedirect {
    pub merchant_identification: MerchantIdentification,
    pub payment_information: BankPaymentInformation,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum TrustpayRefundRequest {
    CardsRefund(Box<TrustpayRefundRequestCards>),
    BankRedirectRefund(Box<TrustpayRefundRequestBankRedirect>),
}

impl<F> TryFrom<&TrustpayRouterData<&RefundsRouterData<F>>> for TrustpayRefundRequest {
    type Error = Error;
    fn try_from(item: &TrustpayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let amount = item.amount.to_owned();
        match item.router_data.payment_method {
            enums::PaymentMethod::BankRedirect => {
                let auth = TrustpayAuthType::try_from(&item.router_data.connector_auth_type)
                    .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
                Ok(Self::BankRedirectRefund(Box::new(
                    TrustpayRefundRequestBankRedirect {
                        merchant_identification: MerchantIdentification {
                            project_id: auth.project_id,
                        },
                        payment_information: BankPaymentInformation {
                            amount: Amount {
                                amount,
                                currency: item.router_data.request.currency.to_string(),
                            },
                            references: References {
                                merchant_reference: item.router_data.request.refund_id.clone(),
                            },
                            debtor: None,
                        },
                    },
                )))
            }
            _ => Ok(Self::CardsRefund(Box::new(TrustpayRefundRequestCards {
                instance_id: item.router_data.request.connector_transaction_id.clone(),
                amount,
                currency: item.router_data.request.currency.to_string(),
                reference: item.router_data.request.refund_id.clone(),
            }))),
        }
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CardsRefundResponse {
    pub status: i64,
    pub description: Option<String>,
    pub instance_id: String,
    pub payment_status: String,
    pub payment_description: Option<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct BankRedirectRefundResponse {
    pub payment_request_id: i64,
    pub result_info: ResultInfo,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RefundResponse {
    CardsRefund(Box<CardsRefundResponse>),
    WebhookRefund(Box<WebhookPaymentInformation>),
    BankRedirectRefund(Box<BankRedirectRefundResponse>),
    BankRedirectRefundSyncResponse(Box<SyncResponseBankRedirect>),
    BankRedirectError(Box<ErrorResponseBankRedirect>),
}

fn handle_cards_refund_response(
    response: CardsRefundResponse,
    status_code: u16,
) -> CustomResult<(Option<ErrorResponse>, RefundsResponseData), errors::ConnectorError> {
    let (refund_status, msg) = get_refund_status(&response.payment_status)?;
    let error = if msg.is_some() {
        Some(ErrorResponse {
            code: response.payment_status,
            message: msg
                .clone()
                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
            reason: msg,
            status_code,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let refund_response_data = RefundsResponseData {
        connector_refund_id: response.instance_id,
        refund_status,
    };
    Ok((error, refund_response_data))
}

fn handle_webhooks_refund_response(
    response: WebhookPaymentInformation,
    status_code: u16,
) -> CustomResult<(Option<ErrorResponse>, RefundsResponseData), errors::ConnectorError> {
    let refund_status = enums::RefundStatus::try_from(response.status)?;
    let error = if utils::is_refund_failure(refund_status) {
        let reason_info = response.status_reason_information.unwrap_or_default();
        Some(ErrorResponse {
            code: reason_info
                .reason
                .code
                .clone()
                .unwrap_or(consts::NO_ERROR_CODE.to_string()),
            // message vary for the same code, so relying on code alone as it is unique
            message: reason_info
                .reason
                .code
                .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
            reason: reason_info.reason.reject_reason,
            status_code,
            attempt_status: None,
            connector_transaction_id: response.references.payment_request_id.clone(),
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let refund_response_data = RefundsResponseData {
        connector_refund_id: response
            .references
            .payment_request_id
            .ok_or(errors::ConnectorError::MissingConnectorRefundID)?,
        refund_status,
    };
    Ok((error, refund_response_data))
}

fn handle_bank_redirects_refund_response(
    response: BankRedirectRefundResponse,
    status_code: u16,
) -> (Option<ErrorResponse>, RefundsResponseData) {
    let (refund_status, msg) = get_refund_status_from_result_info(response.result_info.result_code);
    let error = if msg.is_some() {
        Some(ErrorResponse {
            code: response.result_info.result_code.to_string(),
            // message vary for the same code, so relying on code alone as it is unique
            message: response.result_info.result_code.to_string(),
            reason: msg.map(|message| message.to_string()),
            status_code,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let refund_response_data = RefundsResponseData {
        connector_refund_id: response.payment_request_id.to_string(),
        refund_status,
    };
    (error, refund_response_data)
}

fn handle_bank_redirects_refund_sync_response(
    response: SyncResponseBankRedirect,
    status_code: u16,
) -> (Option<ErrorResponse>, RefundsResponseData) {
    let refund_status = enums::RefundStatus::from(response.payment_information.status);
    let error = if utils::is_refund_failure(refund_status) {
        let reason_info = response
            .payment_information
            .status_reason_information
            .unwrap_or_default();
        Some(ErrorResponse {
            code: reason_info
                .reason
                .code
                .clone()
                .unwrap_or(consts::NO_ERROR_CODE.to_string()),
            // message vary for the same code, so relying on code alone as it is unique
            message: reason_info
                .reason
                .code
                .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
            reason: reason_info.reason.reject_reason,
            status_code,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let refund_response_data = RefundsResponseData {
        connector_refund_id: response.payment_information.references.payment_request_id,
        refund_status,
    };
    (error, refund_response_data)
}

fn handle_bank_redirects_refund_sync_error_response(
    response: ErrorResponseBankRedirect,
    status_code: u16,
) -> (Option<ErrorResponse>, RefundsResponseData) {
    let error = Some(ErrorResponse {
        code: response.payment_result_info.result_code.to_string(),
        // message vary for the same code, so relying on code alone as it is unique
        message: response.payment_result_info.result_code.to_string(),
        reason: response.payment_result_info.additional_info,
        status_code,
        attempt_status: None,
        connector_transaction_id: None,
        network_advice_code: None,
        network_decline_code: None,
        network_error_message: None,
        connector_metadata: None,
    });
    //unreachable case as we are sending error as Some()
    let refund_response_data = RefundsResponseData {
        connector_refund_id: "".to_string(),
        refund_status: enums::RefundStatus::Failure,
    };
    (error, refund_response_data)
}

impl<F> TryFrom<RefundsResponseRouterData<F, RefundResponse>> for RefundsRouterData<F> {
    type Error = Error;
    fn try_from(item: RefundsResponseRouterData<F, RefundResponse>) -> Result<Self, Self::Error> {
        let (error, response) = match item.response {
            RefundResponse::CardsRefund(response) => {
                handle_cards_refund_response(*response, item.http_code)?
            }
            RefundResponse::WebhookRefund(response) => {
                handle_webhooks_refund_response(*response, item.http_code)?
            }
            RefundResponse::BankRedirectRefund(response) => {
                handle_bank_redirects_refund_response(*response, item.http_code)
            }
            RefundResponse::BankRedirectRefundSyncResponse(response) => {
                handle_bank_redirects_refund_sync_response(*response, item.http_code)
            }
            RefundResponse::BankRedirectError(response) => {
                handle_bank_redirects_refund_sync_error_response(*response, item.http_code)
            }
        };
        Ok(Self {
            response: error.map_or_else(|| Ok(response), Err),
            ..item.data
        })
    }
}

fn get_refund_status(
    payment_status: &str,
) -> CustomResult<(enums::RefundStatus, Option<String>), errors::ConnectorError> {
    let (is_failed, failure_message) = is_payment_failed(payment_status);
    if payment_status == "000.200.000" {
        Ok((enums::RefundStatus::Pending, None))
    } else if is_failed {
        Ok((
            enums::RefundStatus::Failure,
            Some(failure_message.to_string()),
        ))
    } else if is_payment_successful(payment_status)? {
        Ok((enums::RefundStatus::Success, None))
    } else {
        Ok((enums::RefundStatus::Pending, None))
    }
}

fn get_refund_status_from_result_info(
    result_code: i64,
) -> (enums::RefundStatus, Option<&'static str>) {
    match result_code {
        1001000 => (enums::RefundStatus::Success, None),
        1130001 => (enums::RefundStatus::Pending, Some("MapiPending")),
        1130000 => (enums::RefundStatus::Pending, Some("MapiSuccess")),
        1130004 => (enums::RefundStatus::Pending, Some("MapiProcessing")),
        1130002 => (enums::RefundStatus::Pending, Some("MapiAnnounced")),
        1130003 => (enums::RefundStatus::Pending, Some("MapiAuthorized")),
        1130005 => (enums::RefundStatus::Pending, Some("MapiAuthorizedOnly")),
        1112008 => (enums::RefundStatus::Failure, Some("InvalidPaymentState")),
        1112009 => (enums::RefundStatus::Failure, Some("RefundRejected")),
        1122006 => (
            enums::RefundStatus::Failure,
            Some("AccountCurrencyNotAllowed"),
        ),
        1132000 => (enums::RefundStatus::Failure, Some("InvalidMapiRequest")),
        1132001 => (enums::RefundStatus::Failure, Some("UnknownAccount")),
        1132002 => (
            enums::RefundStatus::Failure,
            Some("MerchantAccountDisabled"),
        ),
        1132003 => (enums::RefundStatus::Failure, Some("InvalidSign")),
        1132004 => (enums::RefundStatus::Failure, Some("DisposableBalance")),
        1132005 => (enums::RefundStatus::Failure, Some("TransactionNotFound")),
        1132006 => (enums::RefundStatus::Failure, Some("UnsupportedTransaction")),
        1132007 => (enums::RefundStatus::Failure, Some("GeneralMapiError")),
        1132008 => (
            enums::RefundStatus::Failure,
            Some("UnsupportedCurrencyConversion"),
        ),
        1132009 => (enums::RefundStatus::Failure, Some("UnknownMandate")),
        1132010 => (enums::RefundStatus::Failure, Some("CanceledMandate")),
        1132011 => (enums::RefundStatus::Failure, Some("MissingCid")),
        1132012 => (enums::RefundStatus::Failure, Some("MandateAlreadyPaid")),
        1132013 => (enums::RefundStatus::Failure, Some("AccountIsTesting")),
        1132014 => (enums::RefundStatus::Failure, Some("RequestThrottled")),
        1133000 => (enums::RefundStatus::Failure, Some("InvalidAuthentication")),
        1133001 => (enums::RefundStatus::Failure, Some("ServiceNotAllowed")),
        1133002 => (enums::RefundStatus::Failure, Some("PaymentRequestNotFound")),
        1133003 => (enums::RefundStatus::Failure, Some("UnexpectedGateway")),
        1133004 => (enums::RefundStatus::Failure, Some("MissingExternalId")),
        1152000 => (enums::RefundStatus::Failure, Some("RiskDecline")),
        _ => (enums::RefundStatus::Pending, None),
    }
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct TrustpayRedirectResponse {
    pub status: Option<String>,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Errors {
    pub code: i64,
    pub description: String,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TrustpayErrorResponse {
    pub status: i64,
    pub description: Option<String>,
    pub errors: Option<Vec<Errors>>,
    pub instance_id: Option<String>,
    pub payment_description: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum CreditDebitIndicator {
    Crdt,
    Dbit,
}

#[derive(strum::Display, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum WebhookStatus {
    Paid,
    Rejected,
    Refunded,
    Chargebacked,
    #[serde(other)]
    Unknown,
}

impl TryFrom<WebhookStatus> for enums::AttemptStatus {
    type Error = errors::ConnectorError;
    fn try_from(item: WebhookStatus) -> Result<Self, Self::Error> {
        match item {
            WebhookStatus::Paid => Ok(Self::Charged),
            WebhookStatus::Rejected => Ok(Self::AuthorizationFailed),
            _ => Err(errors::ConnectorError::WebhookEventTypeNotFound),
        }
    }
}

impl TryFrom<WebhookStatus> for enums::RefundStatus {
    type Error = errors::ConnectorError;
    fn try_from(item: WebhookStatus) -> Result<Self, Self::Error> {
        match item {
            WebhookStatus::Paid => Ok(Self::Success),
            WebhookStatus::Refunded => Ok(Self::Success),
            WebhookStatus::Rejected => Ok(Self::Failure),
            _ => Err(errors::ConnectorError::WebhookEventTypeNotFound),
        }
    }
}

#[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct WebhookReferences {
    pub merchant_reference: Option<String>,
    pub payment_id: Option<String>,
    pub payment_request_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct WebhookAmount {
    pub amount: FloatMajorUnit,
    pub currency: enums::Currency,
}


// Struct: DwollaPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/dwolla/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DwollaPaymentsRequest


// Function: update
// File: crates/diesel_models/src/query/address.rs
// Module: diesel_models

pub fn update(
        self,
        conn: &PgPooledConn,
        address_update_internal: AddressUpdateInternal,
    ) -> StorageResult<Self>


// Function: get_invoice_handler
// File: crates/router/src/core/subscription.rs
// Module: router

pub fn get_invoice_handler(&self) -> errors::RouterResult<InvoiceHandler>


// File: crates/hyperswitch_connectors/src/connectors/authipay.rs
// Module: hyperswitch_connectors
// Public functions: 2
// Public structs: 1

pub mod transformers;

use std::sync::LazyLock;

use base64::Engine;
use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use masking::{ExposeInterface, Mask, PeekInterface};
use transformers as authipay;

use crate::{constants::headers, types::ResponseRouterData, utils};

#[derive(Clone)]
pub struct Authipay {
    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}

impl Authipay {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &FloatMajorUnitForConnector,
        }
    }

    pub fn generate_authorization_signature(
        &self,
        auth: authipay::AuthipayAuthType,
        request_id: &str,
        payload: &str,
        timestamp: i128,
    ) -> CustomResult<String, errors::ConnectorError> {
        let authipay::AuthipayAuthType {
            api_key,
            api_secret,
        } = auth;
        let raw_signature = format!("{}{request_id}{timestamp}{payload}", api_key.peek());

        let key = ring::hmac::Key::new(ring::hmac::HMAC_SHA256, api_secret.expose().as_bytes());
        let signature_value = common_utils::consts::BASE64_ENGINE
            .encode(ring::hmac::sign(&key, raw_signature.as_bytes()).as_ref());
        Ok(signature_value)
    }
}

impl api::Payment for Authipay {}
impl api::PaymentSession for Authipay {}
impl api::ConnectorAccessToken for Authipay {}
impl api::MandateSetup for Authipay {}
impl api::PaymentAuthorize for Authipay {}
impl api::PaymentSync for Authipay {}
impl api::PaymentCapture for Authipay {}
impl api::PaymentVoid for Authipay {}
impl api::Refund for Authipay {}
impl api::RefundExecute for Authipay {}
impl api::RefundSync for Authipay {}
impl api::PaymentToken for Authipay {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Authipay
{
    // Not Implemented (R)
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Authipay
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let timestamp = time::OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000;
        let auth: authipay::AuthipayAuthType =
            authipay::AuthipayAuthType::try_from(&req.connector_auth_type)?;
        let mut auth_header = self.get_auth_header(&req.connector_auth_type)?;

        let authipay_req = self.get_request_body(req, connectors)?;

        let client_request_id = uuid::Uuid::new_v4().to_string();
        let hmac = self
            .generate_authorization_signature(
                auth,
                &client_request_id,
                authipay_req.get_inner_value().peek(),
                timestamp,
            )
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let mut headers = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                types::PaymentsAuthorizeType::get_content_type(self)
                    .to_string()
                    .into(),
            ),
            ("Client-Request-Id".to_string(), client_request_id.into()),
            ("Auth-Token-Type".to_string(), "HMAC".to_string().into()),
            (headers::TIMESTAMP.to_string(), timestamp.to_string().into()),
            ("Message-Signature".to_string(), hmac.into_masked()),
        ];
        headers.append(&mut auth_header);
        Ok(headers)
    }
}

impl ConnectorCommon for Authipay {
    fn id(&self) -> &'static str {
        "authipay"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.authipay.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = authipay::AuthipayAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::API_KEY.to_string(),
            auth.api_key.into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: authipay::AuthipayErrorResponse = res
            .response
            .parse_struct("AuthipayErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_error_response_body(&response));

        let mut error_response = ErrorResponse::from(&response);

        // Set status code from the response, or 400 if error code is a "404"
        if let Some(error_code) = &response.error.code {
            if error_code == "404" {
                error_response.status_code = 404;
            } else {
                error_response.status_code = res.status_code;
            }
        } else {
            error_response.status_code = res.status_code;
        }

        Ok(error_response)
    }
}

impl ConnectorValidation for Authipay {
    fn validate_connector_against_payment_request(
        &self,
        capture_method: Option<enums::CaptureMethod>,
        _payment_method: enums::PaymentMethod,
        _pmt: Option<enums::PaymentMethodType>,
    ) -> CustomResult<(), errors::ConnectorError> {
        let capture_method = capture_method.unwrap_or_default();
        match capture_method {
            enums::CaptureMethod::Automatic
            | enums::CaptureMethod::Manual
            | enums::CaptureMethod::SequentialAutomatic => Ok(()),
            enums::CaptureMethod::Scheduled | enums::CaptureMethod::ManualMultiple => Err(
                utils::construct_not_implemented_error_report(capture_method, self.id()),
            ),
        }
    }
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Authipay {
    //TODO: implement sessions flow
}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Authipay {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Authipay
{
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}payments", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = authipay::AuthipayRouterData::from((amount, req));
        let connector_req = authipay::AuthipayPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::PaymentsAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: authipay::AuthipayPaymentsResponse = res
            .response
            .parse_struct("Authipay PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_transaction_id = req
            .request
            .connector_transaction_id
            .get_connector_transaction_id()
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        Ok(format!(
            "{}payments/{}",
            self.base_url(connectors),
            connector_transaction_id
        ))
    }

    fn get_request_body(
        &self,
        _req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Ok(RequestContent::RawBytes(Vec::new()))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: authipay::AuthipayPaymentsResponse = res
            .response
            .parse_struct("authipay PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_transaction_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}payments/{}",
            self.base_url(connectors),
            connector_transaction_id
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount_to_capture,
            req.request.currency,
        )?;

        let connector_router_data = authipay::AuthipayRouterData::from((amount, req));
        let connector_req = authipay::AuthipayCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsCaptureType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: authipay::AuthipayPaymentsResponse = res
            .response
            .parse_struct("Authipay PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        // For void operations, Authipay requires using the /orders/{orderId} endpoint
        // The orderId should be stored in connector_meta from the authorization response
        let order_id = req
            .request
            .connector_meta
            .as_ref()
            .and_then(|meta| meta.get("order_id"))
            .and_then(|v| v.as_str())
            .ok_or(errors::ConnectorError::RequestEncodingFailed)?;

        Ok(format!("{}orders/{}", self.base_url(connectors), order_id))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        // For void, we don't need amount conversion since it's always full amount
        let connector_router_data =
            authipay::AuthipayRouterData::from((FloatMajorUnit::zero(), req));
        let connector_req = authipay::AuthipayVoidRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
                .set_body(types::PaymentsVoidType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: authipay::AuthipayPaymentsResponse = res
            .response
            .parse_struct("Authipay PaymentsVoidResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_payment_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}payments/{}",
            self.base_url(connectors),
            connector_payment_id
        ))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data = authipay::AuthipayRouterData::from((refund_amount, req));
        let connector_req = authipay::AuthipayRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::RefundExecuteType::get_headers(
                self, req, connectors,
            )?)
            .set_body(types::RefundExecuteType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: authipay::RefundResponse = res
            .response
            .parse_struct("authipay RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Authipay {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let refund_id = req
            .request
            .connector_refund_id
            .clone()
            .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
        Ok(format!(
            "{}payments/{}",
            self.base_url(connectors),
            refund_id
        ))
    }

    fn get_request_body(
        &self,
        _req: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Ok(RequestContent::RawBytes(Vec::new()))
    }

    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: authipay::RefundResponse = res
            .response
            .parse_struct("authipay RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Authipay {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

static AUTHIPAY_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::SequentialAutomatic,
            enums::CaptureMethod::Manual,
        ];

        let supported_card_network = vec![
            common_enums::CardNetwork::Visa,
            common_enums::CardNetwork::Mastercard,
        ];

        let mut authipay_supported_payment_methods = SupportedPaymentMethods::new();

        authipay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        authipay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        authipay_supported_payment_methods
    });

static AUTHIPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Authipay",
    description: "Authipay is a Fiserv-powered payment gateway for the EMEA region supporting Visa and Mastercard transactions. Features include flexible capture methods (automatic, manual, sequential), partial captures/refunds, payment tokenization, and secure HMAC SHA256 authentication.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
};

static AUTHIPAY_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];

impl ConnectorSpecifications for Authipay {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&AUTHIPAY_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*AUTHIPAY_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&AUTHIPAY_SUPPORTED_WEBHOOK_FLOWS)
    }
}


// Function: unify_with_payment_method_data_billing
// File: crates/hyperswitch_domain_models/src/payment_address.rs
// Module: hyperswitch_domain_models

// Documentation: Here the fields passed in payment_method_data_billing takes precedence

pub fn unify_with_payment_method_data_billing(
        self,
        payment_method_data_billing: Option<Address>,
    ) -> Self


// Implementation: impl behaviour::Conversion for for PaymentAttempt
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models
// Methods: 3 total (0 public)

impl behaviour::Conversion for for PaymentAttempt


// Function: read
// File: crates/hsdev/src/input_file.rs
// Module: hsdev

pub fn read(db_table: &Value) -> Result<Self, toml::de::Error>


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

impl Digitalvirgo


// Function: check_tenant
// File: crates/router/src/services/authorization.rs
// Module: router

pub fn check_tenant(
    token_tenant_id: Option<id_type::TenantId>,
    header_tenant_id: &id_type::TenantId,
) -> RouterResult<()>


// Function: delete_gsm_rule
// File: crates/openapi/src/routes/gsm.rs
// Module: openapi

pub fn delete_gsm_rule()


// Function: add_refund_sync_task
// File: crates/router/src/core/refunds.rs
// Module: router

pub fn add_refund_sync_task(
    db: &dyn db::StorageInterface,
    refund: &diesel_refund::Refund,
    runner: storage::ProcessTrackerRunner,
) -> RouterResult<storage::ProcessTracker>


// Implementation: impl OrganizationNew
// File: crates/api_models/src/organization.rs
// Module: api_models
// Methods: 1 total (1 public)

impl OrganizationNew


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

impl api::PaymentSync for for Gigadat


// Trait: Feature
// File: crates/router/src/core/payments/flows.rs
// Module: router

pub trait Feature<F, T>


// Struct: IncrementalAuthorizationDetails
// File: crates/router/src/core/payments.rs
// Module: router
// Implementations: 0

pub struct IncrementalAuthorizationDetails


// Function: update_connector
// File: crates/router/src/core/admin.rs
// Module: router

pub fn update_connector(
    state: SessionState,
    merchant_id: &id_type::MerchantId,
    profile_id: Option<id_type::ProfileId>,
    merchant_connector_id: &id_type::MerchantConnectorAccountId,
    req: api_models::admin::MerchantConnectorUpdate,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse>


// Function: generate_permissions
// File: crates/router_derive/src/lib.rs
// Module: router_derive

pub fn generate_permissions(input: proc_macro::TokenStream) -> proc_macro::TokenStream


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

impl api::ConnectorAccessToken for for Itaubank


// File: crates/storage_impl/src/redis/pub_sub.rs
// Module: storage_impl

use std::sync::atomic;

use error_stack::ResultExt;
use redis_interface::{errors as redis_errors, PubsubInterface, RedisValue};
use router_env::{logger, tracing::Instrument};

use crate::redis::cache::{
    CacheKey, CacheKind, CacheRedact, ACCOUNTS_CACHE, CGRAPH_CACHE, CONFIG_CACHE,
    CONTRACT_BASED_DYNAMIC_ALGORITHM_CACHE, DECISION_MANAGER_CACHE,
    ELIMINATION_BASED_DYNAMIC_ALGORITHM_CACHE, PM_FILTERS_CGRAPH_CACHE, ROUTING_CACHE,
    SUCCESS_BASED_DYNAMIC_ALGORITHM_CACHE, SURCHARGE_CACHE,
};

#[async_trait::async_trait]
pub trait PubSubInterface {
    async fn subscribe(&self, channel: &str) -> error_stack::Result<(), redis_errors::RedisError>;

    async fn publish<'a>(
        &self,
        channel: &str,
        key: CacheKind<'a>,
    ) -> error_stack::Result<usize, redis_errors::RedisError>;

    async fn on_message(&self) -> error_stack::Result<(), redis_errors::RedisError>;
}

#[async_trait::async_trait]
impl PubSubInterface for std::sync::Arc<redis_interface::RedisConnectionPool> {
    #[inline]
    async fn subscribe(&self, channel: &str) -> error_stack::Result<(), redis_errors::RedisError> {
        // Spawns a task that will automatically re-subscribe to any channels or channel patterns used by the client.
        self.subscriber.manage_subscriptions();

        self.subscriber
            .subscribe::<(), &str>(channel)
            .await
            .change_context(redis_errors::RedisError::SubscribeError)?;

        // Spawn only one thread handling all the published messages to different channels
        if self
            .subscriber
            .is_subscriber_handler_spawned
            .compare_exchange(
                false,
                true,
                atomic::Ordering::SeqCst,
                atomic::Ordering::SeqCst,
            )
            .is_ok()
        {
            let redis_clone = self.clone();
            let _task_handle = tokio::spawn(
                async move {
                    if let Err(pubsub_error) = redis_clone.on_message().await {
                        logger::error!(?pubsub_error);
                    }
                }
                .in_current_span(),
            );
        }

        Ok(())
    }

    #[inline]
    async fn publish<'a>(
        &self,
        channel: &str,
        key: CacheKind<'a>,
    ) -> error_stack::Result<usize, redis_errors::RedisError> {
        let key = CacheRedact {
            kind: key,
            tenant: self.key_prefix.clone(),
        };

        self.publisher
            .publish(
                channel,
                RedisValue::try_from(key).change_context(redis_errors::RedisError::PublishError)?,
            )
            .await
            .change_context(redis_errors::RedisError::SubscribeError)
    }

    #[inline]
    async fn on_message(&self) -> error_stack::Result<(), redis_errors::RedisError> {
        logger::debug!("Started on message");
        let mut rx = self.subscriber.on_message();
        while let Ok(message) = rx.recv().await {
            let channel_name = message.channel.to_string();
            logger::debug!("Received message on channel: {channel_name}");

            match channel_name.as_str() {
                super::cache::IMC_INVALIDATION_CHANNEL => {
                    let message = match CacheRedact::try_from(RedisValue::new(message.value))
                        .change_context(redis_errors::RedisError::OnMessageError)
                    {
                        Ok(value) => value,
                        Err(err) => {
                            logger::error!(value_conversion_err=?err);
                            continue;
                        }
                    };

                    let key = match message.kind {
                        CacheKind::Config(key) => {
                            CONFIG_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::Accounts(key) => {
                            ACCOUNTS_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::CGraph(key) => {
                            CGRAPH_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::PmFiltersCGraph(key) => {
                            PM_FILTERS_CGRAPH_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::EliminationBasedDynamicRoutingCache(key) => {
                            ELIMINATION_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::ContractBasedDynamicRoutingCache(key) => {
                            CONTRACT_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::SuccessBasedDynamicRoutingCache(key) => {
                            SUCCESS_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::Routing(key) => {
                            ROUTING_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::DecisionManager(key) => {
                            DECISION_MANAGER_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::Surcharge(key) => {
                            SURCHARGE_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            key
                        }
                        CacheKind::All(key) => {
                            CONFIG_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            ACCOUNTS_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            CGRAPH_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            PM_FILTERS_CGRAPH_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            SUCCESS_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            ELIMINATION_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            CONTRACT_BASED_DYNAMIC_ALGORITHM_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            ROUTING_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            DECISION_MANAGER_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;
                            SURCHARGE_CACHE
                                .remove(CacheKey {
                                    key: key.to_string(),
                                    prefix: message.tenant.clone(),
                                })
                                .await;

                            key
                        }
                    };

                    logger::debug!(
                        key_prefix=?message.tenant.clone(),
                        channel_name=?channel_name,
                        "Done invalidating {key}"
                    );
                }
                _ => {
                    logger::debug!("Received message from unknown channel: {channel_name}");
                }
            }
        }
        Ok(())
    }
}


// File: crates/hyperswitch_domain_models/src/router_response_types/disputes.rs
// Module: hyperswitch_domain_models
// Public structs: 5

#[derive(Default, Clone, Debug)]
pub struct AcceptDisputeResponse {
    pub dispute_status: api_models::enums::DisputeStatus,
    pub connector_status: Option<String>,
}

#[derive(Default, Clone, Debug)]
pub struct SubmitEvidenceResponse {
    pub dispute_status: api_models::enums::DisputeStatus,
    pub connector_status: Option<String>,
}

#[derive(Default, Debug, Clone)]
pub struct DefendDisputeResponse {
    pub dispute_status: api_models::enums::DisputeStatus,
    pub connector_status: Option<String>,
}

pub struct FileInfo {
    pub file_data: Option<Vec<u8>>,
    pub provider_file_id: Option<String>,
    pub file_type: Option<String>,
}

#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct DisputeSyncResponse {
    pub object_reference_id: api_models::webhooks::ObjectReferenceId,
    pub amount: common_utils::types::StringMinorUnit,
    pub currency: common_enums::enums::Currency,
    pub dispute_stage: common_enums::enums::DisputeStage,
    pub dispute_status: api_models::enums::DisputeStatus,
    pub connector_status: String,
    pub connector_dispute_id: String,
    pub connector_reason: Option<String>,
    pub connector_reason_code: Option<String>,
    pub challenge_required_by: Option<time::PrimitiveDateTime>,
    pub created_at: Option<time::PrimitiveDateTime>,
    pub updated_at: Option<time::PrimitiveDateTime>,
}

pub type FetchDisputesResponse = Vec<DisputeSyncResponse>;