) -> CustomResult<String, errors::ApiErrorResponse> {
    let (tera, mut context) = build_payment_link_template(payment_link_data)
        .attach_printable("Failed to build payment link's HTML template")?;
    let payment_link_initiator =
        include_str!("../core/payment_link/payment_link_initiate/payment_link_initiator.js")
            .to_string();
    context.insert("payment_link_initiator", &payment_link_initiator);

    tera.render("payment_link", &context)
        .map_err(|tera_error: TeraError| {
            crate::logger::warn!("{tera_error}");
            report!(errors::ApiErrorResponse::InternalServerError)
        })
        .attach_printable("Error while rendering open payment link's HTML template")
}

pub fn build_secure_payment_link_html(
    payment_link_data: PaymentLinkFormData,
) -> CustomResult<String, errors::ApiErrorResponse> {
    let (tera, mut context) = build_payment_link_template(payment_link_data)
        .attach_printable("Failed to build payment link's HTML template")?;
    let payment_link_initiator =
        include_str!("../core/payment_link/payment_link_initiate/secure_payment_link_initiator.js")
            .to_string();
    context.insert("payment_link_initiator", &payment_link_initiator);

    tera.render("payment_link", &context)
        .map_err(|tera_error: TeraError| {
            crate::logger::warn!("{tera_error}");
            report!(errors::ApiErrorResponse::InternalServerError)
        })
        .attach_printable("Error while rendering secure payment link's HTML template")
}

fn get_hyper_loader_sdk(sdk_url: &url::Url) -> String {
    format!("<script src=\"{sdk_url}\" onload=\"initializeSDK()\"></script>")
}

fn get_preload_link_html_template(sdk_url: &url::Url) -> String {
    format!(
        r#"<link rel="preload" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800" as="style">
            <link rel="preload" href="{sdk_url}" as="script">"#,
    )
}

pub fn get_payment_link_status(
    payment_link_data: PaymentLinkStatusData,
) -> CustomResult<String, errors::ApiErrorResponse> {
    let mut tera = Tera::default();

    // Add modification to css template with dynamic data
    let css_template =
        include_str!("../core/payment_link/payment_link_status/status.css").to_string();
    let _ = tera.add_raw_template("payment_link_css", &css_template);
    let mut context = Context::new();
    context.insert("css_color_scheme", &payment_link_data.css_script);

    let rendered_css = match tera.render("payment_link_css", &context) {
        Ok(rendered_css) => rendered_css,
        Err(tera_error) => {
            crate::logger::warn!("{tera_error}");
            Err(errors::ApiErrorResponse::InternalServerError)?
        }
    };

    //Locale template
    let locale_template = include_str!("../core/payment_link/locale.js");

    // Logging template
    let logging_template =
        include_str!("redirection/assets/redirect_error_logs_push.js").to_string();

    // Add modification to js template with dynamic data
    let js_template =
        include_str!("../core/payment_link/payment_link_status/status.js").to_string();
    let _ = tera.add_raw_template("payment_link_js", &js_template);
    context.insert("payment_details_js_script", &payment_link_data.js_script);

    let rendered_js = match tera.render("payment_link_js", &context) {
        Ok(rendered_js) => rendered_js,
        Err(tera_error) => {
            crate::logger::warn!("{tera_error}");
            Err(errors::ApiErrorResponse::InternalServerError)?
        }
    };

    // Modify Html template with rendered js and rendered css files
    let html_template =
        include_str!("../core/payment_link/payment_link_status/status.html").to_string();
    let _ = tera.add_raw_template("payment_link_status", &html_template);

    context.insert("rendered_css", &rendered_css);
    context.insert("locale_template", &locale_template);

    context.insert("rendered_js", &rendered_js);
    context.insert("logging_template", &logging_template);

    match tera.render("payment_link_status", &context) {
        Ok(rendered_html) => Ok(rendered_html),
        Err(tera_error) => {
            crate::logger::warn!("{tera_error}");
            Err(errors::ApiErrorResponse::InternalServerError)?
        }
    }
}

