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

pub mod transformers;
use std::sync::LazyLock;

#[cfg(feature = "payouts")]
use api_models::webhooks::PayoutIdType;
use api_models::{
    payments::PaymentIdType,
    webhooks::{IncomingWebhookEvent, RefundIdType},
};
use common_enums::{enums, CallConnectorAction, PaymentAction};
use common_utils::{
    crypto,
    errors::{CustomResult, ReportSwitchExt},
    ext_traits::{ByteSliceExt, BytesExt, ValueExt},
    id_type,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{
        AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, StringMajorUnit,
        StringMajorUnitForConnector, StringMinorUnit, StringMinorUnitForConnector,
    },
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
        AuthorizeSessionToken, CompleteAuthorize, PostCaptureVoid, PreProcessing,
    },
    router_request_types::{
        AccessTokenRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData,
        PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData,
        PaymentsCancelPostCaptureData, PaymentsCaptureData, PaymentsPreProcessingData,
        PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsAuthorizeSessionTokenRouterData,
        PaymentsCancelPostCaptureRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData,
        PaymentsSyncRouterData, RefundsRouterData,
    },
};
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::{
    router_flow_types::payouts::PoFulfill, router_request_types::PayoutsData,
    router_response_types::PayoutsResponseData, types::PayoutsRouterData,
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse,
        ConnectorSpecifications, ConnectorValidation,
    },
    configs::Connectors,
    disputes, errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::ExposeInterface;
use transformers as nuvei;

use crate::{
    connectors::nuvei::transformers::{NuveiPaymentsResponse, NuveiTransactionSyncResponse},
    constants::headers,
    types::ResponseRouterData,
    utils::{self, is_mandate_supported, PaymentMethodDataType, RouterData as _},
};

#[derive(Clone)]
pub struct Nuvei {
    pub amount_convertor: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
    amount_converter_string_minor_unit:
        &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
    amount_converter_float_major_unit:
        &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}
impl Nuvei {
    pub fn new() -> &'static Self {
        &Self {
            amount_convertor: &StringMajorUnitForConnector,
            amount_converter_string_minor_unit: &StringMinorUnitForConnector,
            amount_converter_float_major_unit: &FloatMajorUnitForConnector,
        }
    }
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Nuvei
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 headers = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        Ok(headers)
    }
}

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

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

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

    fn get_auth_header(
        &self,
        _auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![])
    }
}

