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

use cards;
use common_enums::enums;
use common_utils::types::FloatMajorUnit;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        RefundsRouterData,
    },
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils,
};

// Type definition for router data with amount
pub struct AuthipayRouterData<T> {
    pub amount: FloatMajorUnit, // Amount in major units (e.g., dollars instead of cents)
    pub router_data: T,
}

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

// Basic request/response structs used across multiple operations

#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Amount {
    total: FloatMajorUnit,
    currency: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    components: Option<AmountComponents>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AmountComponents {
    subtotal: FloatMajorUnit,
}

#[derive(Default, Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExpiryDate {
    month: Secret<String>,
    year: Secret<String>,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Card {
    number: cards::CardNumber,
    security_code: Secret<String>,
    expiry_date: ExpiryDate,
}

#[derive(Default, Debug, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PaymentMethod {
    payment_card: Card,
}

#[derive(Default, Debug, Serialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SplitShipment {
    total_count: i32,
    final_shipment: bool,
}

#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayPaymentsRequest {
    request_type: &'static str,
    transaction_amount: Amount,
    payment_method: PaymentMethod,
    // split_shipment: Option<SplitShipment>,
    // incremental_flag: Option<bool>,
}

impl TryFrom<&AuthipayRouterData<&PaymentsAuthorizeRouterData>> for AuthipayPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &AuthipayRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        // Check if 3DS is being requested - Authipay doesn't support 3DS
        if matches!(
            item.router_data.auth_type,
            enums::AuthenticationType::ThreeDs
        ) {
            return Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("authipay"),
            )
            .into());
        }

        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                let expiry_date = ExpiryDate {
                    month: req_card.card_exp_month.clone(),
                    year: req_card.card_exp_year.clone(),
                };

                let card = Card {
                    number: req_card.card_number.clone(),
                    security_code: req_card.card_cvc.clone(),
                    expiry_date,
                };

                let payment_method = PaymentMethod { payment_card: card };

                let transaction_amount = Amount {
                    total: item.amount,
                    currency: item.router_data.request.currency.to_string(),
                    components: None,
                };

                // Determine request type based on capture method
                let request_type = match item.router_data.request.capture_method {
                    Some(enums::CaptureMethod::Manual) => "PaymentCardPreAuthTransaction",
                    Some(enums::CaptureMethod::Automatic) => "PaymentCardSaleTransaction",
                    Some(enums::CaptureMethod::SequentialAutomatic) => "PaymentCardSaleTransaction",
                    Some(enums::CaptureMethod::ManualMultiple)
                    | Some(enums::CaptureMethod::Scheduled) => {
                        return Err(errors::ConnectorError::NotSupported {
                            message: "Capture method not supported by Authipay".to_string(),
                            connector: "Authipay",
                        }
                        .into());
                    }
                    None => "PaymentCardSaleTransaction", // Default when not specified
                };

                let request = Self {
                    request_type,
                    transaction_amount,
                    payment_method,
                };

                Ok(request)
            }
            _ => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("authipay"),
            )
            .into()),
        }
    }
}

//TODO: Fill the struct with respective fields
// Auth Struct
pub struct AuthipayAuthType {
    pub(super) api_key: Secret<String>,
    pub(super) api_secret: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for AuthipayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::SignatureKey {
                api_key,
                api_secret,
                ..
            } => Ok(Self {
                api_key: api_key.to_owned(),
                api_secret: api_secret.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// Transaction Status enum (like Fiserv's FiservPaymentStatus)
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum AuthipayTransactionStatus {
    Authorized,
    Captured,
    Voided,
    Declined,
    Failed,
    #[default]
    Processing,
}

impl From<AuthipayTransactionStatus> for enums::AttemptStatus {
    fn from(item: AuthipayTransactionStatus) -> Self {
        match item {
            AuthipayTransactionStatus::Captured => Self::Charged,
            AuthipayTransactionStatus::Declined | AuthipayTransactionStatus::Failed => {
                Self::Failure
            }
            AuthipayTransactionStatus::Processing => Self::Pending,
            AuthipayTransactionStatus::Authorized => Self::Authorized,
            AuthipayTransactionStatus::Voided => Self::Voided,
        }
    }
}

// Transaction Processing Details (like Fiserv's TransactionProcessingDetails)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayTransactionProcessingDetails {
    pub order_id: String,
    pub transaction_id: String,
}

// Gateway Response (like Fiserv's GatewayResponse)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayGatewayResponse {
    pub transaction_state: AuthipayTransactionStatus,
    pub transaction_processing_details: AuthipayTransactionProcessingDetails,
}

// Payment Receipt (like Fiserv's PaymentReceipt)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayPaymentReceipt {
    pub approved_amount: Amount,
    pub processor_response_details: Option<Processor>,
}

// Main Response (like Fiserv's FiservPaymentsResponse) - but flat for JSON deserialization
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayPaymentsResponse {
    #[serde(rename = "type")]
    response_type: Option<String>,
    client_request_id: String,
    api_trace_id: String,
    ipg_transaction_id: String,
    order_id: String,
    transaction_type: String,
    payment_token: Option<PaymentToken>,
    transaction_origin: Option<String>,
    payment_method_details: Option<PaymentMethodDetails>,
    country: Option<String>,
    terminal_id: Option<String>,
    merchant_id: Option<String>,
    transaction_time: i64,
    approved_amount: Amount,
    transaction_amount: Amount,
    // For payment transactions (SALE)
    transaction_status: Option<String>,
    // For refund transactions (RETURN)
    transaction_result: Option<String>,
    transaction_state: Option<String>,
    approval_code: String,
    scheme_transaction_id: Option<String>,
    processor: Processor,
}

impl AuthipayPaymentsResponse {
    /// Get gateway response (like Fiserv's gateway_response)
    pub fn gateway_response(&self) -> AuthipayGatewayResponse {
        AuthipayGatewayResponse {
            transaction_state: self.get_transaction_status(),
            transaction_processing_details: AuthipayTransactionProcessingDetails {
                order_id: self.order_id.clone(),
                transaction_id: self.ipg_transaction_id.clone(),
            },
        }
    }

    /// Get payment receipt (like Fiserv's payment_receipt)
    pub fn payment_receipt(&self) -> AuthipayPaymentReceipt {
        AuthipayPaymentReceipt {
            approved_amount: self.approved_amount.clone(),
            processor_response_details: Some(self.processor.clone()),
        }
    }

