    return_raw_connector_response: Option<bool>,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    FData: Send + Sync + Clone,
    Op: Operation<F, Req, Data = D> + ValidateStatusForOperation + Send + Sync + Clone,
    Req: Debug,
    D: OperationSessionGetters<F>
        + OperationSessionSetters<F>
        + transformers::GenerateResponse<Res>
        + Send
        + Sync
        + Clone,
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    PaymentResponse: Operation<F, FData, Data = D>,

    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,
{
    operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    let get_tracker_response = operation
        .to_get_tracker()?
        .get_trackers(
            &state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;

    let (payment_data, _req, connector_http_status_code, external_latency) =
        external_vault_proxy_for_payments_operation_core::<_, _, _, _, _>(
            &state,
            req_state,
            merchant_context.clone(),
            profile.clone(),
            operation.clone(),
            req,
            get_tracker_response,
            call_connector_action,
            header_payload.clone(),
            return_raw_connector_response,
        )
        .await?;

    payment_data.generate_response(
        &state,
        connector_http_status_code,
        external_latency,
        header_payload.x_hs_latency,
        &merchant_context,
        &profile,
        None,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn record_attempt_core(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    req: api_models::payments::PaymentsAttemptRecordRequest,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResponse<api_models::payments::PaymentAttemptRecordResponse> {
    tracing::Span::current().record(
        "merchant_id",
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
    );

    let operation: &operations::payment_attempt_record::PaymentAttemptRecord =
        &operations::payment_attempt_record::PaymentAttemptRecord;
    let boxed_operation: BoxedOperation<
        '_,
        api::RecordAttempt,
        api_models::payments::PaymentsAttemptRecordRequest,
        domain_payments::PaymentAttemptRecordData<api::RecordAttempt>,
    > = Box::new(operation);

    let _validate_result = boxed_operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    tracing::Span::current().record("global_payment_id", payment_id.get_string_repr());

    let operations::GetTrackerResponse { payment_data } = boxed_operation
        .to_get_tracker()?
        .get_trackers(
            &state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;
    let default_payment_status_data = PaymentStatusData {
        flow: PhantomData,
        payment_intent: payment_data.payment_intent.clone(),
        payment_attempt: payment_data.payment_attempt.clone(),
        attempts: None,
        should_sync_with_connector: false,
        payment_address: payment_data.payment_address.clone(),
        merchant_connector_details: None,
    };

    let payment_status_data = (req.triggered_by == common_enums::TriggeredBy::Internal)
    .then(|| default_payment_status_data.clone())
    .async_unwrap_or_else(|| async {
        match Box::pin(proxy_for_payments_operation_core::<
            api::PSync,
            _,
            _,
            _,
            PaymentStatusData<api::PSync>,
        >(
            &state,
            req_state.clone(),
            merchant_context.clone(),
            profile.clone(),
            operations::PaymentGet,
            api::PaymentsRetrieveRequest {
                force_sync: true,
                expand_attempts: false,
                param: None,
                return_raw_connector_response: None,
                merchant_connector_details: None,
            },
            operations::GetTrackerResponse {
                payment_data: PaymentStatusData {
                    flow: PhantomData,
                    payment_intent: payment_data.payment_intent.clone(),
                    payment_attempt: payment_data.payment_attempt.clone(),
                    attempts: None,
                    should_sync_with_connector: true,
                    payment_address: payment_data.payment_address.clone(),
                    merchant_connector_details: None,
                },
            },
            CallConnectorAction::Trigger,
            HeaderPayload::default(),
            None,
        ))
        .await
        {
            Ok((data, _, _, _)) => data,
            Err(err) => {
                router_env::logger::error!(error=?err, "proxy_for_payments_operation_core failed for external payment attempt");
                default_payment_status_data
            }
        }
    })
    .await;

    let record_payment_data = domain_payments::PaymentAttemptRecordData {
        flow: PhantomData,
        payment_intent: payment_status_data.payment_intent,
        payment_attempt: payment_status_data.payment_attempt,
        revenue_recovery_data: payment_data.revenue_recovery_data.clone(),
        payment_address: payment_data.payment_address.clone(),
    };

    let (_operation, final_payment_data) = boxed_operation
        .to_update_tracker()?
        .update_trackers(
            &state,
            req_state,
            record_payment_data,
            None,
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None,
            header_payload.clone(),
        )
        .await?;

    transformers::GenerateResponse::generate_response(
        final_payment_data,
        &state,
        None,
        None,
        header_payload.x_hs_latency,
        &merchant_context,
        &profile,
        None,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn payments_intent_core<F, Res, Req, Op, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
    Req: Debug + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
    Res: transformers::ToResponse<F, D, Op>,
{
    let (payment_data, _req, customer) = payments_intent_operation_core::<_, _, _, _>(
        &state,
        req_state,
        merchant_context.clone(),
        profile,
        operation.clone(),
        req,
        payment_id,
        header_payload.clone(),
    )
    .await?;

    Res::generate_response(
        payment_data,
        customer,
        &state.base_url,
        operation,
        &state.conf.connector_request_reference_id_config,
        None,
        None,
        header_payload.x_hs_latency,
        &merchant_context,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn payments_list_attempts_using_payment_intent_id<F, Res, Req, Op, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
    Req: Debug + Clone,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
    Res: transformers::ToResponse<F, D, Op>,
{
    let (payment_data, _req, customer) = payments_attempt_operation_core::<_, _, _, _>(
        &state,
        req_state,
        merchant_context.clone(),
        profile,
        operation.clone(),
        req,
        payment_id,
        header_payload.clone(),
    )
    .await?;

    Res::generate_response(
        payment_data,
        customer,
        &state.base_url,
        operation,
        &state.conf.connector_request_reference_id_config,
        None,
        None,
        header_payload.x_hs_latency,
        &merchant_context,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn payments_get_intent_using_merchant_reference(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    req_state: ReqState,
    merchant_reference_id: &id_type::PaymentReferenceId,
    header_payload: HeaderPayload,
) -> RouterResponse<api::PaymentsIntentResponse> {
    let db = state.store.as_ref();
    let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
    let key_manager_state = &(&state).into();
    let payment_intent = db
        .find_payment_intent_by_merchant_reference_id_profile_id(
            key_manager_state,
            merchant_reference_id,
            profile.get_id(),
            merchant_context.get_merchant_key_store(),
            &storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    let (payment_data, _req, customer) = Box::pin(payments_intent_operation_core::<
        api::PaymentGetIntent,
        _,
        _,
        PaymentIntentData<api::PaymentGetIntent>,
    >(
        &state,
        req_state,
        merchant_context.clone(),
        profile.clone(),
        operations::PaymentGetIntent,
        api_models::payments::PaymentsGetIntentRequest {
            id: payment_intent.get_id().clone(),
        },
        payment_intent.get_id().clone(),
        header_payload.clone(),
    ))
    .await?;

    transformers::ToResponse::<
        api::PaymentGetIntent,
        PaymentIntentData<api::PaymentGetIntent>,
        operations::PaymentGetIntent,
    >::generate_response(
        payment_data,
        customer,
        &state.base_url,
        operations::PaymentGetIntent,
        &state.conf.connector_request_reference_id_config,
        None,
        None,
        header_payload.x_hs_latency,
        &merchant_context,
    )
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn payments_core<F, Res, Req, Op, FData, D>(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
) -> RouterResponse<Res>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    FData: Send + Sync + Clone,
    Op: Operation<F, Req, Data = D> + ValidateStatusForOperation + Send + Sync + Clone,
    Req: Debug,
    D: OperationSessionGetters<F>
        + OperationSessionSetters<F>
        + transformers::GenerateResponse<Res>
        + Send
        + Sync
        + Clone,
    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,

    // To create updatable objects in post update tracker
    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,
{
    // Validate the request fields
    operation
        .to_validate_request()?
        .validate_request(&req, &merchant_context)?;

    // Get the tracker related information. This includes payment intent and payment attempt
    let get_tracker_response = operation
        .to_get_tracker()?
        .get_trackers(
            &state,
            &payment_id,
            &req,
            &merchant_context,
            &profile,
            &header_payload,
        )
        .await?;

    let (payment_data, connector_http_status_code, external_latency, connector_response_data) =
        if state.conf.merchant_id_auth.merchant_id_auth_enabled {
            let (
                payment_data,
                _req,
                connector_http_status_code,
                external_latency,
                connector_response_data,
            ) = internal_payments_operation_core::<_, _, _, _, _>(
                &state,
                req_state,
                merchant_context.clone(),
                &profile,
                operation.clone(),
                req,
                get_tracker_response,
                call_connector_action,
                header_payload.clone(),
            )
            .await?;
            (
                payment_data,
                connector_http_status_code,
                external_latency,
                connector_response_data,
            )
        } else {
            let (
                payment_data,
                _req,
                _customer,
                connector_http_status_code,
                external_latency,
                connector_response_data,
            ) = payments_operation_core::<_, _, _, _, _>(
                &state,
                req_state,
                merchant_context.clone(),
                &profile,
                operation.clone(),
                req,
                get_tracker_response,
                call_connector_action,
                header_payload.clone(),
            )
            .await?;
            (
                payment_data,
                connector_http_status_code,
                external_latency,
                connector_response_data,
            )
        };

    payment_data.generate_response(
        &state,
        connector_http_status_code,
        external_latency,
        header_payload.x_hs_latency,
        &merchant_context,
        &profile,
        Some(connector_response_data),
    )
}

#[allow(clippy::too_many_arguments)]
#[cfg(feature = "v2")]
pub(crate) async fn payments_create_and_confirm_intent(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    request: payments_api::PaymentsRequest,
    header_payload: HeaderPayload,
) -> RouterResponse<payments_api::PaymentsResponse> {
    use hyperswitch_domain_models::{
        payments::PaymentIntentData, router_flow_types::PaymentCreateIntent,
    };

    let payment_id = id_type::GlobalPaymentId::generate(&state.conf.cell_information.id);

    let payload = payments_api::PaymentsCreateIntentRequest::from(&request);

    let create_intent_response = Box::pin(payments_intent_core::<
        PaymentCreateIntent,
        payments_api::PaymentsIntentResponse,
        _,
        _,
        PaymentIntentData<PaymentCreateIntent>,
    >(
        state.clone(),
        req_state.clone(),
        merchant_context.clone(),
        profile.clone(),
        operations::PaymentIntentCreate,
        payload,
        payment_id.clone(),
        header_payload.clone(),
    ))
    .await?;

    logger::info!(?create_intent_response);

    let create_intent_response = create_intent_response
        .get_json_body()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unexpected response from payments core")?;

    let payload = payments_api::PaymentsConfirmIntentRequest::from(&request);

    let confirm_intent_response = decide_authorize_or_setup_intent_flow(
        state,
        req_state,
        merchant_context,
        profile,
        &create_intent_response,
        payload,
        payment_id,
        header_payload,
    )
    .await?;

    logger::info!(?confirm_intent_response);

    Ok(confirm_intent_response)
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
async fn decide_authorize_or_setup_intent_flow(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    create_intent_response: &payments_api::PaymentsIntentResponse,
    confirm_intent_request: payments_api::PaymentsConfirmIntentRequest,
    payment_id: id_type::GlobalPaymentId,
    header_payload: HeaderPayload,
) -> RouterResponse<payments_api::PaymentsResponse> {
    use hyperswitch_domain_models::{
        payments::PaymentConfirmData,
        router_flow_types::{Authorize, SetupMandate},
    };

    if create_intent_response.amount_details.order_amount == MinorUnit::zero() {
        Box::pin(payments_core::<
            SetupMandate,
            api_models::payments::PaymentsResponse,
            _,
            _,
            _,
            PaymentConfirmData<SetupMandate>,
        >(
            state,
            req_state,
            merchant_context,
            profile,
            operations::PaymentIntentConfirm,
            confirm_intent_request,
            payment_id,
            CallConnectorAction::Trigger,
            header_payload,
        ))
        .await
    } else {
        Box::pin(payments_core::<
            Authorize,
            api_models::payments::PaymentsResponse,
            _,
            _,
            _,
            PaymentConfirmData<Authorize>,
        >(
            state,
            req_state,
            merchant_context,
            profile,
            operations::PaymentIntentConfirm,
            confirm_intent_request,
            payment_id,
            CallConnectorAction::Trigger,
            header_payload,
        ))
        .await
    }
}

fn is_start_pay<Op: Debug>(operation: &Op) -> bool {
    format!("{operation:?}").eq("PaymentStart")
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, serde::Serialize)]
pub struct PaymentsRedirectResponseData {
    pub connector: Option<String>,
    pub param: Option<String>,
    pub merchant_id: Option<id_type::MerchantId>,
    pub json_payload: Option<serde_json::Value>,
    pub resource_id: api::PaymentIdType,
    pub force_sync: bool,
    pub creds_identifier: Option<String>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize)]
pub struct PaymentsRedirectResponseData {
    pub payment_id: id_type::GlobalPaymentId,
    pub query_params: String,
    pub json_payload: Option<serde_json::Value>,
}

#[async_trait::async_trait]
pub trait PaymentRedirectFlow: Sync {
    // Associated type for call_payment_flow response
    type PaymentFlowResponse;

    #[cfg(feature = "v1")]
    #[allow(clippy::too_many_arguments)]
    async fn call_payment_flow(
        &self,
        state: &SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        req: PaymentsRedirectResponseData,
        connector_action: CallConnectorAction,
        connector: String,
        payment_id: id_type::PaymentId,
    ) -> RouterResult<Self::PaymentFlowResponse>;

    #[cfg(feature = "v2")]
    #[allow(clippy::too_many_arguments)]
    async fn call_payment_flow(
        &self,
        state: &SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        profile: domain::Profile,
        req: PaymentsRedirectResponseData,
    ) -> RouterResult<Self::PaymentFlowResponse>;

    fn get_payment_action(&self) -> services::PaymentAction;

    #[cfg(feature = "v1")]
    fn generate_response(
        &self,
        payment_flow_response: &Self::PaymentFlowResponse,
        payment_id: id_type::PaymentId,
        connector: String,
    ) -> RouterResult<services::ApplicationResponse<api::RedirectionResponse>>;

    #[cfg(feature = "v2")]
    fn generate_response(
        &self,
        payment_flow_response: &Self::PaymentFlowResponse,
    ) -> RouterResult<services::ApplicationResponse<api::RedirectionResponse>>;

    #[cfg(feature = "v1")]
    async fn handle_payments_redirect_response(
        &self,
        state: SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        req: PaymentsRedirectResponseData,
    ) -> RouterResponse<api::RedirectionResponse> {
        metrics::REDIRECTION_TRIGGERED.add(
            1,
            router_env::metric_attributes!(
                (
                    "connector",
                    req.connector.to_owned().unwrap_or("null".to_string()),
                ),
                (
                    "merchant_id",
                    merchant_context.get_merchant_account().get_id().clone()
                ),
            ),
        );
        let connector = req.connector.clone().get_required_value("connector")?;

        let query_params = req.param.clone().get_required_value("param")?;

        #[cfg(feature = "v1")]
        let resource_id = api::PaymentIdTypeExt::get_payment_intent_id(&req.resource_id)
            .change_context(errors::ApiErrorResponse::MissingRequiredField {
                field_name: "payment_id",
            })?;

        #[cfg(feature = "v2")]
        //TODO: Will get the global payment id from the resource id, we need to handle this in the further flow
        let resource_id: id_type::PaymentId = todo!();

        // This connector data is ephemeral, the call payment flow will get new connector data
        // with merchant account details, so the connector_id can be safely set to None here
        let connector_data = api::ConnectorData::get_connector_by_name(
            &state.conf.connectors,
            &connector,
            api::GetToken::Connector,
            None,
        )?;

        let flow_type = connector_data
            .connector
            .get_flow_type(
                &query_params,
                req.json_payload.clone(),
                self.get_payment_action(),
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to decide the response flow")?;

        let payment_flow_response = self
            .call_payment_flow(
                &state,
                req_state,
                merchant_context,
                req.clone(),
                flow_type,
                connector.clone(),
                resource_id.clone(),
            )
            .await?;

        self.generate_response(&payment_flow_response, resource_id, connector)
    }

    #[cfg(feature = "v2")]
    #[allow(clippy::too_many_arguments)]
    async fn handle_payments_redirect_response(
        &self,
        state: SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        profile: domain::Profile,
        request: PaymentsRedirectResponseData,
    ) -> RouterResponse<api::RedirectionResponse> {
        metrics::REDIRECTION_TRIGGERED.add(
            1,
            router_env::metric_attributes!((
                "merchant_id",
                merchant_context.get_merchant_account().get_id().clone()
            )),
        );

        let payment_flow_response = self
            .call_payment_flow(&state, req_state, merchant_context, profile, request)
            .await?;

        self.generate_response(&payment_flow_response)
    }
}

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

#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
    type PaymentFlowResponse = router_types::RedirectPaymentFlowResponse;

    #[allow(clippy::too_many_arguments)]
    async fn call_payment_flow(
        &self,
        state: &SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        req: PaymentsRedirectResponseData,
        connector_action: CallConnectorAction,
        _connector: String,
        _payment_id: id_type::PaymentId,
    ) -> RouterResult<Self::PaymentFlowResponse> {
        let key_manager_state = &state.into();
        let payment_confirm_req = api::PaymentsRequest {
            payment_id: Some(req.resource_id.clone()),
            merchant_id: req.merchant_id.clone(),
            merchant_connector_details: req.creds_identifier.map(|creds_id| {
                api::MerchantConnectorDetailsWrap {
                    creds_identifier: creds_id,
                    encoded_data: None,
                }
            }),
            feature_metadata: Some(api_models::payments::FeatureMetadata {
                redirect_response: Some(api_models::payments::RedirectResponse {
                    param: req.param.map(Secret::new),
                    json_payload: Some(req.json_payload.unwrap_or(serde_json::json!({})).into()),
                }),
                search_tags: None,
                apple_pay_recurring_details: None,
            }),
            ..Default::default()
        };
        let response = Box::pin(payments_core::<
            api::CompleteAuthorize,
            api::PaymentsResponse,
            _,
            _,
            _,
            _,
        >(
            state.clone(),
            req_state,
            merchant_context.clone(),
            None,
            operations::payment_complete_authorize::CompleteAuthorize,
            payment_confirm_req,
            services::api::AuthFlow::Merchant,
            connector_action,
            None,
            HeaderPayload::default(),
        ))
        .await?;
        let payments_response = match response {
            services::ApplicationResponse::Json(response) => Ok(response),
            services::ApplicationResponse::JsonWithHeaders((response, _)) => Ok(response),
            _ => Err(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to get the response in json"),
        }?;
        let profile_id = payments_response
            .profile_id
            .as_ref()
            .get_required_value("profile_id")?;
        let business_profile = state
            .store
            .find_business_profile_by_profile_id(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                profile_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
                id: profile_id.get_string_repr().to_owned(),
            })?;
        Ok(router_types::RedirectPaymentFlowResponse {
            payments_response,
            business_profile,
        })
    }

    fn get_payment_action(&self) -> services::PaymentAction {
        services::PaymentAction::CompleteAuthorize
    }

    fn generate_response(
        &self,
        payment_flow_response: &Self::PaymentFlowResponse,
        payment_id: id_type::PaymentId,
        connector: String,
    ) -> RouterResult<services::ApplicationResponse<api::RedirectionResponse>> {
        let payments_response = &payment_flow_response.payments_response;
        // There might be multiple redirections needed for some flows
        // If the status is requires customer action, then send the startpay url again
        // The redirection data must have been provided and updated by the connector
        let redirection_response = match payments_response.status {
            enums::IntentStatus::RequiresCustomerAction => {
                let startpay_url = payments_response
                    .next_action
                    .clone()
                    .and_then(|next_action_data| match next_action_data {
                        api_models::payments::NextActionData::RedirectToUrl { redirect_to_url } => Some(redirect_to_url),
                        api_models::payments::NextActionData::RedirectInsidePopup{popup_url, ..} => Some(popup_url),
                        api_models::payments::NextActionData::DisplayBankTransferInformation { .. } => None,
                        api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None,
                        api_models::payments::NextActionData::QrCodeInformation{..} => None,
                        api_models::payments::NextActionData::FetchQrCodeInformation{..} => None,
                        api_models::payments::NextActionData::DisplayVoucherInformation{ .. } => None,
                        api_models::payments::NextActionData::WaitScreenInformation{..} => None,
                        api_models::payments::NextActionData::ThreeDsInvoke{..} => None,
                        api_models::payments::NextActionData::InvokeSdkClient{..} => None,
                        api_models::payments::NextActionData::CollectOtp{ .. } => None,
                        api_models::payments::NextActionData::InvokeHiddenIframe{ .. } => None,
                    })
                    .ok_or(errors::ApiErrorResponse::InternalServerError)

                    .attach_printable(
                        "did not receive redirect to url when status is requires customer action",
                    )?;
                Ok(api::RedirectionResponse {
                    return_url: String::new(),
                    params: vec![],
                    return_url_with_query_params: startpay_url,
                    http_method: "GET".to_string(),
                    headers: vec![],
                })
            }
            // If the status is terminal status, then redirect to merchant return url to provide status
            enums::IntentStatus::Succeeded
            | enums::IntentStatus::Failed
            | enums::IntentStatus::Cancelled | enums::IntentStatus::RequiresCapture| enums::IntentStatus::Processing=> helpers::get_handle_response_url(
                payment_id,
                &payment_flow_response.business_profile,
                payments_response,
                connector,
            ),
            _ => Err(errors::ApiErrorResponse::InternalServerError).attach_printable_lazy(|| format!("Could not proceed with payment as payment status {} cannot be handled during redirection",payments_response.status))?
        }?;
        if payments_response
            .is_iframe_redirection_enabled
            .unwrap_or(false)
        {
            // html script to check if inside iframe, then send post message to parent for redirection else redirect self to return_url
            let html = core_utils::get_html_redirect_response_popup(
                redirection_response.return_url_with_query_params,
            )?;
            Ok(services::ApplicationResponse::Form(Box::new(
                services::RedirectionFormData {
                    redirect_form: services::RedirectForm::Html { html_data: html },
                    payment_method_data: None,
                    amount: payments_response.amount.to_string(),
                    currency: payments_response.currency.clone(),
                },
            )))
        } else {
            Ok(services::ApplicationResponse::JsonForRedirection(
                redirection_response,
            ))
        }
    }
}

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

#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl PaymentRedirectFlow for PaymentRedirectSync {
    type PaymentFlowResponse = router_types::RedirectPaymentFlowResponse;

    #[allow(clippy::too_many_arguments)]
    async fn call_payment_flow(
        &self,
        state: &SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        req: PaymentsRedirectResponseData,
        connector_action: CallConnectorAction,
        _connector: String,
        _payment_id: id_type::PaymentId,
    ) -> RouterResult<Self::PaymentFlowResponse> {
        let key_manager_state = &state.into();

        let payment_sync_req = api::PaymentsRetrieveRequest {
            resource_id: req.resource_id,
            merchant_id: req.merchant_id,
            param: req.param,
            force_sync: req.force_sync,
            connector: req.connector,
            merchant_connector_details: req.creds_identifier.map(|creds_id| {
                api::MerchantConnectorDetailsWrap {
                    creds_identifier: creds_id,
                    encoded_data: None,
                }
            }),
            client_secret: None,
            expand_attempts: None,
            expand_captures: None,
            all_keys_required: None,
        };
        let response = Box::pin(
            payments_core::<api::PSync, api::PaymentsResponse, _, _, _, _>(
                state.clone(),
                req_state,
                merchant_context.clone(),
                None,
                PaymentStatus,
                payment_sync_req,
                services::api::AuthFlow::Merchant,
                connector_action,
                None,
                HeaderPayload::default(),
            ),
        )
        .await?;
        let payments_response = match response {
            services::ApplicationResponse::Json(response) => Ok(response),
            services::ApplicationResponse::JsonWithHeaders((response, _)) => Ok(response),
            _ => Err(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to get the response in json"),
        }?;
        let profile_id = payments_response
            .profile_id
            .as_ref()
            .get_required_value("profile_id")?;
        let business_profile = state
            .store
            .find_business_profile_by_profile_id(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                profile_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
                id: profile_id.get_string_repr().to_owned(),
            })?;
        Ok(router_types::RedirectPaymentFlowResponse {
            payments_response,
            business_profile,
        })
    }
    fn generate_response(
        &self,
        payment_flow_response: &Self::PaymentFlowResponse,
        payment_id: id_type::PaymentId,
        connector: String,
    ) -> RouterResult<services::ApplicationResponse<api::RedirectionResponse>> {
        let payments_response = &payment_flow_response.payments_response;
        let redirect_response = helpers::get_handle_response_url(
            payment_id.clone(),
            &payment_flow_response.business_profile,
            payments_response,
            connector.clone(),
        )?;
        if payments_response
            .is_iframe_redirection_enabled
            .unwrap_or(false)
        {
            // html script to check if inside iframe, then send post message to parent for redirection else redirect self to return_url
            let html = core_utils::get_html_redirect_response_popup(
                redirect_response.return_url_with_query_params,
            )?;
            Ok(services::ApplicationResponse::Form(Box::new(
                services::RedirectionFormData {
                    redirect_form: services::RedirectForm::Html { html_data: html },
                    payment_method_data: None,
                    amount: payments_response.amount.to_string(),
                    currency: payments_response.currency.clone(),
                },
            )))
        } else {
            Ok(services::ApplicationResponse::JsonForRedirection(
                redirect_response,
            ))
        }
    }

    fn get_payment_action(&self) -> services::PaymentAction {
        services::PaymentAction::PSync
    }
}

#[cfg(feature = "v2")]
impl ValidateStatusForOperation for &PaymentRedirectSync {
    fn validate_status_for_operation(
        &self,
        intent_status: common_enums::IntentStatus,
    ) -> Result<(), errors::ApiErrorResponse> {
        match intent_status {
            common_enums::IntentStatus::RequiresCustomerAction => Ok(()),
            common_enums::IntentStatus::Succeeded
            | common_enums::IntentStatus::Conflicted
            | common_enums::IntentStatus::Failed
            | common_enums::IntentStatus::Cancelled
            | common_enums::IntentStatus::CancelledPostCapture
            | common_enums::IntentStatus::Processing
            | common_enums::IntentStatus::RequiresPaymentMethod
            | common_enums::IntentStatus::RequiresMerchantAction
            | common_enums::IntentStatus::RequiresCapture
            | common_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture
            | common_enums::IntentStatus::PartiallyCaptured
            | common_enums::IntentStatus::RequiresConfirmation
            | common_enums::IntentStatus::PartiallyCapturedAndCapturable
            | common_enums::IntentStatus::Expired => {
                Err(errors::ApiErrorResponse::PaymentUnexpectedState {
                    current_flow: format!("{self:?}"),
                    field_name: "status".to_string(),
                    current_value: intent_status.to_string(),
                    states: ["requires_customer_action".to_string()].join(", "),
                })
            }
        }
    }
}

#[cfg(feature = "v2")]
#[async_trait::async_trait]
impl PaymentRedirectFlow for PaymentRedirectSync {
    type PaymentFlowResponse =
        router_types::RedirectPaymentFlowResponse<PaymentStatusData<api::PSync>>;

    async fn call_payment_flow(
        &self,
        state: &SessionState,
        req_state: ReqState,
        merchant_context: domain::MerchantContext,
        profile: domain::Profile,
        req: PaymentsRedirectResponseData,
    ) -> RouterResult<Self::PaymentFlowResponse> {
        let payment_id = req.payment_id.clone();

        let payment_sync_request = api::PaymentsRetrieveRequest {
            param: Some(req.query_params.clone()),
            force_sync: true,
            expand_attempts: false,
            return_raw_connector_response: None,
            merchant_connector_details: None, // TODO: Implement for connectors requiring 3DS or redirection-based authentication flows.
        };

        let operation = operations::PaymentGet;
        let boxed_operation: BoxedOperation<
            '_,
            api::PSync,
            api::PaymentsRetrieveRequest,
            PaymentStatusData<api::PSync>,
        > = Box::new(operation);

        let get_tracker_response = boxed_operation
            .to_get_tracker()?
            .get_trackers(
                state,
                &payment_id,
                &payment_sync_request,
                &merchant_context,
                &profile,
                &HeaderPayload::default(),
            )
            .await?;

        let payment_data = &get_tracker_response.payment_data;
        self.validate_status_for_operation(payment_data.payment_intent.status)?;

        let payment_attempt = payment_data.payment_attempt.clone();

        let connector = payment_attempt
            .connector
            .as_ref()
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "connector is not set in payment attempt in finish redirection flow",
            )?;

        // This connector data is ephemeral, the call payment flow will get new connector data
        // with merchant account details, so the connector_id can be safely set to None here
        let connector_data = api::ConnectorData::get_connector_by_name(
            &state.conf.connectors,
            connector,
            api::GetToken::Connector,
            None,
        )?;

        let call_connector_action = connector_data
            .connector
            .get_flow_type(
                &req.query_params,
                req.json_payload.clone(),
                self.get_payment_action(),
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to decide the response flow")?;

        let (payment_data, _, _, _, _, _) =
            Box::pin(payments_operation_core::<api::PSync, _, _, _, _>(
                state,
                req_state,
                merchant_context,
                &profile,
                operation,
                payment_sync_request,
                get_tracker_response,
                call_connector_action,
                HeaderPayload::default(),
            ))
            .await?;

        Ok(router_types::RedirectPaymentFlowResponse {
            payment_data,
            profile,
        })
    }
    fn generate_response(
        &self,


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

impl Payu


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

pub struct ProviderMetadata


// Function: redis_error_receiver
// File: crates/drainer/src/handler.rs
// Module: drainer

pub fn redis_error_receiver(rx: oneshot::Receiver<()


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

pub fn get_payment_method_type(&self) -> Option<storage_enums::PaymentMethodType>


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

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

use api_models::webhooks::IncomingWebhookEvent;
use base64::Engine;
use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::{ByteSliceExt, BytesExt},
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::{report, ResultExt};
use http::header::ACCEPT;
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
        CompleteAuthorize, PreProcessing,
    },
    router_request_types::{
        AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData,
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData,
        PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData,
        PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData,
        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    consts::NO_ERROR_CODE,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::{Mask, PeekInterface};
use transformers::{self as shift4, Shift4PaymentsRequest, Shift4RefundRequest};

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

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

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Shift4
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 mut headers = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
            (
                ACCEPT.to_string(),
                self.get_content_type().to_string().into(),
            ),
        ];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        headers.append(&mut api_key);
        Ok(headers)
    }
}
impl ConnectorCommon for Shift4 {
    fn id(&self) -> &'static str {
        "shift4"
    }

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

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = shift4::Shift4AuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let api_key = format!(
            "Basic {}",
            common_utils::consts::BASE64_ENGINE.encode(format!("{}:", auth.api_key.peek()))
        );
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            api_key.into_masked(),
        )])
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response.error.message,
            reason: None,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Shift4 {}

impl api::Payment for Shift4 {}
impl api::PaymentVoid for Shift4 {}
impl api::PaymentSync for Shift4 {}
impl api::PaymentCapture for Shift4 {}
impl api::PaymentSession for Shift4 {}
impl api::PaymentAuthorize for Shift4 {}
impl api::PaymentsCompleteAuthorize for Shift4 {}
impl api::Refund for Shift4 {}
impl api::RefundExecute for Shift4 {}
impl api::RefundSync for Shift4 {}
impl api::PaymentToken for Shift4 {}
impl api::PaymentsPreProcessing for Shift4 {}

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

impl api::ConnectorAccessToken for Shift4 {}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Shift4 {
    // Not Implemented (R)
}

impl api::MandateSetup for Shift4 {}
impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Shift4 {
    fn build_request(
        &self,
        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(
            errors::ConnectorError::NotImplemented("Setup Mandate flow for Shift4".to_string())
                .into(),
        )
    }
}

#[async_trait::async_trait]
impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Shift4 {
    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!("{}charges", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?;
        let connector_req = Shift4PaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .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: shift4::Shift4NonThreeDsResponse = res
            .response
            .parse_struct("Shift4NonThreeDsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .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<Void, PaymentsCancelData, PaymentsResponseData> for Shift4 {
    fn build_request(
        &self,
        _req: &hyperswitch_domain_models::types::PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(errors::ConnectorError::NotSupported {
            message: "Void".to_string(),
            connector: "Shift4",
        }
        .into())
    }
}

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

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

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

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

    fn 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 response: shift4::Shift4NonThreeDsResponse = res
            .response
            .parse_struct("Shift4NonThreeDsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Shift4 {
    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 build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        if req.request.amount_to_capture != req.request.payment_amount {
            Err(errors::ConnectorError::NotSupported {
                message: "Partial Capture".to_string(),
                connector: "Shift4",
            })?
        }
        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,
                )?)
                .build(),
        ))
    }

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

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

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

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

    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<Session, PaymentsSessionData, PaymentsResponseData> for Shift4 {
    //TODO: implement sessions flow
}

impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResponseData>
    for Shift4
{
    fn get_headers(
        &self,
        req: &PaymentsPreProcessingRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut headers = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                "application/x-www-form-urlencoded".to_string().into(),
            ),
            (
                ACCEPT.to_string(),
                self.common_get_content_type().to_string().into(),
            ),
        ];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        headers.append(&mut api_key);
        Ok(headers)
    }

    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!("{}3d-secure", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsPreProcessingRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount.ok_or_else(|| {
                errors::ConnectorError::MissingRequiredField {
                    field_name: "minor_amount",
                }
            })?,
            req.request
                .currency
                .ok_or_else(|| errors::ConnectorError::MissingRequiredField {
                    field_name: "currency",
                })?,
        )?;
        let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?;
        let connector_req = Shift4PaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::FormUrlEncoded(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: shift4::Shift4ThreeDsResponse = res
            .response
            .parse_struct("Shift4ThreeDsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .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 Shift4
{
    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!("{}charges", self.base_url(connectors)))
    }

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

    fn build_request(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsCompleteAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .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: shift4::Shift4NonThreeDsResponse = res
            .response
            .parse_struct("Shift4NonThreeDsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .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 Shift4 {
    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!("{}refunds", self.base_url(connectors),))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;
        let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?;
        let connector_req = Shift4RefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

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

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .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<RSync, RefundsData, RefundsResponseData> for Shift4 {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: shift4::RefundResponse =
            res.response
                .parse_struct("shift4 RefundResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .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 IncomingWebhook for Shift4 {
    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let details: shift4::Shift4WebhookObjectId = request
            .body
            .parse_struct("Shift4WebhookObjectId")
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;

        if shift4::is_transaction_event(&details.event_type) {
            Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id),
            ))
        } else if shift4::is_refund_event(&details.event_type) {
            Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                api_models::webhooks::RefundIdType::ConnectorRefundId(
                    details
                        .data
                        .refunds
                        .and_then(|refund| {
                            refund.first().map(|refund_object| refund_object.id.clone())
                        })
                        .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
                ),
            ))
        } else {
            Err(report!(errors::ConnectorError::WebhookReferenceIdNotFound))
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let details: shift4::Shift4WebhookObjectEventType = request
            .body
            .parse_struct("Shift4WebhookObjectEventType")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        Ok(IncomingWebhookEvent::from(details.event_type))
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let details: shift4::Shift4WebhookObjectResource = request
            .body
            .parse_struct("Shift4WebhookObjectResource")
            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
        // Ideally this should be a strict type that has type information
        // PII information is likely being logged here when this response will be logged
        Ok(Box::new(details.data))
    }
}

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

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

    let mut shift4_supported_payment_methods = SupportedPaymentMethods::new();

    shift4_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Eps,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    shift4_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Giropay,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    shift4_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Ideal,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

    shift4_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Sofort,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

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

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

    shift4_supported_payment_methods
});

static SHIFT4_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Shift4",
    description: "Shift4 Payments, Inc. is an American payment processing company based in Allentown, Pennsylvania. ",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static SHIFT4_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 2] =
    [enums::EventClass::Payments, enums::EventClass::Refunds];

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

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

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