impl ConnectorValidation for Nuvei {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd = std::collections::HashSet::from([
            PaymentMethodDataType::Card,
            PaymentMethodDataType::GooglePay,
            PaymentMethodDataType::ApplePay,
            PaymentMethodDataType::NetworkTransactionIdAndCardDetails,
        ]);
        is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

impl api::Payment for Nuvei {}

impl api::PaymentToken for Nuvei {}

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

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Nuvei {}

impl api::MandateSetup for Nuvei {}
impl api::PaymentVoid for Nuvei {}
impl api::PaymentSync for Nuvei {}
impl api::PaymentCapture for Nuvei {}
impl api::PaymentSession for Nuvei {}
impl api::PaymentAuthorize for Nuvei {}
impl api::PaymentAuthorizeSessionToken for Nuvei {}
impl api::Refund for Nuvei {}
impl api::RefundExecute for Nuvei {}
impl api::RefundSync for Nuvei {}
impl api::PaymentsCompleteAuthorize for Nuvei {}
impl api::ConnectorAccessToken for Nuvei {}
impl api::PaymentsPreProcessing for Nuvei {}
impl api::PaymentPostCaptureVoid for Nuvei {}

impl api::Payouts for Nuvei {}
#[cfg(feature = "payouts")]
impl api::PayoutFulfill for Nuvei {}

#[async_trait::async_trait]
#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoFulfill, PayoutsData, PayoutsResponseData> for Nuvei {
    fn get_url(
        &self,
        _req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/payout.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_headers(
        &self,
        req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoFulfill>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoFulfill>, errors::ConnectorError> {
        let response: nuvei::NuveiPayoutResponse =
            res.response.parse_struct("NuveiPayoutResponse").switch()?;
        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Nuvei {
    fn get_headers(
        &self,
        req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        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: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/payment.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, req.get_session_token()?))?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        errors::ConnectorError,
    > {
        let response: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;
        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 Nuvei {
    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> {
        Ok(format!(
            "{}ppp/api/v1/voidTransaction.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

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

    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = 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();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;
        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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 Nuvei
{
    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> {
        Ok(format!(
            "{}ppp/api/v1/payment.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }
    fn get_request_body(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let meta: nuvei::NuveiMeta = utils::to_connector_meta(req.request.connector_meta.clone())?;
        let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, meta.session_token))?;
        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: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;
        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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<PostCaptureVoid, PaymentsCancelPostCaptureData, PaymentsResponseData>
    for Nuvei
{
    fn get_headers(
        &self,
        req: &PaymentsCancelPostCaptureRouterData,
        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: &PaymentsCancelPostCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/voidTransaction.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

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

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

    fn handle_response(
        &self,
        data: &PaymentsCancelPostCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelPostCaptureRouterData, errors::ConnectorError> {
        let response: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;
        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Nuvei {}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Nuvei {
    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> {
        Ok(format!(
            "{}ppp/api/v1/getTransactionDetails.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentSyncRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }
    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
                .set_body(types::PaymentsSyncType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let nuvie_psync_common_response: nuvei::NuveiPaymentSyncResponse = res
            .response
            .parse_struct("NuveiPaymentSyncResponse")
            .switch()?;

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

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

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Nuvei {
    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> {
        Ok(format!(
            "{}ppp/api/v1/settleTransaction.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentFlowRequest::try_from(req)?;
        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: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;

        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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 ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Nuvei {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/payment.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, req.get_session_token()?))?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;

        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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<AuthorizeSessionToken, AuthorizeSessionTokenData, PaymentsResponseData>
    for Nuvei
{
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeSessionTokenRouterData,
        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: &PaymentsAuthorizeSessionTokenRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/getSessionToken.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

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

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

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeSessionTokenRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeSessionTokenRouterData, errors::ConnectorError> {
        let response: nuvei::NuveiSessionResponse =
            res.response.parse_struct("NuveiSessionResponse").switch()?;

        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<PreProcessing, PaymentsPreProcessingData, PaymentsResponseData>
    for Nuvei
{
    fn get_headers(
        &self,
        req: &PaymentsPreProcessingRouterData,
        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: &PaymentsPreProcessingRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}ppp/api/v1/initPayment.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsPreProcessingRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, req.get_session_token()?))?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsPreProcessingRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsPreProcessingRouterData, errors::ConnectorError> {
        let response: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;
        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,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    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 Nuvei {
    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> {
        Ok(format!(
            "{}ppp/api/v1/refundTransaction.do",
            ConnectorCommon::base_url(self, connectors)
        ))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nuvei::NuveiPaymentFlowRequest::try_from(req)?;
        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: NuveiPaymentsResponse = res
            .response
            .parse_struct("NuveiPaymentsResponse")
            .switch()?;


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

impl ConnectorSpecifications for for Worldpayvantiv


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

impl ConnectorCommon for for Thunes


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

crate::id_type!(
    SubscriptionId,
    " A type for subscription_id that can be used for subscription ids"
);

crate::impl_id_type_methods!(SubscriptionId, "subscription_id");

// This is to display the `SubscriptionId` as SubscriptionId(subs)
crate::impl_debug_id_type!(SubscriptionId);
crate::impl_try_from_cow_str_id_type!(SubscriptionId, "subscription_id");

crate::impl_generate_id_id_type!(SubscriptionId, "subscription");
crate::impl_serializable_secret_id_type!(SubscriptionId);
crate::impl_queryable_id_type!(SubscriptionId);
crate::impl_to_sql_from_sql_id_type!(SubscriptionId);

impl crate::events::ApiEventMetric for SubscriptionId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Subscription)
    }
}


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

pub struct JpmorganErrorInformation


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

pub struct GenerateSaleResponse


// Struct: AnyPurposeOrLoginTokenAuth
// File: crates/router/src/services/authentication.rs
// Module: router
// Implementations: 0

pub struct AnyPurposeOrLoginTokenAuth


// Struct: SyncErrorCode
// File: crates/hyperswitch_connectors/src/connectors/redsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SyncErrorCode


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

pub struct CancelResponseTransactionBody


// Struct: PaymentLinkConfigRequest
// File: crates/diesel_models/src/business_profile.rs
// Module: diesel_models
// Implementations: 0

pub struct PaymentLinkConfigRequest


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

pub fn configure_dynamic_routing_volume_split(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    routing_info: routing::RoutingVolumeSplit,
) -> RouterResponse<routing::RoutingVolumeSplit>


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

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


// Implementation: impl webhooks::IncomingWebhook for for Xendit
// File: crates/hyperswitch_connectors/src/connectors/xendit.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl webhooks::IncomingWebhook for for Xendit


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

impl Refunds


// Implementation: impl KafkaPaymentAttempt
// File: crates/router/src/services/kafka/payment_attempt.rs
// Module: router
// Methods: 1 total (1 public)

impl KafkaPaymentAttempt


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

impl api::PaymentAuthorize for for Zen


// Function: reset_tracking_id
// File: crates/router/src/core/connector_onboarding.rs
// Module: router

pub fn reset_tracking_id(
    state: SessionState,
    user_from_token: auth::UserFromToken,
    request: api::ResetTrackingIdRequest,
    _req_state: ReqState,
) -> RouterResponse<()>


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

impl api::Payment for for Checkout


// Struct: PaysafeApplePayToken
// File: crates/hyperswitch_connectors/src/connectors/paysafe/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaysafeApplePayToken


// Struct: ThreeDSPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/paybox/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ThreeDSPaymentsRequest


// Struct: CeleroAuthType
// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CeleroAuthType


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

impl Files


// Implementation: impl api::PaymentToken for for Bluecode
// File: crates/hyperswitch_connectors/src/connectors/bluecode.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentToken for for Bluecode


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

pub fn mk_delete_card_request_hs_by_id(
    jwekey: &settings::Jwekey,
    locker: &settings::Locker,
    id: &String,
    merchant_id: &id_type::MerchantId,
    card_reference: &str,
    tenant_id: id_type::TenantId,
    request_id: Option<RequestId>,
) -> CustomResult<services::Request, errors::VaultError>


// Module Structure
// File: crates/pm_auth/src/types/api.rs
// Module: pm_auth

// Public submodules:
pub mod auth_service;


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

// Public exports:
pub use common_enums::enums::CallConnectorAction;
pub use hyperswitch_domain_models::{
    mandates::MandateData,
    payment_address::PaymentAddress,
    payments::{HeaderPayload, PaymentIntentData},
    router_data::{PaymentMethodToken, RouterData},
    router_data_v2::{flow_common_types::VaultConnectorFlowData, RouterDataV2},
    router_flow_types::ExternalVaultCreateFlow,
    router_request_types::CustomerDetails,
    types::{VaultRouterData, VaultRouterDataV2},
};


// Function: generic_insert
// File: crates/diesel_models/src/query/generics.rs
// Module: diesel_models

pub fn generic_insert<T, V, R>(conn: &PgPooledConn, values: V) -> StorageResult<R>
where
    T: HasTable<Table = T> + Table + 'static + Debug,
    V: Debug + Insertable<T>,
    <T as QuerySource>::FromClause: QueryFragment<Pg> + Debug,
    <V as Insertable<T>>::Values: CanInsertInSingleQuery<Pg> + QueryFragment<Pg> + 'static,
    InsertStatement<T, <V as Insertable<T>>::Values>:
        AsQuery + LoadQuery<'static, PgConnection, R> + Send,
    R: Send + 'static,


// Implementation: impl Serialize for for FiservCheckoutChargesRequest
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl Serialize for for FiservCheckoutChargesRequest


// Implementation: impl RefundDistributionAccumulator for for RefundReasonDistributionAccumulator
// File: crates/analytics/src/refunds/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl RefundDistributionAccumulator for for RefundReasonDistributionAccumulator


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

pub struct ExternalVaultCard


// Function: server
// File: crates/router/src/routes/app.rs
// Module: router

pub fn server(state: AppState) -> Scope


// Implementation: impl HashiCorpVaultConfig
// File: crates/external_services/src/hashicorp_vault/core.rs
// Module: external_services
// Methods: 1 total (1 public)

impl HashiCorpVaultConfig


// Module Structure
// File: crates/euclid/src/backend/vir_interpreter.rs
// Module: euclid

// Public submodules:
pub mod types;


// File: crates/router/tests/connectors/dlocal.rs
// Module: router
// Public functions: 1

#![allow(clippy::print_stdout)]

use std::str::FromStr;

use hyperswitch_domain_models::address::{Address, AddressDetails};
use masking::Secret;
use router::types::{self, api, domain, storage::enums, PaymentAddress};

use crate::{
    connector_auth,
    utils::{self, ConnectorActions, PaymentInfo},
};

#[derive(Clone, Copy)]
struct DlocalTest;
impl ConnectorActions for DlocalTest {}
impl utils::Connector for DlocalTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Dlocal;
        utils::construct_connector_data_old(
            Box::new(Dlocal::new()),
            types::Connector::Dlocal,
            api::GetToken::Connector,
            None,
        )
    }

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

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

static CONNECTOR: DlocalTest = DlocalTest {};

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(None, Some(get_payment_info()))
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(None, None, Some(get_payment_info()))
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            None,
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(None, Some(get_payment_info()))
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            Some(get_payment_info()),
        )
        .await
        .expect("PSync response");
    println!("{}", response.status);
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            None,
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            Some(get_payment_info()),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(None, None, None, Some(get_payment_info()))
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            None,
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(None, None, None, Some(get_payment_info()))
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(None, Some(get_payment_info()))
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(None, Some(get_payment_info()))
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(None, None, Some(get_payment_info()))
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            Some(get_payment_info()),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(None, None, Some(get_payment_info()))
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect card number.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_card_number() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_number: cards::CardNumber::from_str("1891011").unwrap(),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    assert_eq!(x.message, "Invalid parameter");
    assert_eq!(x.reason, Some("card.number".to_string()));
}

// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("1ad2345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    assert_eq!(x.message, "Invalid parameter");
    assert_eq!(x.reason, Some("card.cvv".to_string()));
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("201".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    assert_eq!(x.message, "Invalid parameter");
    assert_eq!(x.reason, Some("card.expiration_month".to_string()));
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("20001".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    assert_eq!(x.message, "Invalid parameter");
    assert_eq!(x.reason, Some("card.expiration_year".to_string()));
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(None, Some(get_payment_info()))
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, None)
        .await
        .unwrap();
    let x = void_response.response.unwrap_err();
    assert_eq!(x.code, "5021");
    assert_eq!(x.message, "Acquirer could not process the request");
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456sdf789".to_string(), None, Some(get_payment_info()))
        .await
        .unwrap();
    let x = capture_response.response.unwrap_err();
    assert_eq!(x.code, "3003");
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            Some(get_payment_info()),
        )
        .await
        .unwrap();
    let x = response.response.unwrap_err();
    println!("response from refund amount higher payment");
    println!("{}", x.code);
    assert_eq!(x.code, "5007");
    assert_eq!(x.message, "Amount exceeded");
}

pub fn get_payment_info() -> PaymentInfo {
    PaymentInfo {
        address: Some(PaymentAddress::new(
            None,
            Some(Address {
                phone: None,
                address: Some(AddressDetails {
                    city: None,
                    country: Some(api_models::enums::CountryAlpha2::PA),
                    line1: None,
                    line2: None,
                    line3: None,
                    zip: None,
                    state: None,
                    first_name: None,
                    last_name: None,
                    origin_zip: None,
                }),
                email: None,
            }),
            None,
            None,
        )),
        auth_type: None,
        access_token: None,
        connector_meta_data: None,
        ..Default::default()
    }
}
// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


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

pub struct ChargebeeEstimate


// Function: entity_type
// File: crates/router_derive/src/macros/generate_permissions.rs
// Module: router_derive

pub fn entity_type(&self) -> EntityType


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

impl ConnectorCommon for for Paysafe


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

pub struct BarclaycardClientReferenceResponse


// File: crates/hyperswitch_interfaces/src/connector_integration_interface.rs
// Module: hyperswitch_interfaces
// Public functions: 2

use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
use common_enums::PaymentAction;
use common_utils::{crypto, errors::CustomResult, request::Request};
use hyperswitch_domain_models::{
    api::ApplicationResponse,
    connector_endpoints::Connectors,
    errors::api_error_response::ApiErrorResponse,
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
    router_data_v2::RouterDataV2,
    router_response_types::{ConnectorInfo, SupportedPaymentMethods},
};

use crate::{
    api,
    api::{
        BoxedConnectorIntegration, CaptureSyncMethod, Connector, ConnectorCommon,
        ConnectorIntegration, ConnectorRedirectResponse, ConnectorSpecifications,
        ConnectorValidation, CurrencyUnit,
    },
    authentication::ExternalAuthenticationPayload,
    connector_integration_v2::{BoxedConnectorIntegrationV2, ConnectorIntegrationV2, ConnectorV2},
    disputes, errors,
    events::connector_api_logs::ConnectorEvent,
    types,
    webhooks::{IncomingWebhook, IncomingWebhookFlowError, IncomingWebhookRequestDetails},
};

/// RouterDataConversion trait
///
/// This trait must be implemented for conversion between Router data and RouterDataV2
pub trait RouterDataConversion<T, Req: Clone, Resp: Clone> {
    /// Convert RouterData to RouterDataV2
    ///
    /// # Arguments
    ///
    /// * `old_router_data` - A reference to the old RouterData
    ///
    /// # Returns
    ///
    /// A `CustomResult` containing the new RouterDataV2 or a ConnectorError
    fn from_old_router_data(
        old_router_data: &RouterData<T, Req, Resp>,
    ) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, errors::ConnectorError>
    where
        Self: Sized;
    /// Convert RouterDataV2 back to RouterData
    ///
    /// # Arguments
    ///
    /// * `new_router_data` - The new RouterDataV2
    ///
    /// # Returns
    ///
    /// A `CustomResult` containing the old RouterData or a ConnectorError
    fn to_old_router_data(
        new_router_data: RouterDataV2<T, Self, Req, Resp>,
    ) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
    where
        Self: Sized;
}
/// Alias for Box<&'static (dyn Connector + Sync)>
pub type BoxedConnector = Box<&'static (dyn Connector + Sync)>;
/// Alias for Box<&'static (dyn ConnectorV2 + Sync)>
pub type BoxedConnectorV2 = Box<&'static (dyn ConnectorV2 + Sync)>;

/// Enum representing the Connector
#[derive(Clone)]
pub enum ConnectorEnum {
    /// Old connector type
    Old(BoxedConnector),
    /// New connector type
    New(BoxedConnectorV2),
}

impl std::fmt::Debug for ConnectorEnum {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Old(_) => f
                .debug_tuple("Old")
                .field(&std::any::type_name::<BoxedConnector>().to_string())
                .finish(),
            Self::New(_) => f
                .debug_tuple("New")
                .field(&std::any::type_name::<BoxedConnectorV2>().to_string())
                .finish(),
        }
    }
}

#[allow(missing_debug_implementations)]
/// Enum representing the Connector Integration
#[derive(Clone)]
pub enum ConnectorIntegrationEnum<'a, F, ResourceCommonData, Req, Resp> {
    /// Old connector integration type
    Old(BoxedConnectorIntegration<'a, F, Req, Resp>),
    /// New connector integration type
    New(BoxedConnectorIntegrationV2<'a, F, ResourceCommonData, Req, Resp>),
}

/// Alias for Box<dyn ConnectorIntegrationInterface>
pub type BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> =
    Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;

impl ConnectorEnum {
    /// Get the connector integration
    ///
    /// # Returns
    ///
    /// A `BoxedConnectorIntegrationInterface` containing the connector integration
    pub fn get_connector_integration<F, ResourceCommonData, Req, Resp>(
        &self,
    ) -> BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>
    where
        dyn Connector + Sync: ConnectorIntegration<F, Req, Resp>,
        dyn ConnectorV2 + Sync: ConnectorIntegrationV2<F, ResourceCommonData, Req, Resp>,
        ResourceCommonData: RouterDataConversion<F, Req, Resp> + Clone + 'static,
        F: Clone + 'static,
        Req: Clone + 'static,
        Resp: Clone + 'static,
    {
        match self {
            Self::Old(old_integration) => Box::new(ConnectorIntegrationEnum::Old(
                old_integration.get_connector_integration(),
            )),
            Self::New(new_integration) => Box::new(ConnectorIntegrationEnum::New(
                new_integration.get_connector_integration_v2(),
            )),
        }
    }
    /// validates the file upload
    pub fn validate_file_upload(
        &self,
        purpose: api::files::FilePurpose,
        file_size: i32,
        file_type: mime::Mime,
    ) -> CustomResult<(), errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.validate_file_upload(purpose, file_size, file_type),
            Self::New(connector) => {
                connector.validate_file_upload_v2(purpose, file_size, file_type)
            }
        }
    }
}

#[async_trait::async_trait]
impl IncomingWebhook for ConnectorEnum {
    fn get_webhook_body_decoding_algorithm(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::DecodeMessage + Send>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_body_decoding_algorithm(request),
            Self::New(connector) => connector.get_webhook_body_decoding_algorithm(request),
        }
    }

    fn get_webhook_body_decoding_message(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_body_decoding_message(request),
            Self::New(connector) => connector.get_webhook_body_decoding_message(request),
        }
    }

    async fn decode_webhook_body(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        connector_name: &str,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => {
                connector
                    .decode_webhook_body(
                        request,
                        merchant_id,
                        connector_webhook_details,
                        connector_name,
                    )
                    .await
            }
            Self::New(connector) => {
                connector
                    .decode_webhook_body(
                        request,
                        merchant_id,
                        connector_webhook_details,
                        connector_name,
                    )
                    .await
            }
        }
    }

    fn get_webhook_source_verification_algorithm(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_source_verification_algorithm(request),
            Self::New(connector) => connector.get_webhook_source_verification_algorithm(request),
        }
    }

    async fn get_webhook_source_verification_merchant_secret(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_name: &str,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<api_models::webhooks::ConnectorWebhookSecrets, errors::ConnectorError> {
        match self {
            Self::Old(connector) => {
                connector
                    .get_webhook_source_verification_merchant_secret(
                        merchant_id,
                        connector_name,
                        connector_webhook_details,
                    )
                    .await
            }
            Self::New(connector) => {
                connector
                    .get_webhook_source_verification_merchant_secret(
                        merchant_id,
                        connector_name,
                        connector_webhook_details,
                    )
                    .await
            }
        }
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector
                .get_webhook_source_verification_signature(request, connector_webhook_secrets),
            Self::New(connector) => connector
                .get_webhook_source_verification_signature(request, connector_webhook_secrets),
        }
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_source_verification_message(
                request,
                merchant_id,
                connector_webhook_secrets,
            ),
            Self::New(connector) => connector.get_webhook_source_verification_message(
                request,
                merchant_id,
                connector_webhook_secrets,
            ),
        }
    }

    async fn verify_webhook_source(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        connector_account_details: crypto::Encryptable<masking::Secret<serde_json::Value>>,
        connector_name: &str,
    ) -> CustomResult<bool, errors::ConnectorError> {
        match self {
            Self::Old(connector) => {
                connector
                    .verify_webhook_source(
                        request,
                        merchant_id,
                        connector_webhook_details,
                        connector_account_details,
                        connector_name,
                    )
                    .await
            }
            Self::New(connector) => {
                connector
                    .verify_webhook_source(
                        request,
                        merchant_id,
                        connector_webhook_details,
                        connector_account_details,
                        connector_name,
                    )
                    .await
            }
        }
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_object_reference_id(request),
            Self::New(connector) => connector.get_webhook_object_reference_id(request),
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_event_type(request),
            Self::New(connector) => connector.get_webhook_event_type(request),
        }
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_resource_object(request),
            Self::New(connector) => connector.get_webhook_resource_object(request),
        }
    }

    fn get_webhook_api_response(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        error_kind: Option<IncomingWebhookFlowError>,
    ) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_webhook_api_response(request, error_kind),
            Self::New(connector) => connector.get_webhook_api_response(request, error_kind),
        }
    }

    fn get_dispute_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<disputes::DisputePayload, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_dispute_details(request),
            Self::New(connector) => connector.get_dispute_details(request),
        }
    }

    fn get_external_authentication_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ExternalAuthenticationPayload, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_external_authentication_details(request),
            Self::New(connector) => connector.get_external_authentication_details(request),
        }
    }

    fn get_mandate_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
        errors::ConnectorError,
    > {
        match self {
            Self::Old(connector) => connector.get_mandate_details(request),
            Self::New(connector) => connector.get_mandate_details(request),
        }
    }

    fn get_network_txn_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
        errors::ConnectorError,
    > {
        match self {
            Self::Old(connector) => connector.get_network_txn_id(request),
            Self::New(connector) => connector.get_network_txn_id(request),
        }
    }

    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
    fn get_revenue_recovery_invoice_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        hyperswitch_domain_models::revenue_recovery::RevenueRecoveryInvoiceData,
        errors::ConnectorError,
    > {
        match self {
            Self::Old(connector) => connector.get_revenue_recovery_invoice_details(request),
            Self::New(connector) => connector.get_revenue_recovery_invoice_details(request),
        }
    }

    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
    fn get_revenue_recovery_attempt_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        hyperswitch_domain_models::revenue_recovery::RevenueRecoveryAttemptData,
        errors::ConnectorError,
    > {
        match self {
            Self::Old(connector) => connector.get_revenue_recovery_attempt_details(request),
            Self::New(connector) => connector.get_revenue_recovery_attempt_details(request),
        }
    }
}

impl ConnectorRedirectResponse for ConnectorEnum {
    fn get_flow_type(
        &self,
        query_params: &str,
        json_payload: Option<serde_json::Value>,
        action: PaymentAction,
    ) -> CustomResult<common_enums::CallConnectorAction, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_flow_type(query_params, json_payload, action),
            Self::New(connector) => connector.get_flow_type(query_params, json_payload, action),
        }
    }
}

impl ConnectorValidation for ConnectorEnum {
    fn validate_connector_against_payment_request(
        &self,
        capture_method: Option<common_enums::CaptureMethod>,
        payment_method: common_enums::PaymentMethod,
        pmt: Option<common_enums::PaymentMethodType>,
    ) -> CustomResult<(), errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.validate_connector_against_payment_request(
                capture_method,
                payment_method,
                pmt,
            ),
            Self::New(connector) => connector.validate_connector_against_payment_request(
                capture_method,
                payment_method,
                pmt,
            ),
        }
    }

    fn validate_mandate_payment(
        &self,
        pm_type: Option<common_enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.validate_mandate_payment(pm_type, pm_data),
            Self::New(connector) => connector.validate_mandate_payment(pm_type, pm_data),
        }
    }