    /// Determine the transaction status based on transaction type and various status fields (like Fiserv)
    fn get_transaction_status(&self) -> AuthipayTransactionStatus {
        match self.transaction_type.as_str() {
            "RETURN" => {
                // Refund transaction - use transaction_result
                match self.transaction_result.as_deref() {
                    Some("APPROVED") => AuthipayTransactionStatus::Captured,
                    Some("DECLINED") | Some("FAILED") => AuthipayTransactionStatus::Failed,
                    _ => AuthipayTransactionStatus::Processing,
                }
            }
            "VOID" => {
                // Void transaction - use transaction_result, fallback to transaction_state
                match self.transaction_result.as_deref() {
                    Some("APPROVED") => AuthipayTransactionStatus::Voided,
                    Some("DECLINED") | Some("FAILED") => AuthipayTransactionStatus::Failed,
                    Some("PENDING") | Some("PROCESSING") => AuthipayTransactionStatus::Processing,
                    _ => {
                        // Fallback to transaction_state for void operations
                        match self.transaction_state.as_deref() {
                            Some("VOIDED") => AuthipayTransactionStatus::Voided,
                            Some("FAILED") | Some("DECLINED") => AuthipayTransactionStatus::Failed,
                            _ => AuthipayTransactionStatus::Voided, // Default assumption for void requests
                        }
                    }
                }
            }
            _ => {
                // Payment transaction - prioritize transaction_state over transaction_status
                match self.transaction_state.as_deref() {
                    Some("AUTHORIZED") => AuthipayTransactionStatus::Authorized,
                    Some("CAPTURED") => AuthipayTransactionStatus::Captured,
                    Some("VOIDED") => AuthipayTransactionStatus::Voided,
                    Some("DECLINED") | Some("FAILED") => AuthipayTransactionStatus::Failed,
                    _ => {
                        // Fallback to transaction_status with transaction_type context
                        match (
                            self.transaction_type.as_str(),
                            self.transaction_status.as_deref(),
                        ) {
                            // For PREAUTH transactions, "APPROVED" means authorized and awaiting capture
                            ("PREAUTH", Some("APPROVED")) => AuthipayTransactionStatus::Authorized,
                            // For POSTAUTH transactions, "APPROVED" means successfully captured
                            ("POSTAUTH", Some("APPROVED")) => AuthipayTransactionStatus::Captured,
                            // For SALE transactions, "APPROVED" means completed payment
                            ("SALE", Some("APPROVED")) => AuthipayTransactionStatus::Captured,
                            // For VOID transactions, "APPROVED" means successfully voided
                            ("VOID", Some("APPROVED")) => AuthipayTransactionStatus::Voided,
                            // Generic status mappings for other cases
                            (_, Some("APPROVED")) => AuthipayTransactionStatus::Captured,
                            (_, Some("AUTHORIZED")) => AuthipayTransactionStatus::Authorized,
                            (_, Some("DECLINED") | Some("FAILED")) => {
                                AuthipayTransactionStatus::Failed
                            }
                            _ => AuthipayTransactionStatus::Processing,
                        }
                    }
                }
            }
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PaymentToken {
    reusable: Option<bool>,
    decline_duplicates: Option<bool>,
    brand: Option<String>,
    #[serde(rename = "type")]
    token_type: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PaymentMethodDetails {
    payment_card: Option<PaymentCardDetails>,
    payment_method_type: Option<String>,
    payment_method_brand: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PaymentCardDetails {
    expiry_date: ExpiryDate,
    bin: String,
    last4: String,
    brand: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Processor {
    reference_number: Option<String>,
    authorization_code: Option<String>,
    response_code: String,
    response_message: String,
    avs_response: Option<AvsResponse>,
    security_code_response: Option<String>,
    tax_refund_data: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AvsResponse {
    street_match: Option<String>,
    postal_code_match: Option<String>,
}

impl<F, T> TryFrom<ResponseRouterData<F, AuthipayPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, AuthipayPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        // Get gateway response (like Fiserv pattern)
        let gateway_resp = item.response.gateway_response();

        // Store order_id in connector_metadata for void operations (like Fiserv)
        let mut metadata = std::collections::HashMap::new();
        metadata.insert(
            "order_id".to_string(),
            serde_json::Value::String(gateway_resp.transaction_processing_details.order_id.clone()),
        );
        let connector_metadata = Some(serde_json::Value::Object(serde_json::Map::from_iter(
            metadata,
        )));

        Ok(Self {
            status: enums::AttemptStatus::from(gateway_resp.transaction_state.clone()),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    gateway_resp
                        .transaction_processing_details
                        .transaction_id
                        .clone(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata,
                network_txn_id: None,
                connector_response_reference_id: Some(
                    gateway_resp.transaction_processing_details.order_id.clone(),
                ),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

// Type definition for CaptureRequest
#[derive(Debug, Serialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayCaptureRequest {
    request_type: &'static str,
    transaction_amount: Amount,
}

impl TryFrom<&AuthipayRouterData<&PaymentsCaptureRouterData>> for AuthipayCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: &AuthipayRouterData<&PaymentsCaptureRouterData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            request_type: "PostAuthTransaction",
            transaction_amount: Amount {
                total: item.amount,
                currency: item.router_data.request.currency.to_string(),
                components: None,
            },
        })
    }
}

// Type definition for VoidRequest
#[derive(Debug, Serialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayVoidRequest {
    request_type: &'static str,
}

impl TryFrom<&AuthipayRouterData<&PaymentsCancelRouterData>> for AuthipayVoidRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        _item: &AuthipayRouterData<&PaymentsCancelRouterData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            request_type: "VoidTransaction",
        })
    }
}

// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayRefundRequest {
    request_type: &'static str,
    transaction_amount: Amount,
}

impl<F> TryFrom<&AuthipayRouterData<&RefundsRouterData<F>>> for AuthipayRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &AuthipayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            request_type: "ReturnTransaction",
            transaction_amount: Amount {
                total: item.amount.to_owned(),
                currency: item.router_data.request.currency.to_string(),
                components: None,
            },
        })
    }
}

// Type definition for Refund Response

#[allow(dead_code)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Succeeded => Self::Success,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Processing => Self::Pending,
            //TODO: Review mapping
        }
    }
}

// Reusing the payments response structure for refunds
// because Authipay uses the same endpoint and response format
pub type RefundResponse = AuthipayPaymentsResponse;

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        let refund_status = if item.response.transaction_type == "RETURN" {
            match item.response.transaction_result.as_deref() {
                Some("APPROVED") => RefundStatus::Succeeded,
                Some("DECLINED") | Some("FAILED") => RefundStatus::Failed,
                _ => RefundStatus::Processing,
            }
        } else {
            RefundStatus::Processing
        };

        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.ipg_transaction_id.to_string(),
                refund_status: enums::RefundStatus::from(refund_status),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        let refund_status = if item.response.transaction_type == "RETURN" {
            match item.response.transaction_result.as_deref() {
                Some("APPROVED") => RefundStatus::Succeeded,
                Some("DECLINED") | Some("FAILED") => RefundStatus::Failed,
                _ => RefundStatus::Processing,
            }
        } else {
            RefundStatus::Processing
        };

        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.ipg_transaction_id.to_string(),
                refund_status: enums::RefundStatus::from(refund_status),
            }),
            ..item.data
        })
    }
}

// Error Response structs
#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ErrorDetailItem {
    pub field: String,
    pub message: String,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ErrorDetails {
    pub code: Option<String>,
    pub message: String,
    pub details: Option<Vec<ErrorDetailItem>>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthipayErrorResponse {
    pub client_request_id: Option<String>,
    pub api_trace_id: Option<String>,
    pub response_type: Option<String>,
    #[serde(rename = "type")]
    pub response_object_type: Option<String>,
    pub error: ErrorDetails,
    pub decline_reason_code: Option<String>,
}

impl From<&AuthipayErrorResponse> for ErrorResponse {
    fn from(item: &AuthipayErrorResponse) -> Self {
        Self {
            status_code: 500, // Default to Internal Server Error, will be overridden by actual HTTP status
            code: item.error.code.clone().unwrap_or_default(),
            message: item.error.message.clone(),
            reason: None,
            attempt_status: None,
            connector_transaction_id: None,
            network_decline_code: None,
            network_advice_code: None,
            network_error_message: None,
            connector_metadata: None,
        }
    }
}


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

pub struct BraintreeThreeDsErrorResponse


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

pub fn get_id(&self) -> &id_type::GlobalPaymentId


// Struct: NoEncryption
// File: crates/external_services/src/no_encryption/core.rs
// Module: external_services
// Implementations: 1

pub struct NoEncryption


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

pub struct PayuOrderResponseBuyerData


// Implementation: impl api::PaymentsGiftCardBalanceCheck for for Adyen
// File: crates/hyperswitch_connectors/src/connectors/adyen.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentsGiftCardBalanceCheck for for Adyen


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

impl api::ConnectorAccessToken for for Katapult


// Trait: UserRoleInterface
// File: crates/router/src/db/user_role.rs
// Module: router

pub trait UserRoleInterface


// Struct: XenditSplitSubMerchantData
// File: crates/common_types/src/domain.rs
// Module: common_types
// Implementations: 0

pub struct XenditSplitSubMerchantData


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

impl Recon


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

impl api::MandateSetup for for CtpMastercard


// Struct: EbanxRouterData
// File: crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EbanxRouterData<T>


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

pub struct SilverflowPaymentsRequest


// Function: validate_stripe_charge_refund
// File: crates/router/src/core/utils/refunds_validator.rs
// Module: router

pub fn validate_stripe_charge_refund(
    charge_type_option: Option<api_enums::PaymentChargeType>,
    split_refund_request: &Option<common_types::refunds::SplitRefund>,
) -> RouterResult<types::ChargeRefundsOptions>


// Implementation: impl webhooks::IncomingWebhook for for Fiuu
// File: crates/hyperswitch_connectors/src/connectors/fiuu.rs
// Module: hyperswitch_connectors
// Methods: 7 total (0 public)

impl webhooks::IncomingWebhook for for Fiuu


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

impl api::RefundExecute for for Payme


// Trait: SdkEventFilterAnalytics
// File: crates/analytics/src/sdk_events/filters.rs
// Module: analytics

pub trait SdkEventFilterAnalytics: LoadRow<SdkEventFilter>


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

impl api::PaymentSession for for Airwallex


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

pub fn update(
        conn: &PgPooledConn,
        user_id: Option<String>,
        merchant_id: id_type::MerchantId,
        org_id: id_type::OrganizationId,
        data_key: enums::DashboardMetadata,
        dashboard_metadata_update: DashboardMetadataUpdate,
    ) -> StorageResult<Self>


// Function: get_schedule_time_for_smart_retry
// File: crates/router/src/workflows/revenue_recovery.rs
// Module: router

pub fn get_schedule_time_for_smart_retry(
    state: &SessionState,
    payment_intent: &PaymentIntent,
    retry_after_time: Option<prost_types::Timestamp>,
    token_with_retry_info: &PaymentProcessorTokenWithRetryInfo,
) -> Result<Option<time::PrimitiveDateTime>, errors::ProcessTrackerError>


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

impl api::RefundSync for for Celero


// Struct: EdgeId
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Implementations: 0

pub struct EdgeId


// Struct: CardNetworkTokenizeRequest
// File: crates/hyperswitch_domain_models/src/bulk_tokenization.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct CardNetworkTokenizeRequest


// Struct: ApplepayMerchantResponse
// File: crates/api_models/src/verifications.rs
// Module: api_models
// Implementations: 0

pub struct ApplepayMerchantResponse


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

pub struct SubscriptionCreateRequest


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

impl api::PaymentVoid for for Blackhawknetwork


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

pub struct ErrorInformation


// Function: build
// File: crates/router/src/core/payments.rs
// Module: router

pub fn build(self) -> Vec<ActionType>


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

pub fn switch_org_for_user(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<user_api::SwitchOrganizationRequest>,
) -> HttpResponse


// Function: get_amount_captured
// File: crates/hyperswitch_domain_models/src/router_response_types.rs
// Module: hyperswitch_domain_models

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


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

pub fn get_jwt_from_authorization_header(headers: &HeaderMap) -> RouterResult<&str>


// Struct: PaymentsStatusDetails
// File: crates/hyperswitch_connectors/src/connectors/amazonpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentsStatusDetails


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

use masking::PeekInterface;
use router::types::{self, domain, storage::enums, AccessToken, ConnectorAuthType};

use crate::{
    connector_auth,
    utils::{self, Connector, ConnectorActions, PaymentAuthorizeType},
};
struct Payu;
impl ConnectorActions for Payu {}
impl Connector for Payu {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Payu;
        utils::construct_connector_data_old(
            Box::new(Payu::new()),
            types::Connector::Payu,
            types::api::GetToken::Connector,
            None,
        )
    }

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

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

fn get_access_token() -> Option<AccessToken> {
    let connector = Payu {};
    match connector.get_auth_token() {
        ConnectorAuthType::BodyKey { api_key, key1 } => Some(AccessToken {
            token: api_key,
            expires: key1.peek().parse::<i64>().unwrap(),
        }),
        _ => None,
    }
}
fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    Some(utils::PaymentInfo {
        access_token: get_access_token(),
        ..Default::default()
    })
}