// Function: get_merchant_details_as_secret
// File: crates/api_models/src/admin.rs
// Module: api_models

pub fn get_merchant_details_as_secret(
        &self,
    ) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError>


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

pub fn server(state: AppState) -> Scope


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

pub fn new() -> &'static Self


// Struct: BillingConnectorInvoiceSyncFlowRouterData
// File: crates/router/src/core/webhooks/recovery_incoming.rs
// Module: router
// Implementations: 1

pub struct BillingConnectorInvoiceSyncFlowRouterData


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

pub struct OpenIdConnectPrivateConfig


// Struct: ItaubankPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/itaubank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ItaubankPaymentsResponse


// File: crates/analytics/src/refunds/distribution/sessionized_distribution/refund_reason.rs
// Module: analytics

use api_models::analytics::{
    refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
    Granularity, RefundDistributionBody, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::{RefundDistribution, RefundDistributionRow};
use crate::{
    enums::AuthInfo,
    query::{
        Aggregate, GroupByClause, Order, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window,
    },
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(crate) struct RefundReason;

#[async_trait::async_trait]
impl<T> RefundDistribution<T> for RefundReason
where
    T: AnalyticsDataSource + super::RefundDistributionAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_distribution(
        &self,
        distribution: &RefundDistributionBody,
        dimensions: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: &Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundDistributionRow)>> {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::RefundSessionized);

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }

        query_builder
            .add_select_column(&distribution.distribution_for)
            .switch()?;

        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

        filters.set_filter_clause(&mut query_builder).switch()?;

        auth.set_filter_clause(&mut query_builder).switch()?;

        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }

        query_builder
            .add_group_by_clause(&distribution.distribution_for)
            .attach_printable("Error grouping by distribution_for")
            .switch()?;

        if let Some(granularity) = granularity.as_ref() {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        for dim in dimensions.iter() {
            query_builder.add_outer_select_column(dim).switch()?;
        }

        query_builder
            .add_outer_select_column(&distribution.distribution_for)
            .switch()?;
        query_builder.add_outer_select_column("count").switch()?;
        query_builder
            .add_outer_select_column("start_bucket")
            .switch()?;
        query_builder
            .add_outer_select_column("end_bucket")
            .switch()?;
        let sql_dimensions = query_builder.transform_to_sql_values(dimensions).switch()?;

        query_builder
            .add_outer_select_column(Window::Sum {
                field: "count",
                partition_by: Some(sql_dimensions),
                order_by: None,
                alias: Some("total"),
            })
            .switch()?;

        query_builder
            .add_top_n_clause(
                dimensions,
                distribution.distribution_cardinality.into(),
                "count",
                Order::Descending,
            )
            .switch()?;

        query_builder
            .execute_query::<RefundDistributionRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    RefundMetricsBucketIdentifier::new(
                        i.currency.as_ref().map(|i| i.0),
                        i.refund_status.as_ref().map(|i| i.0.to_string()),
                        i.connector.clone(),
                        i.refund_type.as_ref().map(|i| i.0.to_string()),
                        i.profile_id.clone(),
                        i.refund_reason.clone(),
                        i.refund_error_message.clone(),
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                Vec<(RefundMetricsBucketIdentifier, RefundDistributionRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


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

pub fn signout(
    state: SessionState,
    user_from_token: auth::UserIdFromAuth,
) -> UserResponse<()>


// File: crates/euclid/src/backend/vir_interpreter/types.rs
// Module: euclid
// Public functions: 2
// Public structs: 1

use rustc_hash::{FxHashMap, FxHashSet};

use crate::{
    backend::inputs::BackendInput,
    dssa,
    types::{self, EuclidKey, EuclidValue, MetadataValue, NumValueRefinement, StrValue},
};

#[derive(Debug, Clone, serde::Serialize, thiserror::Error)]
pub enum VirInterpreterError {
    #[error("Error when lowering the program: {0:?}")]
    LoweringError(dssa::types::AnalysisError),
}

pub struct Context {
    atomic_values: FxHashSet<EuclidValue>,
    numeric_values: FxHashMap<EuclidKey, EuclidValue>,
}

impl Context {
    pub fn check_presence(&self, value: &EuclidValue) -> bool {
        let key = value.get_key();

        match key.key_type() {
            types::DataType::MetadataValue => self.atomic_values.contains(value),
            types::DataType::StrValue => self.atomic_values.contains(value),
            types::DataType::EnumVariant => self.atomic_values.contains(value),
            types::DataType::Number => {
                let ctx_num_value = self
                    .numeric_values
                    .get(&key)
                    .and_then(|value| value.get_num_value());

                value.get_num_value().zip(ctx_num_value).is_some_and(
                    |(program_value, ctx_value)| {
                        let program_num = program_value.number;
                        let ctx_num = ctx_value.number;

                        match &program_value.refinement {
                            None => program_num == ctx_num,
                            Some(NumValueRefinement::NotEqual) => ctx_num != program_num,
                            Some(NumValueRefinement::GreaterThan) => ctx_num > program_num,
                            Some(NumValueRefinement::GreaterThanEqual) => ctx_num >= program_num,
                            Some(NumValueRefinement::LessThanEqual) => ctx_num <= program_num,
                            Some(NumValueRefinement::LessThan) => ctx_num < program_num,
                        }
                    },
                )
            }
        }
    }

    pub fn from_input(input: BackendInput) -> Self {
        let payment = input.payment;
        let payment_method = input.payment_method;
        let meta_data = input.metadata;
        let acquirer_data = input.acquirer_data;
        let customer_device_data = input.customer_device_data;
        let issuer_data = input.issuer_data;
        let payment_mandate = input.mandate;

        let mut enum_values: FxHashSet<EuclidValue> =
            FxHashSet::from_iter([EuclidValue::PaymentCurrency(payment.currency)]);

        if let Some(pm) = payment_method.payment_method {
            enum_values.insert(EuclidValue::PaymentMethod(pm));
        }

        if let Some(pmt) = payment_method.payment_method_type {
            enum_values.insert(EuclidValue::PaymentMethodType(pmt));
        }

        if let Some(met) = meta_data {
            for (key, value) in met.into_iter() {
                enum_values.insert(EuclidValue::Metadata(MetadataValue { key, value }));
            }
        }

        if let Some(card_network) = payment_method.card_network {
            enum_values.insert(EuclidValue::CardNetwork(card_network));
        }

        if let Some(at) = payment.authentication_type {
            enum_values.insert(EuclidValue::AuthenticationType(at));
        }

        if let Some(capture_method) = payment.capture_method {
            enum_values.insert(EuclidValue::CaptureMethod(capture_method));
        }

        if let Some(country) = payment.business_country {
            enum_values.insert(EuclidValue::BusinessCountry(country));
        }

        if let Some(country) = payment.billing_country {
            enum_values.insert(EuclidValue::BillingCountry(country));
        }
        if let Some(card_bin) = payment.card_bin {
            enum_values.insert(EuclidValue::CardBin(StrValue { value: card_bin }));
        }
        if let Some(business_label) = payment.business_label {
            enum_values.insert(EuclidValue::BusinessLabel(StrValue {
                value: business_label,
            }));
        }
        if let Some(setup_future_usage) = payment.setup_future_usage {
            enum_values.insert(EuclidValue::SetupFutureUsage(setup_future_usage));
        }
        if let Some(payment_type) = payment_mandate.payment_type {
            enum_values.insert(EuclidValue::PaymentType(payment_type));
        }
        if let Some(mandate_type) = payment_mandate.mandate_type {
            enum_values.insert(EuclidValue::MandateType(mandate_type));
        }
        if let Some(mandate_acceptance_type) = payment_mandate.mandate_acceptance_type {
            enum_values.insert(EuclidValue::MandateAcceptanceType(mandate_acceptance_type));
        }

        if let Some(acquirer_country) = acquirer_data.clone().and_then(|data| data.country) {
            enum_values.insert(EuclidValue::AcquirerCountry(acquirer_country));
        }

        // Handle customer device data
        if let Some(device_data) = customer_device_data {
            if let Some(platform) = device_data.platform {
                enum_values.insert(EuclidValue::CustomerDevicePlatform(platform));
            }
            if let Some(device_type) = device_data.device_type {
                enum_values.insert(EuclidValue::CustomerDeviceType(device_type));
            }
            if let Some(display_size) = device_data.display_size {
                enum_values.insert(EuclidValue::CustomerDeviceDisplaySize(display_size));
            }
        }

        // Handle issuer data
        if let Some(issuer) = issuer_data {
            if let Some(name) = issuer.name {
                enum_values.insert(EuclidValue::IssuerName(StrValue { value: name }));
            }
            if let Some(country) = issuer.country {
                enum_values.insert(EuclidValue::IssuerCountry(country));
            }
        }

        let numeric_values: FxHashMap<EuclidKey, EuclidValue> = FxHashMap::from_iter([(
            EuclidKey::PaymentAmount,
            EuclidValue::PaymentAmount(types::NumValue {
                number: payment.amount,
                refinement: None,
            }),
        )]);

        Self {
            atomic_values: enum_values,
            numeric_values,
        }
    }
}


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

impl common_utils::events::ApiEventMetric for for ClientSecretCreateRequest


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

pub struct PaysafeApplePayPaymentMethod