    fn validate_psync_reference_id(
        &self,
        data: &hyperswitch_domain_models::router_request_types::PaymentsSyncData,
        is_three_ds: bool,
        status: common_enums::enums::AttemptStatus,
        connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<(), errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.validate_psync_reference_id(
                data,
                is_three_ds,
                status,
                connector_meta_data,
            ),
            Self::New(connector) => connector.validate_psync_reference_id(
                data,
                is_three_ds,
                status,
                connector_meta_data,
            ),
        }
    }

    fn is_webhook_source_verification_mandatory(&self) -> bool {
        match self {
            Self::Old(connector) => connector.is_webhook_source_verification_mandatory(),
            Self::New(connector) => connector.is_webhook_source_verification_mandatory(),
        }
    }
}

impl ConnectorSpecifications for ConnectorEnum {
    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        match self {
            Self::Old(connector) => connector.get_supported_payment_methods(),
            Self::New(connector) => connector.get_supported_payment_methods(),
        }
    }

    /// Supported webhooks flows
    fn get_supported_webhook_flows(&self) -> Option<&'static [common_enums::EventClass]> {
        match self {
            Self::Old(connector) => connector.get_supported_webhook_flows(),
            Self::New(connector) => connector.get_supported_webhook_flows(),
        }
    }

    /// Details related to connector
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        match self {
            Self::Old(connector) => connector.get_connector_about(),
            Self::New(connector) => connector.get_connector_about(),
        }
    }

    /// Check if connector supports authentication token
    fn authentication_token_for_token_creation(&self) -> bool {
        match self {
            Self::Old(connector) => connector.authentication_token_for_token_creation(),
            Self::New(connector) => connector.authentication_token_for_token_creation(),
        }
    }

    #[cfg(feature = "v1")]
    fn generate_connector_request_reference_id(
        &self,
        payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
        payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
        is_config_enabled_to_send_payment_id_as_connector_request_id: bool,
    ) -> String {
        match self {
            Self::Old(connector) => connector.generate_connector_request_reference_id(
                payment_intent,
                payment_attempt,
                is_config_enabled_to_send_payment_id_as_connector_request_id,
            ),
            Self::New(connector) => connector.generate_connector_request_reference_id(
                payment_intent,
                payment_attempt,
                is_config_enabled_to_send_payment_id_as_connector_request_id,
            ),
        }
    }

    #[cfg(feature = "v2")]
    /// Generate connector request reference ID
    fn generate_connector_request_reference_id(
        &self,
        payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
        payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
    ) -> String {
        match self {
            Self::Old(connector) => {
                connector.generate_connector_request_reference_id(payment_intent, payment_attempt)
            }
            Self::New(connector) => {
                connector.generate_connector_request_reference_id(payment_intent, payment_attempt)
            }
        }
    }

    /// Check if connector requires create customer call
    fn should_call_connector_customer(
        &self,
        payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
    ) -> bool {
        match self {
            Self::Old(connector) => connector.should_call_connector_customer(payment_attempt),
            Self::New(connector) => connector.should_call_connector_customer(payment_attempt),
        }
    }
}

