// File: crates/router/src/core/payments/flows.rs
// Module: router
// Public functions: 2

pub mod approve_flow;
pub mod authorize_flow;
pub mod cancel_flow;
pub mod cancel_post_capture_flow;
pub mod capture_flow;
pub mod complete_authorize_flow;
#[cfg(feature = "v2")]
pub mod external_proxy_flow;
pub mod incremental_authorization_flow;
pub mod post_session_tokens_flow;
pub mod psync_flow;
pub mod reject_flow;
pub mod session_flow;
pub mod session_update_flow;
pub mod setup_mandate_flow;
pub mod update_metadata_flow;

use async_trait::async_trait;
use common_types::payments::CustomerAcceptance;
use external_services::grpc_client;
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
use hyperswitch_domain_models::router_flow_types::{
    BillingConnectorInvoiceSync, BillingConnectorPaymentsSync, InvoiceRecordBack,
};
use hyperswitch_domain_models::{
    payments as domain_payments, router_request_types::PaymentsCaptureData,
};

use crate::{
    core::{
        errors::{ApiErrorResponse, RouterResult},
        payments::{self, helpers},
    },
    logger,
    routes::SessionState,
    services, types as router_types,
    types::{self, api, api::enums as api_enums, domain},
};

#[async_trait]
#[allow(clippy::too_many_arguments)]
pub trait ConstructFlowSpecificData<F, Req, Res> {
    #[cfg(feature = "v1")]
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<domain_payments::HeaderPayload>,
    ) -> RouterResult<types::RouterData<F, Req, Res>>;

    #[cfg(feature = "v2")]
    async fn construct_router_data<'a>(
        &self,
        _state: &SessionState,
        _connector_id: &str,
        _merchant_context: &domain::MerchantContext,
        _customer: &Option<domain::Customer>,
        _merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
        _merchant_recipient_data: Option<types::MerchantRecipientData>,
        _header_payload: Option<domain_payments::HeaderPayload>,
    ) -> RouterResult<types::RouterData<F, Req, Res>>;

    async fn get_merchant_recipient_data<'a>(
        &self,
        _state: &SessionState,
        _merchant_context: &domain::MerchantContext,
        _merchant_connector_account: &helpers::MerchantConnectorAccountType,
        _connector: &api::ConnectorData,
    ) -> RouterResult<Option<types::MerchantRecipientData>> {
        Ok(None)
    }
}

#[allow(clippy::too_many_arguments)]
#[async_trait]
pub trait Feature<F, T> {
    async fn decide_flows<'a>(
        self,
        state: &SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
        connector_request: Option<services::Request>,
        business_profile: &domain::Profile,
        header_payload: domain_payments::HeaderPayload,
        return_raw_connector_response: Option<bool>,
    ) -> RouterResult<Self>
    where
        Self: Sized,
        F: Clone,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>;

    async fn add_access_token<'a>(
        &self,
        state: &SessionState,
        connector: &api::ConnectorData,
        merchant_context: &domain::MerchantContext,
        creds_identifier: Option<&str>,
    ) -> RouterResult<types::AddAccessTokenResult>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>;

    async fn add_session_token<'a>(
        self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
    ) -> RouterResult<Self>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(self)
    }

    async fn add_payment_method_token<'a>(
        &mut self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
        _tokenization_action: &payments::TokenizationAction,
        _should_continue_payment: bool,
    ) -> RouterResult<types::PaymentMethodTokenResult>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(types::PaymentMethodTokenResult {
            payment_method_token_result: Ok(None),
            is_payment_method_tokenization_performed: false,
            connector_response: None,
        })
    }

    async fn preprocessing_steps<'a>(
        self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
    ) -> RouterResult<Self>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(self)
    }

    async fn postprocessing_steps<'a>(
        self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
    ) -> RouterResult<Self>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(self)
    }

    async fn create_connector_customer<'a>(
        &self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
    ) -> RouterResult<Option<String>>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(None)
    }

    /// Returns the connector request and a bool which specifies whether to proceed with further
    async fn build_flow_specific_connector_request(
        &mut self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
        _call_connector_action: payments::CallConnectorAction,
    ) -> RouterResult<(Option<services::Request>, bool)> {
        Ok((None, true))
    }

    async fn create_order_at_connector(
        &mut self,
        _state: &SessionState,
        _connector: &api::ConnectorData,
        _should_continue_payment: bool,
    ) -> RouterResult<Option<types::CreateOrderResult>>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(None)
    }

    fn update_router_data_with_create_order_response(
        &mut self,
        _create_order_result: types::CreateOrderResult,
    ) {
    }

    async fn call_unified_connector_service<'a>(
        &mut self,
        _state: &SessionState,
        _header_payload: &domain_payments::HeaderPayload,
        _lineage_ids: grpc_client::LineageIds,
        #[cfg(feature = "v1")] _merchant_connector_account: helpers::MerchantConnectorAccountType,
        #[cfg(feature = "v2")]
        _merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
        _merchant_context: &domain::MerchantContext,
    ) -> RouterResult<()>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(())
    }

    #[cfg(feature = "v2")]
    async fn call_unified_connector_service_with_external_vault_proxy<'a>(
        &mut self,
        _state: &SessionState,
        _header_payload: &domain_payments::HeaderPayload,
        _lineage_ids: grpc_client::LineageIds,
        _merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
        _external_vault_merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
        _merchant_context: &domain::MerchantContext,
    ) -> RouterResult<()>
    where
        F: Clone,
        Self: Sized,
        dyn api::Connector: services::ConnectorIntegration<F, T, types::PaymentsResponseData>,
    {
        Ok(())
    }
}