#[actix_web::test]
#[ignore]
async fn should_authorize_card_payment() {
    //Authorize Card Payment in PLN currency
    let authorize_response = Payu {}
        .authorize_payment(
            Some(types::PaymentsAuthorizeData {
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    // in Payu need Psync to get status therefore set to pending
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);
    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        let sync_response = Payu {}
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Authorized,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id.clone(),
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        // Assert the sync response, it will be authorized in case of manual capture, for automatic it will be Completed Success
        assert_eq!(sync_response.status, enums::AttemptStatus::Authorized);
    }
}

#[actix_web::test]
async fn should_authorize_gpay_payment() {
    let authorize_response = Payu {}
        .authorize_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Wallet(
                    domain::WalletData::GooglePay(domain::GooglePayWalletData {
                        pm_type: "CARD".to_string(),
                        description: "Visa1234567890".to_string(),
                        info: domain::GooglePayPaymentMethodInfo {
                            card_network: "VISA".to_string(),
                            card_details: "1234".to_string(),
                            assurance_details: None,
                        },
                        tokenization_data: common_types::payments::GpayTokenizationData::Encrypted(
                            common_types::payments::GpayEcryptedTokenizationData {
                                token_type: "worldpay".to_string(),
                                token: "someToken".to_string(),
                            },
                        ),
                    }),
                ),
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);
    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        let sync_response = Payu {}
            .sync_payment(
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id.clone(),
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(sync_response.status, enums::AttemptStatus::Authorized);
    }
}

#[actix_web::test]
#[ignore]
async fn should_capture_already_authorized_payment() {
    let connector = Payu {};
    let authorize_response = connector
        .authorize_payment(
            Some(types::PaymentsAuthorizeData {
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);
    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        let sync_response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Authorized,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id.clone(),
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(sync_response.status, enums::AttemptStatus::Authorized);
        let capture_response = connector
            .capture_payment(transaction_id.clone(), None, get_default_payment_info())
            .await
            .unwrap();
        assert_eq!(capture_response.status, enums::AttemptStatus::Pending);
        let response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Charged,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id,
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(response.status, enums::AttemptStatus::Charged,);
    }
}

#[actix_web::test]
#[ignore]
async fn should_sync_payment() {
    let connector = Payu {};
    // Authorize the payment for manual capture
    let authorize_response = connector
        .authorize_payment(
            Some(types::PaymentsAuthorizeData {
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);

    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        // Sync the Payment Data
        let response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Authorized,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id,
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();

        assert_eq!(response.status, enums::AttemptStatus::Authorized);
    }
}

#[actix_web::test]
#[ignore]
async fn should_void_already_authorized_payment() {
    let connector = Payu {};
    //make a successful payment
    let authorize_response = connector
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);

    //try CANCEL for previous payment
    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        let void_response = connector
            .void_payment(transaction_id.clone(), None, get_default_payment_info())
            .await
            .unwrap();
        assert_eq!(void_response.status, enums::AttemptStatus::Pending);

        let sync_response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Voided,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id,
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(sync_response.status, enums::AttemptStatus::Voided,);
    }
}

#[actix_web::test]
#[ignore]
async fn should_refund_succeeded_payment() {
    let connector = Payu {};
    let authorize_response = connector
        .authorize_payment(
            Some(types::PaymentsAuthorizeData {
                currency: enums::Currency::PLN,
                ..PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Pending);

    if let Some(transaction_id) = utils::get_connector_transaction_id(authorize_response.response) {
        let sync_response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Authorized,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id.clone(),
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(sync_response.status, enums::AttemptStatus::Authorized);
        //Capture the payment in case of Manual Capture
        let capture_response = connector
            .capture_payment(transaction_id.clone(), None, get_default_payment_info())
            .await
            .unwrap();
        assert_eq!(capture_response.status, enums::AttemptStatus::Pending);

        let sync_response = connector
            .psync_retry_till_status_matches(
                enums::AttemptStatus::Charged,
                Some(types::PaymentsSyncData {
                    connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                        transaction_id.clone(),
                    ),
                    ..Default::default()
                }),
                get_default_payment_info(),
            )
            .await
            .unwrap();
        assert_eq!(sync_response.status, enums::AttemptStatus::Charged);
        //Refund the payment
        let refund_response = connector
            .refund_payment(transaction_id.clone(), None, get_default_payment_info())
            .await
            .unwrap();
        assert_eq!(
            refund_response.response.unwrap().connector_refund_id.len(),
            10
        );
    }
}

#[actix_web::test]
async fn should_sync_succeeded_refund_payment() {
    let connector = Payu {};

    //Currently hardcoding the order_id because RSync is not instant, change it accordingly
    let sync_refund_response = connector
        .sync_refund(
            "6DHQQN3T57230110GUEST000P01".to_string(),
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        sync_refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success
    );
}

#[actix_web::test]
async fn should_fail_already_refunded_payment() {
    let connector = Payu {};
    //Currently hardcoding the order_id, change it accordingly
    let response = connector
        .refund_payment(
            "5H1SVX6P7W230112GUEST000P01".to_string(),
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    assert_eq!(x.reason.unwrap(), "PAID".to_string());
}


// Struct: DummyConnectorRefundRetrieveRequest
// File: crates/router/src/routes/dummy_connector/types.rs
// Module: router
// Implementations: 0

pub struct DummyConnectorRefundRetrieveRequest


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

pub fn extract_card_network(&self) -> Option<common_enums::CardNetwork>


// File: crates/test_utils/tests/connectors/trustpay_3ds_ui.rs
// Module: test_utils

use serial_test::serial;
use thirtyfour::{prelude::*, WebDriver};

use crate::{selenium::*, tester};

struct TrustpaySeleniumTest;

impl SeleniumTest for TrustpaySeleniumTest {
    fn get_connector_name(&self) -> String {
        "trustpay_3ds".to_string()
    }
}

async fn should_make_trustpay_3ds_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = TrustpaySeleniumTest {};
    conn.make_redirection_payment(
        web_driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/206"))),
            Event::Trigger(Trigger::Sleep(1)),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Trigger(Trigger::Click(By::Css(
                "button.btn.btn-lg.btn-primary.btn-block",
            ))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::Contains(
                Selector::QueryParamStr,
                "status=succeeded",
            )),
        ],
    )
    .await?;
    Ok(())
}

#[test]
#[serial]
#[ignore]
fn should_make_trustpay_3ds_payment_test() {
    tester!(should_make_trustpay_3ds_payment);
}


// Trait: RecoveryDeciderClientInterface
// File: crates/external_services/src/grpc_client/revenue_recovery/recovery_decider_client.rs
// Module: external_services

pub trait RecoveryDeciderClientInterface: dyn_clone::DynClone + Send + Sync + Debug


// Function: confirm_subscription
// File: crates/router/src/routes/subscription.rs
// Module: router

pub fn confirm_subscription(
    state: web::Data<AppState>,
    req: HttpRequest,
    subscription_id: web::Path<common_utils::id_type::SubscriptionId>,
    json_payload: web::Json<subscription_types::ConfirmSubscriptionRequest>,
) -> impl Responder


// Struct: GrpcHeadersUcs
// File: crates/external_services/src/grpc_client.rs
// Module: external_services
// Implementations: 0

pub struct GrpcHeadersUcs


// Function: save_payment_method
// File: crates/router/src/core/payments/tokenization.rs
// Module: router

pub fn save_payment_method<FData>(
    _state: &SessionState,
    _connector_name: String,
    _save_payment_method_data: SavePaymentMethodData<FData>,
    _customer_id: Option<id_type::CustomerId>,
    _merchant_context: &domain::MerchantContext,
    _payment_method_type: Option<storage_enums::PaymentMethodType>,
    _billing_name: Option<Secret<String>>,
    _payment_method_billing_address: Option<&api::Address>,
    _business_profile: &domain::Profile,
    _connector_mandate_request_reference_id: Option<String>,
) -> RouterResult<SavePaymentMethodDataResponse>
where
    FData: mandate::MandateBehaviour + Clone,


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