impl ConnectorCommon for ConnectorEnum {
    fn id(&self) -> &'static str {
        match self {
            Self::Old(connector) => connector.id(),
            Self::New(connector) => connector.id(),
        }
    }

    fn get_currency_unit(&self) -> CurrencyUnit {
        match self {
            Self::Old(connector) => connector.get_currency_unit(),
            Self::New(connector) => connector.get_currency_unit(),
        }
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.get_auth_header(auth_type),
            Self::New(connector) => connector.get_auth_header(auth_type),
        }
    }

    fn common_get_content_type(&self) -> &'static str {
        match self {
            Self::Old(connector) => connector.common_get_content_type(),
            Self::New(connector) => connector.common_get_content_type(),
        }
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        match self {
            Self::Old(connector) => connector.base_url(connectors),
            Self::New(connector) => connector.base_url(connectors),
        }
    }

    fn build_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        match self {
            Self::Old(connector) => connector.build_error_response(res, event_builder),
            Self::New(connector) => connector.build_error_response(res, event_builder),
        }
    }
}

/// Trait representing the connector integration interface
///
/// This trait defines the methods required for a connector integration interface.
pub trait ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>: Send + Sync {
    /// Clone the connector integration interface
    ///
    /// # Returns
    ///
    /// A `Box` containing the cloned connector integration interface
    fn clone_box(
        &self,
    ) -> Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;
    /// Get the multiple capture sync method
    ///
    /// # Returns
    ///
    /// A `CustomResult` containing the `CaptureSyncMethod` or a `ConnectorError`
    fn get_multiple_capture_sync_method(
        &self,
    ) -> CustomResult<CaptureSyncMethod, errors::ConnectorError>;
    /// Build a request for the connector integration
    ///
    /// # Arguments
    ///
    /// * `req` - A reference to the RouterData
    /// # Returns
    ///
    /// A `CustomResult` containing an optional Request or a ConnectorError
    fn build_request(
        &self,
        req: &RouterData<F, Req, Resp>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError>;
    /// handles response from the connector
    fn handle_response(
        &self,
        data: &RouterData<F, Req, Resp>,
        event_builder: Option<&mut ConnectorEvent>,
        _res: types::Response,
    ) -> CustomResult<RouterData<F, Req, Resp>, errors::ConnectorError>
    where
        F: Clone,
        Req: Clone,
        Resp: Clone;
    /// Get the error response
    ///
    /// # Arguments
    ///
    /// * `res` - The response
    /// * `event_builder` - An optional event builder
    ///
    /// # Returns
    ///
    /// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
    fn get_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError>;
    /// Get the 5xx error response
    ///
    /// # Arguments
    ///
    /// * `res` - The response
    /// * `event_builder` - An optional event builder
    ///
    /// # Returns
    ///
    /// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
    fn get_5xx_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError>;
}

impl<T: 'static, ResourceCommonData: 'static, Req: 'static, Resp: 'static>
    ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp>
    for ConnectorIntegrationEnum<'static, T, ResourceCommonData, Req, Resp>
where
    ResourceCommonData: RouterDataConversion<T, Req, Resp> + Clone,
    T: Clone,
    Req: Clone,
    Resp: Clone,
{
    fn get_multiple_capture_sync_method(
        &self,
    ) -> CustomResult<CaptureSyncMethod, errors::ConnectorError> {
        match self {
            ConnectorIntegrationEnum::Old(old_integration) => {
                old_integration.get_multiple_capture_sync_method()
            }
            ConnectorIntegrationEnum::New(new_integration) => {
                new_integration.get_multiple_capture_sync_method()
            }
        }
    }
    fn build_request(
        &self,
        req: &RouterData<T, Req, Resp>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        match self {
            ConnectorIntegrationEnum::Old(old_integration) => {
                old_integration.build_request(req, connectors)
            }
            ConnectorIntegrationEnum::New(new_integration) => {
                let new_router_data = ResourceCommonData::from_old_router_data(req)?;
                new_integration.build_request_v2(&new_router_data)
            }
        }
    }
    fn handle_response(
        &self,
        data: &RouterData<T, Req, Resp>,
        event_builder: Option<&mut ConnectorEvent>,
        res: types::Response,
    ) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
    where
        T: Clone,
        Req: Clone,
        Resp: Clone,
    {
        match self {
            ConnectorIntegrationEnum::Old(old_integration) => {
                old_integration.handle_response(data, event_builder, res)
            }
            ConnectorIntegrationEnum::New(new_integration) => {
                let new_router_data = ResourceCommonData::from_old_router_data(data)?;
                new_integration
                    .handle_response_v2(&new_router_data, event_builder, res)
                    .map(ResourceCommonData::to_old_router_data)?
            }
        }
    }
    fn get_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        match self {
            ConnectorIntegrationEnum::Old(old_integration) => {
                old_integration.get_error_response(res, event_builder)
            }
            ConnectorIntegrationEnum::New(new_integration) => {
                new_integration.get_error_response_v2(res, event_builder)
            }
        }
    }
    fn get_5xx_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        match self {
            ConnectorIntegrationEnum::Old(old_integration) => {
                old_integration.get_5xx_error_response(res, event_builder)
            }
            ConnectorIntegrationEnum::New(new_integration) => {
                new_integration.get_5xx_error_response(res, event_builder)
            }
        }
    }

    fn clone_box(
        &self,
    ) -> Box<dyn ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp> + Send + Sync>
    {
        Box::new(self.clone())
    }
}