/// Determines whether a capture API call should be made for a payment attempt
/// This function evaluates whether an authorized payment should proceed with a capture API call
/// based on various payment parameters. It's primarily used in two-step (auth + capture) payment flows for CaptureMethod SequentialAutomatic
///
pub fn should_initiate_capture_flow(
    connector_name: &router_types::Connector,
    customer_acceptance: Option<CustomerAcceptance>,
    capture_method: Option<api_enums::CaptureMethod>,
    setup_future_usage: Option<api_enums::FutureUsage>,
    status: common_enums::AttemptStatus,
) -> bool {
    match status {
        common_enums::AttemptStatus::Authorized => {
            if let Some(api_enums::CaptureMethod::SequentialAutomatic) = capture_method {
                match connector_name {
                    router_types::Connector::Paybox => {
                        // Check CIT conditions for Paybox
                        setup_future_usage == Some(api_enums::FutureUsage::OffSession)
                            && customer_acceptance.is_some()
                    }
                    _ => false,
                }
            } else {
                false
            }
        }
        _ => false,
    }
}

/// Executes a capture request by building a connector-specific request and deciding
/// the appropriate flow to send it to the payment connector.
pub async fn call_capture_request(
    mut capture_router_data: types::RouterData<
        api::Capture,
        PaymentsCaptureData,
        types::PaymentsResponseData,
    >,
    state: &SessionState,
    connector: &api::ConnectorData,
    call_connector_action: payments::CallConnectorAction,
    business_profile: &domain::Profile,
    header_payload: domain_payments::HeaderPayload,
) -> RouterResult<types::RouterData<api::Capture, PaymentsCaptureData, types::PaymentsResponseData>>
{
    // Build capture-specific connector request
    let (connector_request, _should_continue_further) = capture_router_data
        .build_flow_specific_connector_request(state, connector, call_connector_action.clone())
        .await?;

    // Execute capture flow
    capture_router_data
        .decide_flows(
            state,
            connector,
            call_connector_action,
            connector_request,
            business_profile,
            header_payload.clone(),
            None,
        )
        .await
}

/// Processes the response from the capture flow and determines the final status and the response.
fn handle_post_capture_response(
    authorize_router_data_response: types::PaymentsResponseData,
    post_capture_router_data: Result<
        types::RouterData<api::Capture, PaymentsCaptureData, types::PaymentsResponseData>,
        error_stack::Report<ApiErrorResponse>,
    >,
) -> RouterResult<(common_enums::AttemptStatus, types::PaymentsResponseData)> {
    match post_capture_router_data {
        Err(err) => {
            logger::error!(
                "Capture flow encountered an error: {:?}. Proceeding without updating.",
                err
            );
            Ok((
                common_enums::AttemptStatus::Authorized,
                authorize_router_data_response,
            ))
        }
        Ok(post_capture_router_data) => {
            match (
                &post_capture_router_data.response,
                post_capture_router_data.status,
            ) {
                (Ok(post_capture_resp), common_enums::AttemptStatus::Charged) => Ok((
                    common_enums::AttemptStatus::Charged,
                    types::PaymentsResponseData::merge_transaction_responses(
                        &authorize_router_data_response,
                        post_capture_resp,
                    )?,
                )),
                _ => {
                    logger::error!(
                        "Error in post capture_router_data response: {:?}, Current Status: {:?}. Proceeding without updating.",
                        post_capture_router_data.response,
                        post_capture_router_data.status,
                    );
                    Ok((
                        common_enums::AttemptStatus::Authorized,
                        authorize_router_data_response,
                    ))
                }
            }
        }
    }
}