pub struct AdyenCategoryData


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

pub fn switch_org_for_user(
    state: SessionState,
    request: user_api::SwitchOrganizationRequest,
    user_from_token: auth::UserFromToken,
) -> UserResponse<user_api::TokenResponse>


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

impl api::PaymentCapture for for Moneris


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

pub struct NovalnetErrorResponse


// File: crates/hyperswitch_interfaces/src/events/routing_api_logs.rs
// Module: hyperswitch_interfaces
// Public functions: 12
// Public structs: 1

//! Routing API logs interface

use std::fmt;

use api_models::routing::RoutableConnectorChoice;
use common_utils::request::Method;
use router_env::tracing_actix_web::RequestId;
use serde::Serialize;
use serde_json::json;
use time::OffsetDateTime;

/// RoutingEngine enum
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RoutingEngine {
    /// Dynamo for routing
    IntelligentRouter,
    /// Decision engine for routing
    DecisionEngine,
}

/// Method type enum
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ApiMethod {
    /// grpc call
    Grpc,
    /// Rest call
    Rest(Method),
}

impl fmt::Display for ApiMethod {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Grpc => write!(f, "Grpc"),
            Self::Rest(method) => write!(f, "Rest ({method})"),
        }
    }
}

#[derive(Debug, Serialize)]
/// RoutingEvent type
pub struct RoutingEvent {
    tenant_id: common_utils::id_type::TenantId,
    routable_connectors: String,
    payment_connector: Option<String>,
    flow: String,
    request: String,
    response: Option<String>,
    error: Option<String>,
    url: String,
    method: String,
    payment_id: String,
    profile_id: common_utils::id_type::ProfileId,
    merchant_id: common_utils::id_type::MerchantId,
    created_at: i128,
    status_code: Option<u16>,
    request_id: String,
    routing_engine: RoutingEngine,
    routing_approach: Option<String>,
}

impl RoutingEvent {
    /// fn new RoutingEvent
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        tenant_id: common_utils::id_type::TenantId,
        routable_connectors: String,
        flow: &str,
        request: serde_json::Value,
        url: String,
        method: ApiMethod,
        payment_id: String,
        profile_id: common_utils::id_type::ProfileId,
        merchant_id: common_utils::id_type::MerchantId,
        request_id: Option<RequestId>,
        routing_engine: RoutingEngine,
    ) -> Self {
        Self {
            tenant_id,
            routable_connectors,
            flow: flow.to_string(),
            request: request.to_string(),
            response: None,
            error: None,
            url,
            method: method.to_string(),
            payment_id,
            profile_id,
            merchant_id,
            created_at: OffsetDateTime::now_utc().unix_timestamp_nanos(),
            status_code: None,
            request_id: request_id
                .map(|i| i.as_hyphenated().to_string())
                .unwrap_or("NO_REQUEST_ID".to_string()),
            routing_engine,
            payment_connector: None,
            routing_approach: None,
        }
    }

    /// fn set_response_body
    pub fn set_response_body<T: Serialize>(&mut self, response: &T) {
        match masking::masked_serialize(response) {
            Ok(masked) => {
                self.response = Some(masked.to_string());
            }
            Err(er) => self.set_error(json!({"error": er.to_string()})),
        }
    }

    /// fn set_error_response_body
    pub fn set_error_response_body<T: Serialize>(&mut self, response: &T) {
        match masking::masked_serialize(response) {
            Ok(masked) => {
                self.error = Some(masked.to_string());
            }
            Err(er) => self.set_error(json!({"error": er.to_string()})),
        }
    }

    /// fn set_error
    pub fn set_error(&mut self, error: serde_json::Value) {
        self.error = Some(error.to_string());
    }

    /// set response status code
    pub fn set_status_code(&mut self, code: u16) {
        self.status_code = Some(code);
    }

    /// set response status code
    pub fn set_routable_connectors(&mut self, connectors: Vec<RoutableConnectorChoice>) {
        let connectors = connectors
            .into_iter()
            .map(|c| {
                format!(
                    "{:?}:{:?}",
                    c.connector,
                    c.merchant_connector_id
                        .map(|id| id.get_string_repr().to_string())
                        .unwrap_or(String::from(""))
                )
            })
            .collect::<Vec<_>>()
            .join(",");
        self.routable_connectors = connectors;
    }

    /// set payment connector
    pub fn set_payment_connector(&mut self, connector: RoutableConnectorChoice) {
        self.payment_connector = Some(format!(
            "{:?}:{:?}",
            connector.connector,
            connector
                .merchant_connector_id
                .map(|id| id.get_string_repr().to_string())
                .unwrap_or(String::from(""))
        ));
    }

    /// set routing approach
    pub fn set_routing_approach(&mut self, approach: String) {
        self.routing_approach = Some(approach);
    }

    /// Returns the request ID of the event.
    pub fn get_request_id(&self) -> &str {
        &self.request_id
    }

    /// Returns the merchant ID of the event.
    pub fn get_merchant_id(&self) -> &str {
        self.merchant_id.get_string_repr()
    }

    /// Returns the payment ID of the event.
    pub fn get_payment_id(&self) -> &str {
        &self.payment_id
    }

    /// Returns the profile ID of the event.
    pub fn get_profile_id(&self) -> &str {
        self.profile_id.get_string_repr()
    }
}


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

impl Health


// Struct: ConnectorOnboarding
// File: crates/router/src/routes/app.rs
// Module: router
// Implementations: 1

pub struct ConnectorOnboarding


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

pub fn delete_by_merchant_id_merchant_connector_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_connector_id: &common_utils::id_type::MerchantConnectorAccountId,
    ) -> StorageResult<bool>


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

impl ConnectorSpecifications for for Volt


// Struct: GetFrmMetricRequest
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 1
// Traits: ApiEventMetric

pub struct GetFrmMetricRequest


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

impl Gigadat


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

pub struct AdyenPlatformAccountHolder


// Struct: PmTokenized
// File: crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
// Module: router
// Implementations: 1
// Traits: State

pub struct PmTokenized


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

pub struct WisePayoutSyncResponse


// Function: get_profile_dispute_metrics
// File: crates/router/src/analytics.rs
// Module: router

// Documentation: Panics if `json_payload` array does not contain one `GetDisputeMetricRequest` element.

pub fn get_profile_dispute_metrics(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<[GetDisputeMetricRequest; 1]>,
    ) -> impl Responder


// Struct: ExternalVerifyTokenRequest
// File: crates/api_models/src/external_service_auth.rs
// Module: api_models
// Implementations: 0

pub struct ExternalVerifyTokenRequest


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

pub fn create_payment_method_api()


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

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


// Struct: TokenizedBankDebitValue2
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct TokenizedBankDebitValue2


// Implementation: impl ConnectorAuthentication
// File: crates/test_utils/src/connector_auth.rs
// Module: test_utils
// Methods: 1 total (1 public)

impl ConnectorAuthentication


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

// Public submodules:
pub mod transformers;


// Implementation: impl GlobalRefundId
// File: crates/common_utils/src/id_type/global_id/refunds.rs
// Module: common_utils
// Methods: 2 total (2 public)

impl GlobalRefundId


// Struct: Address
// File: crates/hyperswitch_connectors/src/connectors/getnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Address


// File: crates/drainer/src/health_check.rs
// Module: drainer
// Public functions: 4
// Public structs: 2

use std::{collections::HashMap, sync::Arc};

use actix_web::{web, Scope};
use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl};
use common_utils::{errors::CustomResult, id_type};
use diesel_models::{Config, ConfigNew};
use error_stack::ResultExt;
use router_env::{instrument, logger, tracing};

use crate::{
    connection::pg_connection,
    errors::HealthCheckError,
    services::{self, log_and_return_error_response, Store},
    Settings,
};

pub const TEST_STREAM_NAME: &str = "TEST_STREAM_0";
pub const TEST_STREAM_DATA: &[(&str, &str)] = &[("data", "sample_data")];

pub struct Health;

impl Health {
    pub fn server(conf: Settings, stores: HashMap<id_type::TenantId, Arc<Store>>) -> Scope {
        web::scope("health")
            .app_data(web::Data::new(conf))
            .app_data(web::Data::new(stores))
            .service(web::resource("").route(web::get().to(health)))
            .service(web::resource("/ready").route(web::get().to(deep_health_check)))
    }
}

#[instrument(skip_all)]
pub async fn health() -> impl actix_web::Responder {
    logger::info!("Drainer health was called");
    actix_web::HttpResponse::Ok().body("Drainer health is good")
}