impl api::ConnectorTransactionId for ConnectorEnum {
    /// Get the connector transaction ID
    ///
    /// # Arguments
    ///
    /// * `payment_attempt` - The payment attempt
    ///
    /// # Returns
    ///
    /// A `Result` containing an optional transaction ID or an ApiErrorResponse
    fn connector_transaction_id(
        &self,
        payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        match self {
            Self::Old(connector) => connector.connector_transaction_id(payment_attempt),
            Self::New(connector) => connector.connector_transaction_id(payment_attempt),
        }
    }
}


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

pub fn new() -> &'static Self


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

pub struct UnifiedConnectorServiceClientConfig


// Implementation: impl api::PaymentsCompleteAuthorize for for Nexixpay
// File: crates/hyperswitch_connectors/src/connectors/nexixpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentsCompleteAuthorize for for Nexixpay


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

pub fn do_gsm_multiple_connector_actions(
    state: &app::SessionState,
    mut connectors_routing_data: IntoIter<api::ConnectorRoutingData>,
    original_connector_data: api::ConnectorData,
    payout_data: &mut PayoutData,
    merchant_context: &domain::MerchantContext,
) -> RouterResult<()>


// File: crates/api_models/src/three_ds_decision_rule.rs
// Module: api_models
// Public structs: 7