// Implementation: impl ConnectorRedirectResponse for for Zen
// File: crates/hyperswitch_connectors/src/connectors/zen.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ConnectorRedirectResponse for for Zen


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

pub mod transformers;

use std::{sync::LazyLock, time::SystemTime};

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

use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{
        self, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData,
        RefundsRequestData, RouterData as ConnectorRouterData,
    },
};

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

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

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

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Deutschebank
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let access_token = req
            .access_token
            .clone()
            .ok_or(errors::ConnectorError::FailedToObtainAuthType)?;
        let mut header = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
            (
                headers::AUTHORIZATION.to_string(),
                format!("Bearer {}", access_token.token.expose()).into_masked(),
            ),
        ];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

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

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

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

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

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

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

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.rc,
            message: response.message.clone(),
            reason: Some(response.message),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Deutschebank {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: hyperswitch_domain_models::payment_method_data::PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd =
            std::collections::HashSet::from([utils::PaymentMethodDataType::SepaBankDebit]);
        utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

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

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

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Deutschebank {
    fn get_url(
        &self,
        _req: &RefreshTokenRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/security/v1/token", self.base_url(connectors)))
    }

    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

    fn build_request(
        &self,
        req: &RefreshTokenRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let auth = deutschebank::DeutschebankAuthType::try_from(&req.connector_auth_type)?;
        let client_id = auth.client_id.expose();
        let date = Date(SystemTime::now().into()).to_string();
        let random_string = Alphanumeric.sample_string(&mut rand::thread_rng(), 50);

        let string_to_sign = client_id.clone() + &date + &random_string;
        let key = hmac::Key::new(hmac::HMAC_SHA256, auth.client_key.expose().as_bytes());
        let client_secret = format!(
            "V1:{}",
            common_utils::consts::BASE64_ENGINE
                .encode(hmac::sign(&key, string_to_sign.as_bytes()).as_ref())
        );

        let headers = vec![
            (
                headers::X_RANDOM_VALUE.to_string(),
                random_string.into_masked(),
            ),
            (headers::X_REQUEST_DATE.to_string(), date.into_masked()),
            (
                headers::CONTENT_TYPE.to_string(),
                types::RefreshTokenType::get_content_type(self)
                    .to_string()
                    .into(),
            ),
        ];

        let connector_req = deutschebank::DeutschebankAccessTokenRequest {
            client_id: Secret::from(client_id),
            client_secret: Secret::from(client_secret),
            grant_type: "client_credentials".to_string(),
            scope: "ftx".to_string(),
        };
        let body = RequestContent::FormUrlEncoded(Box::new(connector_req));

        let req = Some(
            RequestBuilder::new()
                .method(Method::Post)
                .headers(headers)
                .url(&types::RefreshTokenType::get_url(self, req, connectors)?)
                .set_body(body)
                .build(),
        );
        Ok(req)
    }

    fn handle_response(
        &self,
        data: &RefreshTokenRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefreshTokenRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankAccessTokenResponse = res
            .response
            .parse_struct("Paypal PaypalAuthUpdateResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

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

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

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        match response {
            deutschebank::DeutschebankError::PaymentsErrorResponse(response) => Ok(ErrorResponse {
                status_code: res.status_code,
                code: response.rc,
                message: response.message.clone(),
                reason: Some(response.message),
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            deutschebank::DeutschebankError::AccessTokenErrorResponse(response) => {
                Ok(ErrorResponse {
                    status_code: res.status_code,
                    code: response.cause.clone(),
                    message: response.cause.clone(),
                    reason: Some(response.description),
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
        }
    }
}

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

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

    fn get_url(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let event_id = req.connector_request_reference_id.clone();
        let tx_action = if req.request.is_auto_capture()? {
            "authorization"
        } else {
            "preauthorization"
        };

        if req.is_three_ds() && req.request.is_card() {
            Ok(format!(
                "{}/services/v2.1/headless3DSecure/event/{event_id}/{tx_action}/initialize",
                self.base_url(connectors)
            ))
        } else if !req.is_three_ds() && req.request.is_card() {
            Err(errors::ConnectorError::NotSupported {
                message: "Non-ThreeDs".to_owned(),
                connector: "deutschebank",
            }
            .into())
        } else if req.request.connector_mandate_id().is_none() {
            Ok(format!(
                "{}/services/v2.1/managedmandate",
                self.base_url(connectors)
            ))
        } else {
            Ok(format!(
                "{}/services/v2.1/payment/event/{event_id}/directdebit/{tx_action}",
                self.base_url(connectors)
            ))
        }
    }

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

        let connector_router_data = deutschebank::DeutschebankRouterData::from((amount, req));
        let connector_req =
            deutschebank::DeutschebankPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        if data.is_three_ds() && data.request.is_card() {
            let response: deutschebank::DeutschebankThreeDSInitializeResponse = res
                .response
                .parse_struct("DeutschebankPaymentsAuthorizeResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
            event_builder.map(|i| i.set_response_body(&response));
            router_env::logger::info!(connector_response=?response);
            RouterData::try_from(ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            })
        } else if data.request.connector_mandate_id().is_none() {
            let response: deutschebank::DeutschebankMandatePostResponse = res
                .response
                .parse_struct("DeutschebankMandatePostResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
            event_builder.map(|i| i.set_response_body(&response));
            router_env::logger::info!(connector_response=?response);
            RouterData::try_from(ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            })
        } else {
            let response: deutschebank::DeutschebankPaymentsResponse = res
                .response
                .parse_struct("DeutschebankPaymentsAuthorizeResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
            event_builder.map(|i| i.set_response_body(&response));
            router_env::logger::info!(connector_response=?response);
            RouterData::try_from(ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            })
        }
    }

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

impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>
    for Deutschebank
{
    fn get_headers(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let event_id = req.connector_request_reference_id.clone();
        let tx_action = if req.request.is_auto_capture()? {
            "authorization"
        } else {
            "preauthorization"
        };

        if req.is_three_ds() && matches!(req.payment_method, enums::PaymentMethod::Card) {
            Ok(format!(
                "{}/services/v2.1//headless3DSecure/event/{event_id}/final",
                self.base_url(connectors)
            ))
        } else {
            Ok(format!(
                "{}/services/v2.1/payment/event/{event_id}/directdebit/{tx_action}",
                self.base_url(connectors)
            ))
        }
    }

    fn get_request_body(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let connector_router_data = deutschebank::DeutschebankRouterData::from((amount, req));
        let connector_req =
            deutschebank::DeutschebankCompleteAuthorizeRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCompleteAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCompleteAuthorizeRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("Deutschebank PaymentsCompleteAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

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

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

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("DeutschebankPaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

    fn get_url(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let event_id = req.connector_request_reference_id.clone();
        let tx_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}/services/v2.1/payment/event/{event_id}/tx/{tx_id}/capture",
            self.base_url(connectors)
        ))
    }

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

        let connector_router_data = deutschebank::DeutschebankRouterData::from((amount, req));
        let connector_req =
            deutschebank::DeutschebankCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("Deutschebank PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

    fn get_url(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let event_id = req.connector_request_reference_id.clone();
        let tx_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}/services/v2.1/payment/event/{event_id}/tx/{tx_id}/reversal",
            self.base_url(connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = deutschebank::DeutschebankReversalRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("Deutschebank PaymentsCancelResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

    fn get_url(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let event_id = req.attempt_id.clone();
        let tx_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}/services/v2.1/payment/event/{event_id}/tx/{tx_id}/refund",
            self.base_url(connectors)
        ))
    }

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

        let connector_router_data =
            deutschebank::DeutschebankRouterData::from((refund_amount, req));
        let connector_req =
            deutschebank::DeutschebankRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("DeutschebankPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let tx_id = req.request.get_connector_refund_id()?;
        Ok(format!(
            "{}/services/v2.1/payment/tx/{tx_id}",
            self.base_url(connectors)
        ))
    }

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

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: deutschebank::DeutschebankPaymentsResponse = res
            .response
            .parse_struct("DeutschebankPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

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

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

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

        let mut deutschebank_supported_payment_methods = SupportedPaymentMethods::new();

        deutschebank_supported_payment_methods.add(
            enums::PaymentMethod::BankDebit,
            enums::PaymentMethodType::Sepa,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

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

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

        deutschebank_supported_payment_methods
    });

static DEUTSCHEBANK_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Deutsche Bank",
    description:
        "Deutsche Bank is a German multinational investment bank and financial services company ",
    connector_type: enums::HyperswitchConnectorCategory::BankAcquirer,
    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
};

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

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

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

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


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

use hyperswitch_domain_models::{
    router_data_v2::ExternalAuthenticationFlowData,
    router_flow_types::authentication::{
        Authentication, PostAuthentication, PreAuthentication, PreAuthenticationVersionCall,
    },
    router_request_types::authentication::{
        ConnectorAuthenticationRequestData, ConnectorPostAuthenticationRequestData,
        PreAuthNRequestData,
    },
    router_response_types::AuthenticationResponseData,
};

use crate::api::ConnectorIntegrationV2;

/// trait ConnectorAuthenticationV2
pub trait ConnectorAuthenticationV2:
    ConnectorIntegrationV2<
    Authentication,
    ExternalAuthenticationFlowData,
    ConnectorAuthenticationRequestData,
    AuthenticationResponseData,
>
{
}

/// trait ConnectorPreAuthenticationV2
pub trait ConnectorPreAuthenticationV2:
    ConnectorIntegrationV2<
    PreAuthentication,
    ExternalAuthenticationFlowData,
    PreAuthNRequestData,
    AuthenticationResponseData,
>
{
}

/// trait ConnectorPreAuthenticationVersionCallV2
pub trait ConnectorPreAuthenticationVersionCallV2:
    ConnectorIntegrationV2<
    PreAuthenticationVersionCall,
    ExternalAuthenticationFlowData,
    PreAuthNRequestData,
    AuthenticationResponseData,
>
{
}

/// trait ConnectorPostAuthenticationV2
pub trait ConnectorPostAuthenticationV2:
    ConnectorIntegrationV2<
    PostAuthentication,
    ExternalAuthenticationFlowData,
    ConnectorPostAuthenticationRequestData,
    AuthenticationResponseData,
>
{
}

/// trait ExternalAuthenticationV2
pub trait ExternalAuthenticationV2:
    super::ConnectorCommon
    + ConnectorAuthenticationV2
    + ConnectorPreAuthenticationV2
    + ConnectorPreAuthenticationVersionCallV2
    + ConnectorPostAuthenticationV2
{
}


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

impl api::RefundSync for for Airwallex


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

impl api::RefundSync for for Hipay


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

pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserResponse<R>


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

impl api::PaymentSync for for Bamboraapac


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

#[inline]
pub async fn record_operation_time<F, R, T>(
    future: F,
    metric: &router_env::opentelemetry::metrics::Histogram<f64>,
    metric_name: &T,
    source: &crate::AnalyticsProvider,
) -> R
where
    F: futures::Future<Output = R>,
    T: ToString,
{
    let (result, time) = common_utils::metrics::utils::time_future(future).await;
    let attributes = router_env::metric_attributes!(
        ("metric_name", metric_name.to_string()),
        ("source", source.to_string()),
    );
    let value = time.as_secs_f64();
    metric.record(value, attributes);

    router_env::logger::debug!("Attributes: {:?}, Time: {}", attributes, value);
    result
}


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

impl api::PaymentVoid for for Mollie


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

pub fn payments_complete_authorize_redirect_with_creds_identifier(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: Option<web::Form<serde_json::Value>>,
    path: web::Path<(
        common_utils::id_type::PaymentId,
        common_utils::id_type::MerchantId,
        String,
        String,
    )


// File: crates/router/src/types/storage/routing_algorithm.rs
// Module: router

pub use diesel_models::routing_algorithm::{
    RoutingAlgorithm, RoutingAlgorithmMetadata, RoutingProfileMetadata,
};


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

pub fn payment_methods_session_retrieve(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
) -> RouterResponse<payment_methods::PaymentMethodSessionResponse>


// Function: validate
// File: crates/scheduler/src/settings.rs
// Module: scheduler

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


// Implementation: impl super::payments::filters::PaymentFilterAnalytics for for SqlxClient
// File: crates/analytics/src/sqlx.rs
// Module: analytics
// Methods: 0 total (0 public)

impl super::payments::filters::PaymentFilterAnalytics for for SqlxClient


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

pub struct SamsungPayFluidDataValue


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

pub struct AccessTokenAuthenticationRequestData


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

pub struct PayuErrorData


// Struct: WebhookPaymentInformation
// File: crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WebhookPaymentInformation


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

pub struct Status


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

impl api::PaymentSync for for Wellsfargopayout


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

impl api::RefundExecute for for Prophetpay


// Struct: AciPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/aci/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AciPaymentsRequest


// 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<&hyperswitch_domain_models::address::Address>,
    business_profile: &domain::Profile,
    mut original_connector_mandate_reference_id: Option<ConnectorMandateReferenceId>,
    merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    vault_operation: Option<hyperswitch_domain_models::payments::VaultOperation>,
    payment_method_info: Option<domain::PaymentMethod>,
) -> RouterResult<SavePaymentMethodDataResponse>
where
    FData: mandate::MandateBehaviour + Clone,


// Function: get_auth_event_metrics_info
// File: crates/analytics/src/utils.rs
// Module: analytics

pub fn get_auth_event_metrics_info() -> Vec<NameDescription>


// Trait: SeriesBucket
// File: crates/analytics/src/query.rs
// Module: analytics

pub trait SeriesBucket


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

pub struct AuthorizedotnetPaymentProfileRequest


// File: crates/euclid/benches/backends.rs
// Module: euclid

#![allow(unused, clippy::expect_used)]

use common_utils::types::MinorUnit;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use euclid::{
    backend::{inputs, EuclidBackend, InterpreterBackend, VirInterpreterBackend},
    enums,
    frontend::ast::{self, parser},
    types::DummyOutput,
};

fn get_program_data() -> (ast::Program<DummyOutput>, inputs::BackendInput) {
    let code1 = r#"
        default: ["stripe", "adyen", "checkout"]

        stripe_first: ["stripe", "aci"]
        {
            payment_method = card & amount = 40 {
                payment_method = (card, bank_redirect)
                amount = (40, 50)
            }
        }

        adyen_first: ["adyen", "checkout"]
        {
            payment_method = bank_redirect & amount > 60 {
                payment_method = (card, bank_redirect)
                amount = (40, 50)
            }
        }

        auth_first: ["authorizedotnet", "adyen"]
        {
            payment_method = wallet
        }
    "#;

    let inp = inputs::BackendInput {
        metadata: None,
        payment: inputs::PaymentInput {
            amount: MinorUnit::new(32),
            card_bin: None,
            currency: enums::Currency::USD,
            authentication_type: Some(enums::AuthenticationType::NoThreeDs),
            capture_method: Some(enums::CaptureMethod::Automatic),
            business_country: Some(enums::Country::UnitedStatesOfAmerica),
            billing_country: Some(enums::Country::France),
            business_label: None,
            setup_future_usage: None,
        },
        payment_method: inputs::PaymentMethodInput {
            payment_method: Some(enums::PaymentMethod::PayLater),
            payment_method_type: Some(enums::PaymentMethodType::Sofort),
            card_network: None,
        },
        mandate: inputs::MandateData {
            mandate_acceptance_type: None,
            mandate_type: None,
            payment_type: None,
        },
        issuer_data: None,
        acquirer_data: None,
        customer_device_data: None,
    };

    let (_, program) = parser::program(code1).expect("Parser");

    (program, inp)
}

fn interpreter_vs_jit_vs_vir_interpreter(c: &mut Criterion) {
    let (program, binputs) = get_program_data();

    let interp_b = InterpreterBackend::with_program(program.clone()).expect("Interpreter backend");

    let vir_interp_b =
        VirInterpreterBackend::with_program(program).expect("Vir Interpreter Backend");

    c.bench_function("Raw Interpreter Backend", |b| {
        b.iter(|| {
            interp_b
                .execute(binputs.clone())
                .expect("Interpreter EXECUTION");
        });
    });

    c.bench_function("Valued Interpreter Backend", |b| {
        b.iter(|| {
            vir_interp_b
                .execute(binputs.clone())
                .expect("Vir Interpreter execution");
        })
    });
}

criterion_group!(benches, interpreter_vs_jit_vs_vir_interpreter);
criterion_main!(benches);


// Function: validate
// File: crates/router/src/configs/validations.rs
// Module: router

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


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

impl api::ConnectorAccessToken for for Worldline


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

pub struct PaymentsCaptureData


// Function: proxy
// File: crates/router/src/routes/proxy.rs
// Module: router

pub fn proxy(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    payload: web::Json<api_models::proxy::ProxyRequest>,
) -> impl Responder


// Struct: AuthenticationDetails
// File: crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct AuthenticationDetails


// Struct: PaymeVoidResponse
// File: crates/hyperswitch_connectors/src/connectors/payme/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymeVoidResponse


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod payouts;

// Public exports:
pub use payouts::*;


// Function: send_request_to_key_service_for_user
// File: crates/router/src/core/encryption.rs
// Module: router

pub fn send_request_to_key_service_for_user(
    state: &SessionState,
    keys: Vec<UserKeyStore>,
) -> errors::CustomResult<usize, errors::ApiErrorResponse>


// File: crates/common_utils/src/errors.rs
// Module: common_utils
// Public structs: 1

//! Errors and error specific types for universal use

use crate::types::MinorUnit;

/// Custom Result
/// A custom datatype that wraps the error variant <E> into a report, allowing
/// error_stack::Report<E> specific extendability
///
/// Effectively, equivalent to `Result<T, error_stack::Report<E>>`
pub type CustomResult<T, E> = error_stack::Result<T, E>;

/// Parsing Errors
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
#[derive(Debug, thiserror::Error)]
pub enum ParsingError {
    ///Failed to parse enum
    #[error("Failed to parse enum: {0}")]
    EnumParseFailure(&'static str),
    ///Failed to parse struct
    #[error("Failed to parse struct: {0}")]
    StructParseFailure(&'static str),
    /// Failed to encode data to given format
    #[error("Failed to serialize to {0} format")]
    EncodeError(&'static str),
    /// Failed to parse data
    #[error("Unknown error while parsing")]
    UnknownError,
    /// Failed to parse datetime
    #[error("Failed to parse datetime")]
    DateTimeParsingError,
    /// Failed to parse email
    #[error("Failed to parse email")]
    EmailParsingError,
    /// Failed to parse phone number
    #[error("Failed to parse phone number")]
    PhoneNumberParsingError,
    /// Failed to parse Float value for converting to decimal points
    #[error("Failed to parse Float value for converting to decimal points")]
    FloatToDecimalConversionFailure,
    /// Failed to parse Decimal value for i64 value conversion
    #[error("Failed to parse Decimal value for i64 value conversion")]
    DecimalToI64ConversionFailure,
    /// Failed to parse string value for f64 value conversion
    #[error("Failed to parse string value for f64 value conversion")]
    StringToFloatConversionFailure,
    /// Failed to parse i64 value for f64 value conversion
    #[error("Failed to parse i64 value for f64 value conversion")]
    I64ToDecimalConversionFailure,
    /// Failed to parse i64 value for String value conversion
    #[error("Failed to parse i64 value for String value conversion")]
    I64ToStringConversionFailure,
    /// Failed to parse String value to Decimal value conversion because `error`
    #[error("Failed to parse String value to Decimal value conversion because {error}")]
    StringToDecimalConversionFailure { error: String },
    /// Failed to convert the given integer because of integer overflow error
    #[error("Integer Overflow error")]
    IntegerOverflow,
    /// Failed to parse url
    #[error("Failed to parse url")]
    UrlParsingError,
}

/// Validation errors.
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
#[derive(Debug, thiserror::Error, Clone, PartialEq)]
pub enum ValidationError {
    /// The provided input is missing a required field.
    #[error("Missing required field: {field_name}")]
    MissingRequiredField { field_name: String },

    /// An incorrect value was provided for the field specified by `field_name`.
    #[error("Incorrect value provided for field: {field_name}")]
    IncorrectValueProvided { field_name: &'static str },

    /// An invalid input was provided.
    #[error("{message}")]
    InvalidValue { message: String },
}

/// Integrity check errors.
#[derive(Debug, Clone, PartialEq, Default)]
pub struct IntegrityCheckError {
    /// Field names for which integrity check failed!
    pub field_names: String,
    /// Connector transaction reference id
    pub connector_transaction_id: Option<String>,
}

/// Cryptographic algorithm errors
#[derive(Debug, thiserror::Error)]
pub enum CryptoError {
    /// The cryptographic algorithm was unable to encode the message
    #[error("Failed to encode given message")]
    EncodingFailed,
    /// The cryptographic algorithm was unable to decode the message
    #[error("Failed to decode given message")]
    DecodingFailed,
    /// The cryptographic algorithm was unable to sign the message
    #[error("Failed to sign message")]
    MessageSigningFailed,
    /// The cryptographic algorithm was unable to verify the given signature
    #[error("Failed to verify signature")]
    SignatureVerificationFailed,
    /// The provided key length is invalid for the cryptographic algorithm
    #[error("Invalid key length")]
    InvalidKeyLength,
    /// The provided IV length is invalid for the cryptographic algorithm
    #[error("Invalid IV length")]
    InvalidIvLength,
    /// The provided authentication tag length is invalid for the cryptographic algorithm
    #[error("Invalid authentication tag length")]
    InvalidTagLength,
}

/// Errors for Qr code handling
#[derive(Debug, thiserror::Error)]
pub enum QrCodeError {
    /// Failed to encode data into Qr code
    #[error("Failed to create Qr code")]
    FailedToCreateQrCode,
    /// Failed to parse hex color
    #[error("Invalid hex color code supplied")]
    InvalidHexColor,
}

/// Api Models construction error
#[derive(Debug, Clone, thiserror::Error, PartialEq)]
pub enum PercentageError {
    /// Percentage Value provided was invalid
    #[error("Invalid Percentage value")]
    InvalidPercentageValue,

    /// Error occurred while calculating percentage
    #[error("Failed apply percentage of {percentage} on {amount}")]
    UnableToApplyPercentage {
        /// percentage value
        percentage: f32,
        /// amount value
        amount: MinorUnit,
    },
}

/// Allows [error_stack::Report] to change between error contexts
/// using the dependent [ErrorSwitch] trait to define relations & mappings between traits
pub trait ReportSwitchExt<T, U> {
    /// Switch to the intended report by calling switch
    /// requires error switch to be already implemented on the error type
    fn switch(self) -> Result<T, error_stack::Report<U>>;
}

impl<T, U, V> ReportSwitchExt<T, U> for Result<T, error_stack::Report<V>>
where
    V: ErrorSwitch<U> + error_stack::Context,
    U: error_stack::Context,
{
    #[track_caller]
    fn switch(self) -> Result<T, error_stack::Report<U>> {
        match self {
            Ok(i) => Ok(i),
            Err(er) => {
                let new_c = er.current_context().switch();
                Err(er.change_context(new_c))
            }
        }
    }
}

#[allow(missing_docs)]
#[derive(Debug, thiserror::Error)]
pub enum KeyManagerClientError {
    #[error("Failed to construct header from the given value")]
    FailedtoConstructHeader,
    #[error("Failed to send request to Keymanager")]
    RequestNotSent(String),
    #[error("URL encoding of request failed")]
    UrlEncodingFailed,
    #[error("Failed to build the reqwest client ")]
    ClientConstructionFailed,
    #[error("Failed to send the request to Keymanager")]
    RequestSendFailed,
    #[error("Internal Server Error Received {0:?}")]
    InternalServerError(bytes::Bytes),
    #[error("Bad request received {0:?}")]
    BadRequest(bytes::Bytes),
    #[error("Unexpected Error occurred while calling the KeyManager")]
    Unexpected(bytes::Bytes),
    #[error("Response Decoding failed")]
    ResponseDecodingFailed,
}

#[allow(missing_docs)]
#[derive(Debug, thiserror::Error)]
pub enum KeyManagerError {
    #[error("Failed to add key to the KeyManager")]
    KeyAddFailed,
    #[error("Failed to transfer the key to the KeyManager")]
    KeyTransferFailed,
    #[error("Failed to Encrypt the data in the KeyManager")]
    EncryptionFailed,
    #[error("Failed to Decrypt the data in the KeyManager")]
    DecryptionFailed,
}

/// Allow [error_stack::Report] to convert between error types
/// This auto-implements [ReportSwitchExt] for the corresponding errors
pub trait ErrorSwitch<T> {
    /// Get the next error type that the source error can be escalated into
    /// This does not consume the source error since we need to keep it in context
    fn switch(&self) -> T;
}

/// Allow [error_stack::Report] to convert between error types
/// This serves as an alternative to [ErrorSwitch]
pub trait ErrorSwitchFrom<T> {
    /// Convert to an error type that the source can be escalated into
    /// This does not consume the source error since we need to keep it in context
    fn switch_from(error: &T) -> Self;
}

impl<T, S> ErrorSwitch<T> for S
where
    T: ErrorSwitchFrom<Self>,
{
    fn switch(&self) -> T {
        T::switch_from(self)
    }
}


// Struct: AirwallexOrderData
// File: crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AirwallexOrderData


// Struct: CashtocodePaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/cashtocode/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CashtocodePaymentsRequest


// Implementation: impl DerefMut for for Memoization
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Methods: 1 total (0 public)

impl DerefMut for for Memoization


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

impl api::PayoutFulfill for for Paypal