#[instrument(skip_all)]
pub async fn deep_health_check(
    conf: web::Data<Settings>,
    stores: web::Data<HashMap<String, Arc<Store>>>,
) -> impl actix_web::Responder {
    let mut deep_health_res = HashMap::new();
    for (tenant, store) in stores.iter() {
        logger::info!("Tenant: {:?}", tenant);

        let response = match deep_health_check_func(conf.clone(), store).await {
            Ok(response) => serde_json::to_string(&response)
                .map_err(|err| {
                    logger::error!(serialization_error=?err);
                })
                .unwrap_or_default(),
            Err(err) => return log_and_return_error_response(err),
        };
        deep_health_res.insert(tenant.clone(), response);
    }
    services::http_response_json(
        serde_json::to_string(&deep_health_res)
            .map_err(|err| {
                logger::error!(serialization_error=?err);
            })
            .unwrap_or_default(),
    )
}

#[instrument(skip_all)]
pub async fn deep_health_check_func(
    conf: web::Data<Settings>,
    store: &Arc<Store>,
) -> Result<DrainerHealthCheckResponse, error_stack::Report<HealthCheckError>> {
    logger::info!("Deep health check was called");

    logger::debug!("Database health check begin");

    let db_status = store
        .health_check_db()
        .await
        .map(|_| true)
        .map_err(|error| {
            let message = error.to_string();
            error.change_context(HealthCheckError::DbError { message })
        })?;

    logger::debug!("Database health check end");

    logger::debug!("Redis health check begin");

    let redis_status = store
        .health_check_redis(&conf.into_inner())
        .await
        .map(|_| true)
        .map_err(|error| {
            let message = error.to_string();
            error.change_context(HealthCheckError::RedisError { message })
        })?;

    logger::debug!("Redis health check end");

    Ok(DrainerHealthCheckResponse {
        database: db_status,
        redis: redis_status,
    })
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DrainerHealthCheckResponse {
    pub database: bool,
    pub redis: bool,
}

#[async_trait::async_trait]
pub trait HealthCheckInterface {
    async fn health_check_db(&self) -> CustomResult<(), HealthCheckDBError>;
    async fn health_check_redis(&self, conf: &Settings) -> CustomResult<(), HealthCheckRedisError>;
}

#[async_trait::async_trait]
impl HealthCheckInterface for Store {
    async fn health_check_db(&self) -> CustomResult<(), HealthCheckDBError> {
        let conn = pg_connection(&self.master_pool).await;

        conn
            .transaction_async(|conn| {
                Box::pin(async move {
                    let query =
                        diesel::select(diesel::dsl::sql::<diesel::sql_types::Integer>("1 + 1"));
                    let _x: i32 = query.get_result_async(&conn).await.map_err(|err| {
                        logger::error!(read_err=?err,"Error while reading element in the database");
                        HealthCheckDBError::DbReadError
                    })?;

                    logger::debug!("Database read was successful");

                    let config = ConfigNew {
                        key: "test_key".to_string(),
                        config: "test_value".to_string(),
                    };

                    config.insert(&conn).await.map_err(|err| {
                        logger::error!(write_err=?err,"Error while writing to database");
                        HealthCheckDBError::DbWriteError
                    })?;

                    logger::debug!("Database write was successful");

                    Config::delete_by_key(&conn, "test_key").await.map_err(|err| {
                        logger::error!(delete_err=?err,"Error while deleting element in the database");
                        HealthCheckDBError::DbDeleteError
                    })?;

                    logger::debug!("Database delete was successful");

                    Ok::<_, HealthCheckDBError>(())
                })
            })
            .await?;

        Ok(())
    }

    async fn health_check_redis(
        &self,
        _conf: &Settings,
    ) -> CustomResult<(), HealthCheckRedisError> {
        let redis_conn = self.redis_conn.clone();

        redis_conn
            .serialize_and_set_key_with_expiry(&"test_key".into(), "test_value", 30)
            .await
            .change_context(HealthCheckRedisError::SetFailed)?;

        logger::debug!("Redis set_key was successful");

        redis_conn
            .get_key::<()>(&"test_key".into())
            .await
            .change_context(HealthCheckRedisError::GetFailed)?;

        logger::debug!("Redis get_key was successful");

        redis_conn
            .delete_key(&"test_key".into())
            .await
            .change_context(HealthCheckRedisError::DeleteFailed)?;

        logger::debug!("Redis delete_key was successful");

        redis_conn
            .stream_append_entry(
                &TEST_STREAM_NAME.into(),
                &redis_interface::RedisEntryId::AutoGeneratedID,
                TEST_STREAM_DATA.to_vec(),
            )
            .await
            .change_context(HealthCheckRedisError::StreamAppendFailed)?;

        logger::debug!("Stream append succeeded");

        let output = redis_conn
            .stream_read_entries(TEST_STREAM_NAME, "0-0", Some(10))
            .await
            .change_context(HealthCheckRedisError::StreamReadFailed)?;
        logger::debug!("Stream read succeeded");

        let (_, id_to_trim) = output
            .get(&redis_conn.add_prefix(TEST_STREAM_NAME))
            .and_then(|entries| {
                entries
                    .last()
                    .map(|last_entry| (entries, last_entry.0.clone()))
            })
            .ok_or(error_stack::report!(
                HealthCheckRedisError::StreamReadFailed
            ))?;
        logger::debug!("Stream parse succeeded");

        redis_conn
            .stream_trim_entries(
                &TEST_STREAM_NAME.into(),
                (
                    redis_interface::StreamCapKind::MinID,
                    redis_interface::StreamCapTrim::Exact,
                    id_to_trim,
                ),
            )
            .await
            .change_context(HealthCheckRedisError::StreamTrimFailed)?;
        logger::debug!("Stream trim succeeded");

        Ok(())
    }
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, thiserror::Error)]
pub enum HealthCheckDBError {
    #[error("Error while connecting to database")]
    DbError,
    #[error("Error while writing to database")]
    DbWriteError,
    #[error("Error while reading element in the database")]
    DbReadError,
    #[error("Error while deleting element in the database")]
    DbDeleteError,
    #[error("Unpredictable error occurred")]
    UnknownError,
    #[error("Error in database transaction")]
    TransactionError,
}

impl From<diesel::result::Error> for HealthCheckDBError {
    fn from(error: diesel::result::Error) -> Self {
        match error {
            diesel::result::Error::DatabaseError(_, _) => Self::DbError,

            diesel::result::Error::RollbackErrorOnCommit { .. }
            | diesel::result::Error::RollbackTransaction
            | diesel::result::Error::AlreadyInTransaction
            | diesel::result::Error::NotInTransaction
            | diesel::result::Error::BrokenTransactionManager => Self::TransactionError,

            _ => Self::UnknownError,
        }
    }
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, thiserror::Error)]
pub enum HealthCheckRedisError {
    #[error("Failed to set key value in Redis")]
    SetFailed,
    #[error("Failed to get key value in Redis")]
    GetFailed,
    #[error("Failed to delete key value in Redis")]
    DeleteFailed,
    #[error("Failed to append data to the stream in Redis")]
    StreamAppendFailed,
    #[error("Failed to read data from the stream in Redis")]
    StreamReadFailed,
    #[error("Failed to trim data from the stream in Redis")]
    StreamTrimFailed,
}


// Implementation: impl ConnectorAuthTypeValidation
// File: crates/router/src/core/connector_validation.rs
// Module: router
// Methods: 1 total (0 public)

impl ConnectorAuthTypeValidation


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

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


// File: crates/common_enums/src/enums.rs
// Module: common_enums
// Public functions: 35
// Public structs: 1

mod accounts;
mod payments;
mod ui;
use std::{
    collections::HashSet,
    num::{ParseFloatError, TryFromIntError},
};

pub use accounts::{
    MerchantAccountRequestType, MerchantAccountType, MerchantProductType, OrganizationType,
};
pub use payments::ProductType;
use serde::{Deserialize, Serialize};
pub use ui::*;
use utoipa::ToSchema;

pub use super::connector_enums::RoutableConnectors;
#[doc(hidden)]
pub mod diesel_exports {
    pub use super::{
        DbApiVersion as ApiVersion, DbAttemptStatus as AttemptStatus,
        DbAuthenticationType as AuthenticationType, DbBlocklistDataKind as BlocklistDataKind,
        DbCaptureMethod as CaptureMethod, DbCaptureStatus as CaptureStatus,
        DbConnectorType as ConnectorType, DbCountryAlpha2 as CountryAlpha2, DbCurrency as Currency,
        DbDeleteStatus as DeleteStatus, DbDisputeStage as DisputeStage,
        DbDisputeStatus as DisputeStatus, DbFraudCheckStatus as FraudCheckStatus,
        DbFutureUsage as FutureUsage, DbIntentStatus as IntentStatus,
        DbMandateStatus as MandateStatus, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode,
        DbPaymentType as PaymentType, DbProcessTrackerStatus as ProcessTrackerStatus,
        DbRefundStatus as RefundStatus,
        DbRequestIncrementalAuthorization as RequestIncrementalAuthorization,
        DbRoutingApproach as RoutingApproach, DbScaExemptionType as ScaExemptionType,
        DbSuccessBasedRoutingConclusiveState as SuccessBasedRoutingConclusiveState,
        DbTokenizationFlag as TokenizationFlag, DbWebhookDeliveryAttempt as WebhookDeliveryAttempt,
    };
}

pub type ApplicationResult<T> = Result<T, ApplicationError>;