use euclid::frontend::dir::enums::{
    CustomerDeviceDisplaySize, CustomerDevicePlatform, CustomerDeviceType,
};
use utoipa::ToSchema;

/// Represents the payment data used in the 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct PaymentData {
    /// The amount of the payment in minor units (e.g., cents for USD).
    #[schema(value_type = i64)]
    pub amount: common_utils::types::MinorUnit,
    /// The currency of the payment.
    #[schema(value_type = Currency)]
    pub currency: common_enums::Currency,
}

/// Represents metadata about the payment method used in the 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct PaymentMethodMetaData {
    /// The card network (e.g., Visa, Mastercard) if the payment method is a card.
    #[schema(value_type = CardNetwork)]
    pub card_network: Option<common_enums::CardNetwork>,
}

/// Represents data about the customer's device used in the 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct CustomerDeviceData {
    /// The platform of the customer's device (e.g., Web, Android, iOS).
    pub platform: Option<CustomerDevicePlatform>,
    /// The type of the customer's device (e.g., Mobile, Tablet, Desktop).
    pub device_type: Option<CustomerDeviceType>,
    /// The display size of the customer's device.
    pub display_size: Option<CustomerDeviceDisplaySize>,
}

/// Represents data about the issuer used in the 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct IssuerData {
    /// The name of the issuer.
    pub name: Option<String>,
    /// The country of the issuer.
    #[schema(value_type = Country)]
    pub country: Option<common_enums::Country>,
}