pub fn extract_mapped_fields(
    value: &serde_json::Value,
    mapping: Option<&HashMap<String, String>>,
    existing_enhancement: Option<&serde_json::Value>,
) -> Option<serde_json::Value> {
    let mapping = mapping?;

    if mapping.is_empty() {
        return existing_enhancement.cloned();
    }

    let mut enhancement = match existing_enhancement {
        Some(existing) if existing.is_object() => existing.clone(),
        _ => serde_json::json!({}),
    };

    for (dot_path, output_key) in mapping {
        if let Some(extracted_value) = extract_field_by_dot_path(value, dot_path) {
            if let Some(obj) = enhancement.as_object_mut() {
                obj.insert(output_key.clone(), extracted_value);
            }
        }
    }

    if enhancement.as_object().is_some_and(|obj| !obj.is_empty()) {
        Some(enhancement)
    } else {
        None
    }
}

pub fn extract_field_by_dot_path(
    value: &serde_json::Value,
    path: &str,
) -> Option<serde_json::Value> {
    let parts: Vec<&str> = path.split('.').collect();
    let mut current = value;

    for part in parts {
        match current {
            serde_json::Value::Object(obj) => {
                current = obj.get(part)?;
            }
            serde_json::Value::Array(arr) => {
                // Try to parse part as array index
                if let Ok(index) = part.parse::<usize>() {
                    current = arr.get(index)?;
                } else {
                    return None;
                }
            }
            _ => return None,
        }
    }

    Some(current.clone())
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_mime_essence() {
        assert_eq!(mime::APPLICATION_JSON.essence_str(), "application/json");
    }
}


// Function: get_decrypted_apple_pay_payment_data_optional
// File: crates/common_types/src/payments.rs
// Module: common_types

// Documentation: Get the decrypted Apple Pay payment data if it exists

pub fn get_decrypted_apple_pay_payment_data_optional(&self) -> Option<&ApplePayPredecryptData>


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

impl Bambora


// Implementation: impl AccountsStorageInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 0 total (0 public)

impl AccountsStorageInterface for for KafkaStore


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

pub fn check_merchant_account_kv_status(
    state: SessionState,
    merchant_id: id_type::MerchantId,
) -> RouterResponse<api_models::admin::ToggleKVResponse>


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

impl PaymentCapture for for Netcetera


// Implementation: impl MandateNew
// File: crates/diesel_models/src/mandate.rs
// Module: diesel_models
// Methods: 2 total (2 public)

impl MandateNew


// Trait: DecryptedDataConversion
// File: crates/common_utils/src/types/keymanager.rs
// Module: common_utils

pub trait DecryptedDataConversion<T: Clone, S: Strategy<T>


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

pub mod transformers;

use std::sync::LazyLock;