#[derive(Debug, thiserror::Error)]
pub enum ApplicationError {
    #[error("Application configuration error")]
    ConfigurationError,

    #[error("Invalid configuration value provided: {0}")]
    InvalidConfigurationValueError(String),

    #[error("Metrics error")]
    MetricsError,

    #[error("I/O: {0}")]
    IoError(std::io::Error),

    #[error("Error while constructing api client: {0}")]
    ApiClientError(ApiClientError),
}

#[derive(Debug, thiserror::Error, PartialEq, Clone)]
pub enum ApiClientError {
    #[error("Header map construction failed")]
    HeaderMapConstructionFailed,
    #[error("Invalid proxy configuration")]
    InvalidProxyConfiguration,
    #[error("Client construction failed")]
    ClientConstructionFailed,
    #[error("Certificate decode failed")]
    CertificateDecodeFailed,
    #[error("Request body serialization failed")]
    BodySerializationFailed,
    #[error("Unexpected state reached/Invariants conflicted")]
    UnexpectedState,

    #[error("Failed to parse URL")]
    UrlParsingFailed,
    #[error("URL encoding of request payload failed")]
    UrlEncodingFailed,
    #[error("Failed to send request to connector {0}")]
    RequestNotSent(String),
    #[error("Failed to decode response")]
    ResponseDecodingFailed,

    #[error("Server responded with Request Timeout")]
    RequestTimeoutReceived,

    #[error("connection closed before a message could complete")]
    ConnectionClosedIncompleteMessage,

    #[error("Server responded with Internal Server Error")]
    InternalServerErrorReceived,
    #[error("Server responded with Bad Gateway")]
    BadGatewayReceived,
    #[error("Server responded with Service Unavailable")]
    ServiceUnavailableReceived,
    #[error("Server responded with Gateway Timeout")]
    GatewayTimeoutReceived,
    #[error("Server responded with unexpected response")]
    UnexpectedServerResponse,
}
impl ApiClientError {
    pub fn is_upstream_timeout(&self) -> bool {
        self == &Self::RequestTimeoutReceived
    }
    pub fn is_connection_closed_before_message_could_complete(&self) -> bool {
        self == &Self::ConnectionClosedIncompleteMessage
    }
}

impl From<std::io::Error> for ApplicationError {
    fn from(err: std::io::Error) -> Self {
        Self::IoError(err)
    }
}

/// The status of the attempt
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Hash,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AttemptStatus {
    Started,
    AuthenticationFailed,
    RouterDeclined,
    AuthenticationPending,
    AuthenticationSuccessful,
    Authorized,
    AuthorizationFailed,
    Charged,
    Authorizing,
    CodInitiated,
    Voided,
    VoidedPostCharge,
    VoidInitiated,
    CaptureInitiated,
    CaptureFailed,
    VoidFailed,
    AutoRefunded,
    PartialCharged,
    PartiallyAuthorized,
    PartialChargedAndChargeable,
    Unresolved,
    #[default]
    Pending,
    Failure,
    PaymentMethodAwaited,
    ConfirmationAwaited,
    DeviceDataCollectionPending,
    IntegrityFailure,
    Expired,
}

impl AttemptStatus {
    pub fn is_terminal_status(self) -> bool {
        match self {
            Self::RouterDeclined
            | Self::Charged
            | Self::AutoRefunded
            | Self::Voided
            | Self::VoidedPostCharge
            | Self::VoidFailed
            | Self::CaptureFailed
            | Self::Failure
            | Self::PartialCharged
            | Self::Expired => true,
            Self::Started
            | Self::AuthenticationFailed
            | Self::AuthenticationPending
            | Self::AuthenticationSuccessful
            | Self::Authorized
            | Self::PartiallyAuthorized
            | Self::AuthorizationFailed
            | Self::Authorizing
            | Self::CodInitiated
            | Self::VoidInitiated
            | Self::CaptureInitiated
            | Self::PartialChargedAndChargeable
            | Self::Unresolved
            | Self::Pending
            | Self::PaymentMethodAwaited
            | Self::ConfirmationAwaited
            | Self::DeviceDataCollectionPending
            | Self::IntegrityFailure => false,
        }
    }

    pub fn is_success(self) -> bool {
        matches!(self, Self::Charged | Self::PartialCharged)
    }
}

#[derive(
    Clone,
    Copy,
    Debug,
    Hash,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    strum::EnumIter,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ApplePayPaymentMethodType {
    Debit,
    Credit,
    Prepaid,
    Store,
}

/// Indicates the method by which a card is discovered during a payment
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Hash,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    strum::EnumIter,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum CardDiscovery {
    #[default]
    Manual,
    SavedCard,
    ClickToPay,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Hash,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    strum::EnumIter,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RevenueRecoveryAlgorithmType {
    #[default]
    Monitoring,
    Smart,
    Cascading,
}

#[derive(
    Default,
    Clone,
    Copy,
    Debug,
    strum::Display,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum GsmDecision {
    Retry,
    #[default]
    DoDefault,
}

#[derive(
    Clone,
    Copy,
    Debug,
    strum::Display,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[router_derive::diesel_enum(storage_type = "text")]
pub enum GsmFeature {
    Retry,
}

/// Specifies the type of cardholder authentication to be applied for a payment.
///
/// - `ThreeDs`: Requests 3D Secure (3DS) authentication. If the card is enrolled, 3DS authentication will be activated, potentially shifting chargeback liability to the issuer.
/// - `NoThreeDs`: Indicates that 3D Secure authentication should not be performed. The liability for chargebacks typically remains with the merchant. This is often the default if not specified.
///
/// Note: The actual authentication behavior can also be influenced by merchant configuration and specific connector defaults. Some connectors might still enforce 3DS or bypass it regardless of this parameter.
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::VariantNames,
    strum::EnumIter,
    strum::EnumString,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthenticationType {
    /// If the card is enrolled for 3DS authentication, the 3DS based authentication will be activated. The liability of chargeback shift to the issuer
    ThreeDs,
    /// 3DS based authentication will not be activated. The liability of chargeback stays with the merchant.
    #[default]
    NoThreeDs,
}

/// The status of the capture
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[strum(serialize_all = "snake_case")]
pub enum FraudCheckStatus {
    Fraud,
    ManualReview,
    #[default]
    Pending,
    Legit,
    TransactionFailure,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum CaptureStatus {
    // Capture request initiated
    #[default]
    Started,
    // Capture request was successful
    Charged,
    // Capture is pending at connector side
    Pending,
    // Capture request failed
    Failed,
}

#[derive(
    Default,
    Clone,
    Debug,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthorizationStatus {
    Success,
    Failure,
    // Processing state is before calling connector
    #[default]
    Processing,
    // Requires merchant action
    Unresolved,
}

#[derive(
    Clone,
    Debug,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PaymentResourceUpdateStatus {
    Success,
    Failure,
}

impl PaymentResourceUpdateStatus {
    pub fn is_success(&self) -> bool {
        matches!(self, Self::Success)
    }
}

#[derive(
    Clone,
    Debug,
    PartialEq,
    Eq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum BlocklistDataKind {
    PaymentMethod,
    CardBin,
    ExtendedCardBin,
}

/// Specifies how the payment is captured.
/// - `automatic`: Funds are captured immediately after successful authorization. This is the default behavior if the field is omitted.
/// - `manual`: Funds are authorized but not captured. A separate request to the `/payments/{payment_id}/capture` endpoint is required to capture the funds.
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::VariantNames,
    strum::EnumIter,
    strum::EnumString,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum CaptureMethod {
    /// Post the payment authorization, the capture will be executed on the full amount immediately.
    #[default]
    Automatic,
    /// The capture will happen only if the merchant triggers a Capture API request. Allows for a single capture of the authorized amount.
    Manual,
    /// The capture will happen only if the merchant triggers a Capture API request. Allows for multiple partial captures up to the authorized amount.
    ManualMultiple,
    /// The capture can be scheduled to automatically get triggered at a specific date & time.
    Scheduled,
    /// Handles separate auth and capture sequentially; effectively the same as `Automatic` for most connectors.
    SequentialAutomatic,
}

/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    PartialEq,
    strum::Display,
    strum::EnumString,
    serde::Deserialize,
    serde::Serialize,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum ConnectorType {
    /// PayFacs, Acquirers, Gateways, BNPL etc
    PaymentProcessor,
    /// Fraud, Currency Conversion, Crypto etc
    PaymentVas,
    /// Accounting, Billing, Invoicing, Tax etc
    FinOperations,
    /// Inventory, ERP, CRM, KYC etc
    FizOperations,
    /// Payment Networks like Visa, MasterCard etc
    Networks,
    /// All types of banks including corporate / commercial / personal / neo banks
    BankingEntities,
    /// All types of non-banking financial institutions including Insurance, Credit / Lending etc
    NonBankingFinance,
    /// Acquirers, Gateways etc
    PayoutProcessor,
    /// PaymentMethods Auth Services
    PaymentMethodAuth,
    /// 3DS Authentication Service Providers
    AuthenticationProcessor,
    /// Tax Calculation Processor
    TaxProcessor,
    /// Represents billing processors that handle subscription management, invoicing,
    /// and recurring payments. Examples include Chargebee, Recurly, and Stripe Billing.
    BillingProcessor,
    /// Represents vaulting processors that handle the storage and management of payment method data
    VaultProcessor,
}

#[derive(Debug, Eq, PartialEq)]
pub enum PaymentAction {
    PSync,
    CompleteAuthorize,
    PaymentAuthenticateCompleteAuthorize,
}

#[derive(Clone, PartialEq)]
pub enum CallConnectorAction {
    Trigger,
    Avoid,
    StatusUpdate {
        status: AttemptStatus,
        error_code: Option<String>,
        error_message: Option<String>,
    },
    HandleResponse(Vec<u8>),
    UCSHandleResponse(Vec<u8>),
}

#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::VariantNames,
    strum::EnumIter,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "UPPERCASE")]