/// Represents data about the acquirer used in the 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct AcquirerData {
    /// The country of the acquirer.
    #[schema(value_type = Country)]
    pub country: Option<common_enums::Country>,
    /// The fraud rate associated with the acquirer.
    pub fraud_rate: Option<f64>,
}

/// Represents the request to execute a 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct ThreeDsDecisionRuleExecuteRequest {
    /// The ID of the routing algorithm to be executed.
    #[schema(value_type = String)]
    pub routing_id: common_utils::id_type::RoutingId,
    /// Data related to the payment.
    pub payment: PaymentData,
    /// Optional metadata about the payment method.
    pub payment_method: Option<PaymentMethodMetaData>,
    /// Optional data about the customer's device.
    pub customer_device: Option<CustomerDeviceData>,
    /// Optional data about the issuer.
    pub issuer: Option<IssuerData>,
    /// Optional data about the acquirer.
    pub acquirer: Option<AcquirerData>,
}

/// Represents the response from executing a 3DS decision rule.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct ThreeDsDecisionRuleExecuteResponse {
    /// The decision made by the 3DS decision rule engine.
    #[schema(value_type = ThreeDSDecision)]
    pub decision: common_types::three_ds_decision_rule_engine::ThreeDSDecision,
}

impl common_utils::events::ApiEventMetric for ThreeDsDecisionRuleExecuteRequest {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::ThreeDsDecisionRule)
    }
}