use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
use base64::Engine;
use common_enums::enums;
use common_utils::{
    consts::BASE64_ENGINE,
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, TokenizationRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::{Mask, PeekInterface};
use transformers::{
    self as billwerk, BillwerkAuthType, BillwerkCaptureRequest, BillwerkErrorResponse,
    BillwerkPaymentsRequest, BillwerkPaymentsResponse, BillwerkRefundRequest, BillwerkRouterData,
    BillwerkTokenRequest, BillwerkTokenResponse,
};

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

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

impl Billwerk {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &MinorUnitForConnector,
        }
    }
}
impl api::Payment for Billwerk {}
impl api::PaymentSession for Billwerk {}
impl api::ConnectorAccessToken for Billwerk {}
impl api::MandateSetup for Billwerk {}
impl api::PaymentAuthorize for Billwerk {}
impl api::PaymentSync for Billwerk {}
impl api::PaymentCapture for Billwerk {}
impl api::PaymentVoid for Billwerk {}
impl api::Refund for Billwerk {}
impl api::RefundExecute for Billwerk {}
impl api::RefundSync for Billwerk {}
impl api::PaymentToken for Billwerk {}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Billwerk
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 header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

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

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

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

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

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

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .code
                .map_or(NO_ERROR_CODE.to_string(), |code| code.to_string()),
            message: response.message.unwrap_or(NO_ERROR_MESSAGE.to_string()),
            reason: Some(response.error),
            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 Billwerk {}

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

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

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

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Billwerk
{
    fn get_headers(
        &self,
        req: &TokenizationRouterData,
        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: &TokenizationRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let base_url = connectors
            .billwerk
            .secondary_base_url
            .as_ref()
            .ok_or(errors::ConnectorError::FailedToObtainIntegrationUrl)?;
        Ok(format!("{base_url}v1/token"))
    }

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

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

    fn handle_response(
        &self,
        data: &TokenizationRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<TokenizationRouterData, errors::ConnectorError>
    where
        PaymentsResponseData: Clone,
    {
        let response: BillwerkTokenResponse = res
            .response
            .parse_struct("BillwerkTokenResponse")
            .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)
    }

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

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Billwerk {
    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!("{}v1/charge", 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 = BillwerkRouterData::try_from((amount, req))?;
        let connector_req = BillwerkPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

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

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

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

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Billwerk {
    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!(
            "{}v1/charge/{}",
            self.base_url(connectors),
            req.connector_request_reference_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 handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: BillwerkPaymentsResponse = res
            .response
            .parse_struct("billwerk BillwerkPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

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

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

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

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

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

        let connector_router_data = BillwerkRouterData::try_from((amount, req))?;
        let connector_req = BillwerkCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

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

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

    fn get_5xx_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 Billwerk {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

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

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

    fn get_5xx_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 Billwerk {
    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!("{}v1/refund", 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 = BillwerkRouterData::try_from((amount, req))?;
        let connector_req = BillwerkRefundRequest::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: billwerk::RefundResponse = res
            .response
            .parse_struct("billwerk 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,
        })
    }

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

    fn get_5xx_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 Billwerk {
    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!(
            "{}v1/refund/{refund_id}",
            self.base_url(connectors)
        ))
    }

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

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

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

    fn get_5xx_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 Billwerk {
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

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

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

static BILLWERK_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::Mastercard,
            common_enums::CardNetwork::Visa,
            common_enums::CardNetwork::AmericanExpress,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::UnionPay,
            common_enums::CardNetwork::DinersClub,
            common_enums::CardNetwork::Interac,
            common_enums::CardNetwork::CartesBancaires,
        ];

        let mut billwerk_supported_payment_methods = SupportedPaymentMethods::new();

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

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

        billwerk_supported_payment_methods
    });

static BILLWERK_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Billwerk",
    description: "Billwerk+ Pay is an acquirer independent payment gateway that's easy to setup with more than 50 recurring and non-recurring payment methods.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
};

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

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

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

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


// File: crates/router/src/db/role.rs
// Module: router

use common_utils::id_type;
use diesel_models::{
    enums::{EntityType, RoleScope},
    role as storage,
};
use error_stack::report;
use router_env::{instrument, tracing};

use super::MockDb;
use crate::{
    connection,
    core::errors::{self, CustomResult},
    services::Store,
};

#[async_trait::async_trait]
pub trait RoleInterface {
    async fn insert_role(
        &self,
        role: storage::RoleNew,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    async fn find_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    async fn find_role_by_role_id_in_lineage(
        &self,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    async fn find_by_role_id_org_id_tenant_id(
        &self,
        role_id: &str,
        org_id: &id_type::OrganizationId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    async fn update_role_by_role_id(
        &self,
        role_id: &str,
        role_update: storage::RoleUpdate,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    async fn delete_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError>;

    //TODO: Remove once generic_list_roles_by_entity_type is stable
    async fn list_roles_for_org_by_parameters(
        &self,
        tenant_id: &id_type::TenantId,
        org_id: &id_type::OrganizationId,
        merchant_id: Option<&id_type::MerchantId>,
        entity_type: Option<EntityType>,
        limit: Option<u32>,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError>;

    async fn generic_list_roles_by_entity_type(
        &self,
        payload: storage::ListRolesByEntityPayload,
        is_lineage_data_required: bool,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError>;
}

#[async_trait::async_trait]
impl RoleInterface for Store {
    #[instrument(skip_all)]
    async fn insert_role(
        &self,
        role: storage::RoleNew,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        role.insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::Role::find_by_role_id(&conn, role_id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_role_by_role_id_in_lineage(
        &self,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::Role::find_by_role_id_in_lineage(
            &conn,
            role_id,
            merchant_id,
            org_id,
            profile_id,
            tenant_id,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_by_role_id_org_id_tenant_id(
        &self,
        role_id: &str,
        org_id: &id_type::OrganizationId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::Role::find_by_role_id_org_id_tenant_id(&conn, role_id, org_id, tenant_id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn update_role_by_role_id(
        &self,
        role_id: &str,
        role_update: storage::RoleUpdate,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        storage::Role::update_by_role_id(&conn, role_id, role_update)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn delete_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        storage::Role::delete_by_role_id(&conn, role_id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    //TODO: Remove once generic_list_roles_by_entity_type is stable
    #[instrument(skip_all)]
    async fn list_roles_for_org_by_parameters(
        &self,
        tenant_id: &id_type::TenantId,
        org_id: &id_type::OrganizationId,
        merchant_id: Option<&id_type::MerchantId>,
        entity_type: Option<EntityType>,
        limit: Option<u32>,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::Role::generic_roles_list_for_org(
            &conn,
            tenant_id.to_owned(),
            org_id.to_owned(),
            merchant_id.cloned(),
            entity_type,
            limit,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn generic_list_roles_by_entity_type(
        &self,
        payload: storage::ListRolesByEntityPayload,
        is_lineage_data_required: bool,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::Role::generic_list_roles_by_entity_type(
            &conn,
            payload,
            is_lineage_data_required,
            tenant_id,
            org_id,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }
}

#[async_trait::async_trait]
impl RoleInterface for MockDb {
    async fn insert_role(
        &self,
        role: storage::RoleNew,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let mut roles = self.roles.lock().await;
        if roles
            .iter()
            .any(|role_inner| role_inner.role_id == role.role_id)
        {
            Err(errors::StorageError::DuplicateValue {
                entity: "role_id",
                key: None,
            })?
        }
        let role = storage::Role {
            role_name: role.role_name,
            role_id: role.role_id,
            merchant_id: role.merchant_id,
            org_id: role.org_id,
            groups: role.groups,
            scope: role.scope,
            entity_type: role.entity_type,
            created_by: role.created_by,
            created_at: role.created_at,
            last_modified_at: role.last_modified_at,
            last_modified_by: role.last_modified_by,
            profile_id: role.profile_id,
            tenant_id: role.tenant_id,
        };
        roles.push(role.clone());
        Ok(role)
    }

    async fn find_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let roles = self.roles.lock().await;
        roles
            .iter()
            .find(|role| role.role_id == role_id)
            .cloned()
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "No role available role_id  = {role_id}"
                ))
                .into(),
            )
    }

    async fn find_role_by_role_id_in_lineage(
        &self,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let roles = self.roles.lock().await;
        roles
            .iter()
            .find(|role| {
                role.role_id == role_id
                    && (role.tenant_id == *tenant_id)
                    && role.org_id == *org_id
                    && ((role.scope == RoleScope::Organization)
                        || (role
                            .merchant_id
                            .as_ref()
                            .is_some_and(|merchant_id_from_role| {
                                merchant_id_from_role == merchant_id
                                    && role.scope == RoleScope::Merchant
                            }))
                        || (role
                            .profile_id
                            .as_ref()
                            .is_some_and(|profile_id_from_role| {
                                profile_id_from_role == profile_id
                                    && role.scope == RoleScope::Profile
                            })))
            })
            .cloned()
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "No role available in merchant scope for role_id = {role_id}, \
                    merchant_id = {merchant_id:?} and org_id = {org_id:?}"
                ))
                .into(),
            )
    }

    async fn find_by_role_id_org_id_tenant_id(
        &self,
        role_id: &str,
        org_id: &id_type::OrganizationId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let roles = self.roles.lock().await;
        roles
            .iter()
            .find(|role| {
                role.role_id == role_id && role.org_id == *org_id && role.tenant_id == *tenant_id
            })
            .cloned()
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "No role available in org scope for role_id = {role_id} and org_id = {org_id:?}"
                ))
                .into(),
            )
    }

    async fn update_role_by_role_id(
        &self,
        role_id: &str,
        role_update: storage::RoleUpdate,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let mut roles = self.roles.lock().await;
        roles
            .iter_mut()
            .find(|role| role.role_id == role_id)
            .map(|role| {
                *role = match role_update {
                    storage::RoleUpdate::UpdateDetails {
                        groups,
                        role_name,
                        last_modified_at,
                        last_modified_by,
                    } => storage::Role {
                        groups: groups.unwrap_or(role.groups.to_owned()),
                        role_name: role_name.unwrap_or(role.role_name.to_owned()),
                        last_modified_by,
                        last_modified_at,
                        ..role.to_owned()
                    },
                };
                role.to_owned()
            })
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "No role available for role_id = {role_id}"
                ))
                .into(),
            )
    }

    async fn delete_role_by_role_id(
        &self,
        role_id: &str,
    ) -> CustomResult<storage::Role, errors::StorageError> {
        let mut roles = self.roles.lock().await;
        let role_index = roles
            .iter()
            .position(|role| role.role_id == role_id)
            .ok_or(errors::StorageError::ValueNotFound(format!(
                "No role available for role_id = {role_id}"
            )))?;

        Ok(roles.remove(role_index))
    }

    //TODO: Remove once generic_list_roles_by_entity_type is stable
    #[instrument(skip_all)]
    async fn list_roles_for_org_by_parameters(
        &self,
        tenant_id: &id_type::TenantId,
        org_id: &id_type::OrganizationId,
        merchant_id: Option<&id_type::MerchantId>,
        entity_type: Option<EntityType>,
        limit: Option<u32>,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError> {
        let roles = self.roles.lock().await;
        let limit_usize = limit.unwrap_or(u32::MAX).try_into().unwrap_or(usize::MAX);
        let roles_list: Vec<_> = roles
            .iter()
            .filter(|role| {
                let matches_merchant = merchant_id
                    .zip(role.merchant_id.as_ref())
                    .map(|(merchant_id, role_merchant_id)| merchant_id == role_merchant_id)
                    .unwrap_or(true);

                matches_merchant
                    && role.org_id == *org_id
                    && role.tenant_id == *tenant_id
                    && Some(role.entity_type) == entity_type
            })
            .take(limit_usize)
            .cloned()
            .collect();

        Ok(roles_list)
    }

    #[instrument(skip_all)]
    async fn generic_list_roles_by_entity_type(
        &self,
        payload: storage::ListRolesByEntityPayload,
        is_lineage_data_required: bool,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
    ) -> CustomResult<Vec<storage::Role>, errors::StorageError> {
        let roles = self.roles.lock().await;
        let roles_list: Vec<_> = roles
            .iter()
            .filter(|role| match &payload {
                storage::ListRolesByEntityPayload::Organization => {
                    let entity_in_vec = if is_lineage_data_required {
                        vec![
                            EntityType::Organization,
                            EntityType::Merchant,
                            EntityType::Profile,
                        ]
                    } else {
                        vec![EntityType::Organization]
                    };

                    role.tenant_id == tenant_id
                        && role.org_id == org_id
                        && entity_in_vec.contains(&role.entity_type)
                }
                storage::ListRolesByEntityPayload::Merchant(merchant_id) => {
                    let entity_in_vec = if is_lineage_data_required {
                        vec![EntityType::Merchant, EntityType::Profile]
                    } else {
                        vec![EntityType::Merchant]
                    };

                    let matches_merchant = role
                        .merchant_id
                        .as_ref()
                        .is_some_and(|merchant_id_from_role| merchant_id_from_role == merchant_id);

                    role.tenant_id == tenant_id
                        && role.org_id == org_id
                        && (role.scope == RoleScope::Organization || matches_merchant)
                        && entity_in_vec.contains(&role.entity_type)
                }
                storage::ListRolesByEntityPayload::Profile(merchant_id, profile_id) => {
                    let entity_in_vec = [EntityType::Profile];

                    let matches_merchant =
                        role.merchant_id
                            .as_ref()
                            .is_some_and(|merchant_id_from_role| {
                                merchant_id_from_role == merchant_id
                                    && role.scope == RoleScope::Merchant
                            });

                    let matches_profile =
                        role.profile_id
                            .as_ref()
                            .is_some_and(|profile_id_from_role| {
                                profile_id_from_role == profile_id
                                    && role.scope == RoleScope::Profile
                            });

                    role.tenant_id == tenant_id
                        && role.org_id == org_id
                        && (role.scope == RoleScope::Organization
                            || matches_merchant
                            || matches_profile)
                        && entity_in_vec.contains(&role.entity_type)
                }
            })
            .cloned()
            .collect();

        Ok(roles_list)
    }
}


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

pub fn new() -> &'static Self


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

pub fn add_card_to_hs_locker(
    state: &routes::SessionState,
    payload: &payment_methods::StoreLockerReq,
    customer_id: &id_type::CustomerId,
    locker_choice: api_enums::LockerChoice,
) -> errors::CustomResult<payment_methods::StoreCardRespPayload, errors::VaultError>


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

pub struct PaymePaySaleResponse


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

pub struct AuthenticationInfo


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

pub struct AuthenticationErrorInformation


// Function: calculate_signature
// File: crates/hyperswitch_connectors/src/connectors/zsl/transformers.rs
// Module: hyperswitch_connectors

pub fn calculate_signature(
    enctype: EncodingType,
    signature_data: ZslSignatureType,
) -> Result<Secret<String>, error_stack::Report<errors::ConnectorError>>


// File: crates/smithy-core/src/generator.rs
// Module: smithy-core
// Public functions: 3
// Public structs: 1

// crates/smithy-core/generator.rs

use std::{collections::HashMap, fs, path::Path};

use crate::types::{self as types, SmithyModel};

/// Generator for creating Smithy IDL files from models
pub struct SmithyGenerator {
    models: Vec<SmithyModel>,
}

impl SmithyGenerator {
    pub fn new() -> Self {
        Self { models: Vec::new() }
    }

    pub fn add_model(&mut self, model: SmithyModel) {
        self.models.push(model);
    }

    pub fn generate_idl(&self, output_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
        fs::create_dir_all(output_dir)?;

        let mut namespace_models: HashMap<String, Vec<&SmithyModel>> = HashMap::new();
        let mut shape_to_namespace: HashMap<String, String> = HashMap::new();

        // First, build a map of all shape names to their namespaces
        for model in &self.models {
            for shape_name in model.shapes.keys() {
                shape_to_namespace.insert(shape_name.clone(), model.namespace.clone());
            }
        }

        // Group models by namespace for file generation
        for model in &self.models {
            namespace_models
                .entry(model.namespace.clone())
                .or_default()
                .push(model);
        }

        for (namespace, models) in namespace_models {
            let filename = format!("{}.smithy", namespace.replace('.', "_"));
            let filepath = output_dir.join(filename);

            let mut content = String::new();
            content.push_str("$version: \"2\"\n\n");
            content.push_str(&format!("namespace {}\n\n", namespace));

            // Collect all unique shape definitions for the current namespace
            let mut shapes_in_namespace = HashMap::new();
            for model in models {
                for (shape_name, shape) in &model.shapes {
                    shapes_in_namespace.insert(shape_name.clone(), shape.clone());
                }
            }

            // Generate definitions for each shape in the namespace
            for (shape_name, shape) in &shapes_in_namespace {
                content.push_str(&self.generate_shape_definition(
                    shape_name,
                    shape,
                    &namespace,
                    &shape_to_namespace,
                ));
                content.push_str("\n\n");
            }

            fs::write(filepath, content)?;
        }

        Ok(())
    }

    fn generate_shape_definition(
        &self,
        name: &str,
        shape: &types::SmithyShape,
        current_namespace: &str,
        shape_to_namespace: &HashMap<String, String>,
    ) -> String {
        let resolve_target =
            |target: &str| self.resolve_type(target, current_namespace, shape_to_namespace);

        match shape {
            types::SmithyShape::Structure {
                members,
                documentation,
                traits,
            } => {
                let mut def = String::new();

                if let Some(doc) = documentation {
                    def.push_str(&format!("/// {}\n", doc));
                }

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("structure {} {{\n", name));

                for (member_name, member) in members {
                    if let Some(doc) = &member.documentation {
                        def.push_str(&format!("    /// {}\n", doc));
                    }

                    for smithy_trait in &member.traits {
                        def.push_str(&format!("    @{}\n", self.trait_to_string(smithy_trait)));
                    }

                    let resolved_target = resolve_target(&member.target);
                    def.push_str(&format!("    {}: {}\n", member_name, resolved_target));
                }

                def.push('}');
                def
            }
            types::SmithyShape::Union {
                members,
                documentation,
                traits,
            } => {
                let mut def = String::new();

                if let Some(doc) = documentation {
                    def.push_str(&format!("/// {}\n", doc));
                }

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("union {} {{\n", name));

                for (member_name, member) in members {
                    if let Some(doc) = &member.documentation {
                        def.push_str(&format!("    /// {}\n", doc));
                    }

                    for smithy_trait in &member.traits {
                        def.push_str(&format!("    @{}\n", self.trait_to_string(smithy_trait)));
                    }

                    let resolved_target = resolve_target(&member.target);
                    def.push_str(&format!("    {}: {}\n", member_name, resolved_target));
                }

                def.push('}');
                def
            }
            types::SmithyShape::Enum {
                values,
                documentation,
                traits,
            } => {
                let mut def = String::new();

                if let Some(doc) = documentation {
                    def.push_str(&format!("/// {}\n", doc));
                }

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("enum {} {{\n", name));

                for (value_name, enum_value) in values {
                    if let Some(doc) = &enum_value.documentation {
                        def.push_str(&format!("    /// {}\n", doc));
                    }
                    def.push_str(&format!("    {}\n", value_name));
                }

                def.push('}');
                def
            }
            types::SmithyShape::String { traits } => {
                let mut def = String::new();

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("string {}", name));
                def
            }
            types::SmithyShape::Integer { traits } => {
                let mut def = String::new();

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("integer {}", name));
                def
            }
            types::SmithyShape::Long { traits } => {
                let mut def = String::new();

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("long {}", name));
                def
            }
            types::SmithyShape::Boolean { traits } => {
                let mut def = String::new();

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("boolean {}", name));
                def
            }
            types::SmithyShape::List { member, traits } => {
                let mut def = String::new();

                for smithy_trait in traits {
                    def.push_str(&format!("@{}\n", self.trait_to_string(smithy_trait)));
                }

                def.push_str(&format!("list {} {{\n", name));
                let resolved_target = resolve_target(&member.target);
                def.push_str(&format!("    member: {}\n", resolved_target));
                def.push('}');
                def
            }
        }
    }

    fn resolve_type(
        &self,
        target: &str,
        current_namespace: &str,
        shape_to_namespace: &HashMap<String, String>,
    ) -> String {
        // If the target is a primitive or a fully qualified Smithy type, return it as is
        if target.starts_with("smithy.api#") {
            return target.to_string();
        }

        // If the target is a custom type, resolve its namespace
        if let Some(target_namespace) = shape_to_namespace.get(target) {
            if target_namespace == current_namespace {
                // The type is in the same namespace, so no qualification is needed
                target.to_string()
            } else {
                // The type is in a different namespace, so it needs to be fully qualified
                format!("{}#{}", target_namespace, target)
            }
        } else {
            // If the type is not found in the shape map, it might be a primitive
            // or an unresolved type. For now, return it as is.
            target.to_string()
        }
    }

    fn trait_to_string(&self, smithy_trait: &types::SmithyTrait) -> String {
        match smithy_trait {
            types::SmithyTrait::Pattern { pattern } => {
                format!("pattern(\"{}\")", pattern)
            }
            types::SmithyTrait::Range { min, max } => match (min, max) {
                (Some(min), Some(max)) => format!("range(min: {}, max: {})", min, max),
                (Some(min), None) => format!("range(min: {})", min),
                (None, Some(max)) => format!("range(max: {})", max),
                (None, None) => "range".to_string(),
            },
            types::SmithyTrait::Required => "required".to_string(),
            types::SmithyTrait::Documentation { documentation } => {
                format!("documentation(\"{}\")", documentation)
            }
            types::SmithyTrait::Length { min, max } => match (min, max) {
                (Some(min), Some(max)) => format!("length(min: {}, max: {})", min, max),
                (Some(min), None) => format!("length(min: {})", min),
                (None, Some(max)) => format!("length(max: {})", max),
                (None, None) => "length".to_string(),
            },
            types::SmithyTrait::HttpLabel => "httpLabel".to_string(),
            types::SmithyTrait::HttpQuery { name } => {
                format!("httpQuery(\"{}\")", name)
            }
            types::SmithyTrait::Mixin => "mixin".to_string(),
        }
    }
}

impl Default for SmithyGenerator {
    fn default() -> Self {
        Self::new()
    }
}


// Struct: TokenData
// File: crates/injector/src/types.rs
// Module: injector
// Implementations: 0

pub struct TokenData