pub enum DocumentKind {
    Cnpj,
    Cpf,
}

/// The three-letter ISO 4217 currency code (e.g., "USD", "EUR") for the payment amount. This field is mandatory for creating a payment.
#[allow(clippy::upper_case_acronyms)]
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    strum::EnumIter,
    strum::VariantNames,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
pub enum Currency {
    AED,
    AFN,
    ALL,
    AMD,
    ANG,
    AOA,
    ARS,
    AUD,
    AWG,
    AZN,
    BAM,
    BBD,
    BDT,
    BGN,
    BHD,
    BIF,
    BMD,
    BND,
    BOB,
    BRL,
    BSD,
    BTN,
    BWP,
    BYN,
    BZD,
    CAD,
    CDF,
    CHF,
    CLF,
    CLP,
    CNY,
    COP,
    CRC,
    CUC,
    CUP,
    CVE,
    CZK,
    DJF,
    DKK,
    DOP,
    DZD,
    EGP,
    ERN,
    ETB,
    EUR,
    FJD,
    FKP,
    GBP,
    GEL,
    GHS,
    GIP,
    GMD,
    GNF,
    GTQ,
    GYD,
    HKD,
    HNL,
    HRK,
    HTG,
    HUF,
    IDR,
    ILS,
    INR,
    IQD,
    IRR,
    ISK,
    JMD,
    JOD,
    JPY,
    KES,
    KGS,
    KHR,
    KMF,
    KPW,
    KRW,
    KWD,
    KYD,
    KZT,
    LAK,
    LBP,
    LKR,
    LRD,
    LSL,
    LYD,
    MAD,
    MDL,
    MGA,
    MKD,
    MMK,
    MNT,
    MOP,
    MRU,
    MUR,
    MVR,
    MWK,
    MXN,
    MYR,
    MZN,
    NAD,
    NGN,
    NIO,
    NOK,
    NPR,
    NZD,
    OMR,
    PAB,
    PEN,
    PGK,
    PHP,
    PKR,
    PLN,
    PYG,
    QAR,
    RON,
    RSD,
    RUB,
    RWF,
    SAR,
    SBD,
    SCR,
    SDG,
    SEK,
    SGD,
    SHP,
    SLE,
    SLL,
    SOS,
    SRD,
    SSP,
    STD,
    STN,
    SVC,
    SYP,
    SZL,
    THB,
    TJS,
    TMT,
    TND,
    TOP,
    TRY,
    TTD,
    TWD,
    TZS,
    UAH,
    UGX,
    #[default]
    USD,
    UYU,
    UZS,
    VES,
    VND,
    VUV,
    WST,
    XAF,
    XCD,
    XOF,
    XPF,
    YER,
    ZAR,
    ZMW,
    ZWL,
}

impl Currency {
    /// Convert the amount to its base denomination based on Currency and return String
    pub fn to_currency_base_unit(self, amount: i64) -> Result<String, TryFromIntError> {
        let amount_f64 = self.to_currency_base_unit_asf64(amount)?;
        Ok(format!("{amount_f64:.2}"))
    }

    /// Convert the amount to its base denomination based on Currency and return f64
    pub fn to_currency_base_unit_asf64(self, amount: i64) -> Result<f64, TryFromIntError> {
        let amount_f64: f64 = u32::try_from(amount)?.into();
        let amount = if self.is_zero_decimal_currency() {
            amount_f64
        } else if self.is_three_decimal_currency() {
            amount_f64 / 1000.00
        } else {
            amount_f64 / 100.00
        };
        Ok(amount)
    }

    ///Convert the higher decimal amount to its base absolute units
    pub fn to_currency_lower_unit(self, amount: String) -> Result<String, ParseFloatError> {
        let amount_f64 = amount.parse::<f64>()?;
        let amount_string = if self.is_zero_decimal_currency() {
            amount_f64
        } else if self.is_three_decimal_currency() {
            amount_f64 * 1000.00
        } else {
            amount_f64 * 100.00
        };
        Ok(amount_string.to_string())
    }

    /// Convert the amount to its base denomination based on Currency and check for zero decimal currency and return String
    /// Paypal Connector accepts Zero and Two decimal currency but not three decimal and it should be updated as required for 3 decimal currencies.
    /// Paypal Ref - https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/
    pub fn to_currency_base_unit_with_zero_decimal_check(
        self,
        amount: i64,
    ) -> Result<String, TryFromIntError> {
        let amount_f64 = self.to_currency_base_unit_asf64(amount)?;
        if self.is_zero_decimal_currency() {
            Ok(amount_f64.to_string())
        } else {
            Ok(format!("{amount_f64:.2}"))
        }
    }

    pub fn iso_4217(self) -> &'static str {
        match self {
            Self::AED => "784",
            Self::AFN => "971",
            Self::ALL => "008",
            Self::AMD => "051",
            Self::ANG => "532",
            Self::AOA => "973",
            Self::ARS => "032",
            Self::AUD => "036",
            Self::AWG => "533",
            Self::AZN => "944",
            Self::BAM => "977",
            Self::BBD => "052",
            Self::BDT => "050",
            Self::BGN => "975",
            Self::BHD => "048",
            Self::BIF => "108",
            Self::BMD => "060",
            Self::BND => "096",
            Self::BOB => "068",
            Self::BRL => "986",
            Self::BSD => "044",
            Self::BTN => "064",
            Self::BWP => "072",
            Self::BYN => "933",
            Self::BZD => "084",
            Self::CAD => "124",
            Self::CDF => "976",
            Self::CHF => "756",
            Self::CLF => "990",
            Self::CLP => "152",
            Self::COP => "170",
            Self::CRC => "188",
            Self::CUC => "931",
            Self::CUP => "192",
            Self::CVE => "132",
            Self::CZK => "203",
            Self::DJF => "262",
            Self::DKK => "208",
            Self::DOP => "214",
            Self::DZD => "012",
            Self::EGP => "818",
            Self::ERN => "232",
            Self::ETB => "230",
            Self::EUR => "978",
            Self::FJD => "242",
            Self::FKP => "238",
            Self::GBP => "826",
            Self::GEL => "981",
            Self::GHS => "936",
            Self::GIP => "292",
            Self::GMD => "270",
            Self::GNF => "324",
            Self::GTQ => "320",
            Self::GYD => "328",
            Self::HKD => "344",
            Self::HNL => "340",
            Self::HTG => "332",
            Self::HUF => "348",
            Self::HRK => "191",
            Self::IDR => "360",
            Self::ILS => "376",
            Self::INR => "356",
            Self::IQD => "368",
            Self::IRR => "364",
            Self::ISK => "352",
            Self::JMD => "388",
            Self::JOD => "400",
            Self::JPY => "392",
            Self::KES => "404",
            Self::KGS => "417",
            Self::KHR => "116",
            Self::KMF => "174",
            Self::KPW => "408",
            Self::KRW => "410",
            Self::KWD => "414",
            Self::KYD => "136",
            Self::KZT => "398",
            Self::LAK => "418",
            Self::LBP => "422",
            Self::LKR => "144",
            Self::LRD => "430",
            Self::LSL => "426",
            Self::LYD => "434",
            Self::MAD => "504",
            Self::MDL => "498",
            Self::MGA => "969",
            Self::MKD => "807",
            Self::MMK => "104",
            Self::MNT => "496",
            Self::MOP => "446",
            Self::MRU => "929",
            Self::MUR => "480",
            Self::MVR => "462",
            Self::MWK => "454",
            Self::MXN => "484",
            Self::MYR => "458",
            Self::MZN => "943",
            Self::NAD => "516",
            Self::NGN => "566",
            Self::NIO => "558",
            Self::NOK => "578",
            Self::NPR => "524",
            Self::NZD => "554",
            Self::OMR => "512",
            Self::PAB => "590",
            Self::PEN => "604",
            Self::PGK => "598",
            Self::PHP => "608",
            Self::PKR => "586",
            Self::PLN => "985",
            Self::PYG => "600",
            Self::QAR => "634",
            Self::RON => "946",
            Self::CNY => "156",
            Self::RSD => "941",
            Self::RUB => "643",
            Self::RWF => "646",
            Self::SAR => "682",
            Self::SBD => "090",
            Self::SCR => "690",
            Self::SDG => "938",
            Self::SEK => "752",
            Self::SGD => "702",
            Self::SHP => "654",
            Self::SLE => "925",
            Self::SLL => "694",
            Self::SOS => "706",
            Self::SRD => "968",
            Self::SSP => "728",
            Self::STD => "678",
            Self::STN => "930",
            Self::SVC => "222",
            Self::SYP => "760",
            Self::SZL => "748",
            Self::THB => "764",
            Self::TJS => "972",
            Self::TMT => "934",
            Self::TND => "788",
            Self::TOP => "776",
            Self::TRY => "949",
            Self::TTD => "780",
            Self::TWD => "901",
            Self::TZS => "834",
            Self::UAH => "980",
            Self::UGX => "800",
            Self::USD => "840",
            Self::UYU => "858",
            Self::UZS => "860",
            Self::VES => "928",
            Self::VND => "704",
            Self::VUV => "548",
            Self::WST => "882",
            Self::XAF => "950",
            Self::XCD => "951",
            Self::XOF => "952",
            Self::XPF => "953",
            Self::YER => "886",
            Self::ZAR => "710",
            Self::ZMW => "967",
            Self::ZWL => "932",
        }
    }

    pub fn is_zero_decimal_currency(self) -> bool {
        match self {
            Self::BIF
            | Self::CLP
            | Self::DJF
            | Self::GNF
            | Self::IRR
            | Self::JPY
            | Self::KMF
            | Self::KRW
            | Self::MGA
            | Self::PYG
            | Self::RWF
            | Self::UGX
            | Self::VND
            | Self::VUV
            | Self::XAF
            | Self::XOF
            | Self::XPF => true,
            Self::AED
            | Self::AFN
            | Self::ALL
            | Self::AMD
            | Self::ANG
            | Self::AOA
            | Self::ARS
            | Self::AUD
            | Self::AWG
            | Self::AZN
            | Self::BAM
            | Self::BBD
            | Self::BDT
            | Self::BGN
            | Self::BHD
            | Self::BMD
            | Self::BND
            | Self::BOB
            | Self::BRL
            | Self::BSD
            | Self::BTN
            | Self::BWP
            | Self::BYN
            | Self::BZD
            | Self::CAD
            | Self::CDF
            | Self::CHF
            | Self::CLF
            | Self::CNY
            | Self::COP
            | Self::CRC
            | Self::CUC
            | Self::CUP
            | Self::CVE
            | Self::CZK
            | Self::DKK
            | Self::DOP
            | Self::DZD
            | Self::EGP
            | Self::ERN
            | Self::ETB
            | Self::EUR
            | Self::FJD
            | Self::FKP
            | Self::GBP
            | Self::GEL
            | Self::GHS
            | Self::GIP
            | Self::GMD
            | Self::GTQ
            | Self::GYD
            | Self::HKD
            | Self::HNL
            | Self::HRK
            | Self::HTG
            | Self::HUF
            | Self::IDR
            | Self::ILS
            | Self::INR
            | Self::IQD
            | Self::ISK
            | Self::JMD
            | Self::JOD
            | Self::KES
            | Self::KGS
            | Self::KHR
            | Self::KPW
            | Self::KWD
            | Self::KYD
            | Self::KZT
            | Self::LAK
            | Self::LBP
            | Self::LKR
            | Self::LRD
            | Self::LSL
            | Self::LYD
            | Self::MAD
            | Self::MDL
            | Self::MKD
            | Self::MMK
            | Self::MNT
            | Self::MOP
            | Self::MRU
            | Self::MUR
            | Self::MVR
            | Self::MWK
            | Self::MXN
            | Self::MYR
            | Self::MZN
            | Self::NAD
            | Self::NGN
            | Self::NIO
            | Self::NOK
            | Self::NPR
            | Self::NZD
            | Self::OMR
            | Self::PAB
            | Self::PEN
            | Self::PGK
            | Self::PHP
            | Self::PKR
            | Self::PLN
            | Self::QAR
            | Self::RON
            | Self::RSD
            | Self::RUB
            | Self::SAR
            | Self::SBD
            | Self::SCR
            | Self::SDG
            | Self::SEK
            | Self::SGD
            | Self::SHP
            | Self::SLE
            | Self::SLL
            | Self::SOS
            | Self::SRD
            | Self::SSP
            | Self::STD
            | Self::STN
            | Self::SVC
            | Self::SYP
            | Self::SZL
            | Self::THB
            | Self::TJS
            | Self::TMT
            | Self::TND
            | Self::TOP
            | Self::TRY
            | Self::TTD
            | Self::TWD
            | Self::TZS
            | Self::UAH
            | Self::USD
            | Self::UYU
            | Self::UZS
            | Self::VES
            | Self::WST
            | Self::XCD
            | Self::YER
            | Self::ZAR
            | Self::ZMW
            | Self::ZWL => false,
        }
    }

    pub fn is_three_decimal_currency(self) -> bool {
        match self {
            Self::BHD | Self::IQD | Self::JOD | Self::KWD | Self::LYD | Self::OMR | Self::TND => {
                true
            }
            Self::AED
            | Self::AFN
            | Self::ALL
            | Self::AMD
            | Self::AOA
            | Self::ANG
            | Self::ARS
            | Self::AUD
            | Self::AWG
            | Self::AZN
            | Self::BAM
            | Self::BBD
            | Self::BDT
            | Self::BGN
            | Self::BIF
            | Self::BMD
            | Self::BND
            | Self::BOB
            | Self::BRL
            | Self::BSD
            | Self::BTN
            | Self::BWP
            | Self::BYN
            | Self::BZD
            | Self::CAD
            | Self::CDF
            | Self::CHF
            | Self::CLF
            | Self::CLP
            | Self::CNY
            | Self::COP
            | Self::CRC
            | Self::CUC
            | Self::CUP
            | Self::CVE
            | Self::CZK
            | Self::DJF
            | Self::DKK
            | Self::DOP
            | Self::DZD
            | Self::EGP
            | Self::ERN
            | Self::ETB
            | Self::EUR
            | Self::FJD
            | Self::FKP
            | Self::GBP
            | Self::GEL


// Function: log_and_return_error_response
// File: crates/drainer/src/services.rs
// Module: drainer

pub fn log_and_return_error_response<T>(error: Report<T>) -> HttpResponse
where
    T: error_stack::Context + ResponseError + Clone,


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

pub fn get_mca_status(
    state: &routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    profile_id: Option<id_type::ProfileId>,
    merchant_id: &id_type::MerchantId,
    is_connector_agnostic_mit_enabled: bool,
    connector_mandate_details: Option<CommonMandateReference>,
    network_transaction_id: Option<&String>,
) -> errors::RouterResult<Option<bool>>


// Function: third_party_sdk_session_next_action
// File: crates/router/src/core/payments/transformers.rs
// Module: router

pub fn third_party_sdk_session_next_action<Op>(
    payment_attempt: &storage::PaymentAttempt,
    operation: &Op,
) -> bool
where
    Op: Debug,


// Struct: WebhookSourceVerifyData
// File: crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct WebhookSourceVerifyData


// Struct: ProphetpaySyncRequest
// File: crates/hyperswitch_connectors/src/connectors/prophetpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ProphetpaySyncRequest


// Implementation: impl Parse for for SchemaParameterVariant
// File: crates/router_derive/src/macros/schema/helpers.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl Parse for for SchemaParameterVariant


// Implementation: impl Capturable for for PaymentsUpdateMetadataData
// File: crates/router/src/types.rs
// Module: router
// Methods: 0 total (0 public)

impl Capturable for for PaymentsUpdateMetadataData


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

pub struct PaypalZeroMandateRequest


// File: crates/analytics/src/enums.rs
// Module: analytics

pub use common_utils::types::authentication::AuthInfo;


// Implementation: impl DieselEnumMeta
// File: crates/router_derive/src/macros/diesel.rs
// Module: router_derive
// Methods: 1 total (1 public)

impl DieselEnumMeta


// Struct: Checkout
// File: crates/hyperswitch_connectors/src/connectors/checkout.rs
// Module: hyperswitch_connectors
// Implementations: 26
// Traits: ConnectorCommon, ConnectorValidation, api::Payment, api::PaymentAuthorize, api::PaymentSync, api::PaymentVoid, api::PaymentCapture, api::PaymentSession, api::ConnectorAccessToken, AcceptDispute, api::PaymentToken, Dispute, RetrieveFile, DefendDispute, MandateSetup, api::Refund, api::RefundExecute, api::RefundSync, UploadFile, FileUpload, SubmitEvidence, webhooks::IncomingWebhook, api::ConnectorRedirectResponse, utils::ConnectorErrorTypeMapping, ConnectorSpecifications

pub struct Checkout

ConnectorCommon ConnectorValidation api::Payment api::PaymentAuthorize api::PaymentSync api::PaymentVoid api::PaymentCapture api::PaymentSession api::ConnectorAccessToken AcceptDispute api::PaymentToken Dispute RetrieveFile DefendDispute MandateSetup api::Refund api::RefundExecute api::RefundSync UploadFile FileUpload SubmitEvidence webhooks::IncomingWebhook api::ConnectorRedirectResponse utils::ConnectorErrorTypeMapping ConnectorSpecifications