impl common_utils::events::ApiEventMetric for ThreeDsDecisionRuleExecuteResponse {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::ThreeDsDecisionRule)
    }
}


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

pub struct PSyncResponse


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

impl ConnectorSpecifications for for Paysafe


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

impl behaviour::Conversion for for PaymentAttempt


// Implementation: impl GlobalPaymentMethodSessionId
// File: crates/common_utils/src/id_type/global_id/payment_methods.rs
// Module: common_utils
// Methods: 3 total (3 public)

impl GlobalPaymentMethodSessionId


// Struct: CardInfoMigrateResponseRecord
// File: crates/api_models/src/cards_info.rs
// Module: api_models
// Implementations: 0

pub struct CardInfoMigrateResponseRecord


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

impl User


// Function: add_apple_pay_flow_metrics
// File: crates/router/src/utils.rs
// Module: router

pub fn add_apple_pay_flow_metrics(
    apple_pay_flow: &Option<domain::ApplePayFlow>,
    connector: Option<String>,
    merchant_id: id_type::MerchantId,
)


// Struct: ShouldCollectCvvDuringPayment
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Implementations: 2
// Traits: Deref, Default

pub struct ShouldCollectCvvDuringPayment


// Struct: ZenWebhookEventType
// File: crates/hyperswitch_connectors/src/connectors/zen/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ZenWebhookEventType


// Implementation: impl ApiEventMetric for for CardInfoUpdateRequest
// File: crates/api_models/src/cards_info.rs
// Module: api_models
// Methods: 0 total (0 public)

impl ApiEventMetric for for CardInfoUpdateRequest


// Implementation: impl BlocklistLookupNew
// File: crates/diesel_models/src/query/blocklist_lookup.rs
// Module: diesel_models
// Methods: 1 total (0 public)

impl BlocklistLookupNew


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

impl api::PaymentSync for for CtpMastercard


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

pub struct Links


// Implementation: impl Config
// File: crates/diesel_models/src/query/configs.rs
// Module: diesel_models
// Methods: 3 total (0 public)

impl Config


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

pub struct AliPayQr


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

impl ProfileUpdateInternal


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

impl api::Refund for for Finix


// Struct: VaultDelete
// File: crates/router/src/types/payment_methods.rs
// Module: router
// Implementations: 1
// Traits: VaultingInterface

pub struct VaultDelete


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

pub struct V2AdditionalParams


// Struct: ApplePayTokenPaymentInformation
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApplePayTokenPaymentInformation