// File: crates/api_models/src/analytics/frm.rs
// Module: api_models
// Public functions: 1
// Public structs: 6

use std::{
    collections::hash_map::DefaultHasher,
    hash::{Hash, Hasher},
};

use common_enums::enums::FraudCheckStatus;

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

use super::{NameDescription, TimeRange};
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct FrmFilters {
    #[serde(default)]
    pub frm_status: Vec<FraudCheckStatus>,
    #[serde(default)]
    pub frm_name: Vec<String>,
    #[serde(default)]
    pub frm_transaction_type: Vec<FrmTransactionType>,
}

#[derive(
    Debug,
    serde::Serialize,
    serde::Deserialize,
    strum::AsRefStr,
    PartialEq,
    PartialOrd,
    Eq,
    Ord,
    strum::Display,
    strum::EnumIter,
    Clone,
    Copy,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum FrmDimensions {
    FrmStatus,
    FrmName,
    FrmTransactionType,
}

#[derive(
    Clone,
    Debug,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumIter,
    strum::AsRefStr,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum FrmMetrics {
    FrmTriggeredAttempts,
    FrmBlockedRate,
}

pub mod metric_behaviour {
    pub struct FrmTriggeredAttempts;
    pub struct FrmBlockRate;
}

impl From<FrmMetrics> for NameDescription {
    fn from(value: FrmMetrics) -> Self {
        Self {
            name: value.to_string(),
            desc: String::new(),
        }
    }
}

impl From<FrmDimensions> for NameDescription {
    fn from(value: FrmDimensions) -> Self {
        Self {
            name: value.to_string(),
            desc: String::new(),
        }
    }
}

#[derive(Debug, serde::Serialize, Eq)]
pub struct FrmMetricsBucketIdentifier {
    pub frm_status: Option<String>,
    pub frm_name: Option<String>,
    pub frm_transaction_type: Option<String>,
    #[serde(rename = "time_range")]
    pub time_bucket: TimeRange,
    #[serde(rename = "time_bucket")]
    #[serde(with = "common_utils::custom_serde::iso8601custom")]
    pub start_time: time::PrimitiveDateTime,
}

impl Hash for FrmMetricsBucketIdentifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.frm_status.hash(state);
        self.frm_name.hash(state);
        self.frm_transaction_type.hash(state);
        self.time_bucket.hash(state);
    }
}

impl PartialEq for FrmMetricsBucketIdentifier {
    fn eq(&self, other: &Self) -> bool {
        let mut left = DefaultHasher::new();
        self.hash(&mut left);
        let mut right = DefaultHasher::new();
        other.hash(&mut right);
        left.finish() == right.finish()
    }
}

impl FrmMetricsBucketIdentifier {
    pub fn new(
        frm_status: Option<String>,
        frm_name: Option<String>,
        frm_transaction_type: Option<String>,
        normalized_time_range: TimeRange,
    ) -> Self {
        Self {
            frm_status,
            frm_name,
            frm_transaction_type,
            time_bucket: normalized_time_range,
            start_time: normalized_time_range.start_time,
        }
    }
}

#[derive(Debug, serde::Serialize)]
pub struct FrmMetricsBucketValue {
    pub frm_triggered_attempts: Option<u64>,
    pub frm_blocked_rate: Option<f64>,
}

#[derive(Debug, serde::Serialize)]
pub struct FrmMetricsBucketResponse {
    #[serde(flatten)]
    pub values: FrmMetricsBucketValue,
    #[serde(flatten)]
    pub dimensions: FrmMetricsBucketIdentifier,
}


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

impl api::PaymentSession for for Fiservemea


// Struct: KafkaSettings
// File: crates/router/src/services/kafka.rs
// Module: router
// Implementations: 1

pub struct KafkaSettings


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

// Public submodules:
pub mod transformers;


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

pub struct AuthorizedotnetSyncResponse


// Implementation: impl MerchantContext
// File: crates/hyperswitch_domain_models/src/merchant_context.rs
// Module: hyperswitch_domain_models
// Methods: 2 total (2 public)

impl MerchantContext


// Struct: DisputeListPTData
// File: crates/router/src/types/api/disputes.rs
// Module: router
// Implementations: 0

pub struct DisputeListPTData


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

pub struct BarclaycardRouterData<T>


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

impl ConnectorSpecifications for for Taxjar


// Function: customers_update
// File: crates/router/src/routes/customers.rs
// Module: router

pub fn customers_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::CustomerId>,
    json_payload: web::Json<customers::CustomerUpdateRequest>,
) -> HttpResponse


// Struct: DeutschebankRouterData
// File: crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DeutschebankRouterData<T>


// Function: event_serialize
// File: crates/router_env/src/logger/formatter.rs
// Module: router_env

// Documentation: Serialize event into a buffer of bytes using parent span.

pub fn event_serialize<S>(
        &self,
        span: Option<&SpanRef<'_, S>>,
        event: &Event<'_>,
    ) -> std::io::Result<Vec<u8>>
    where
        S: Subscriber + for<'a> LookupSpan<'a>,


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

pub struct TokenizedWalletValue1


// Struct: BlackhawknetworkPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/blackhawknetwork/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BlackhawknetworkPaymentsResponse


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

pub struct VerifyRecoveryCodeRequest


// Implementation: impl ApiEventMetric for for DisputeId
// File: crates/router/src/events/api_logs.rs
// Module: router
// Methods: 1 total (0 public)

impl ApiEventMetric for for DisputeId


// File: crates/analytics/src/auth_events/sankey.rs
// Module: analytics
// Public functions: 1
// Public structs: 1

use common_enums::AuthenticationStatus;
use common_utils::{
    errors::ParsingError,
    types::{authentication::AuthInfo, TimeRange},
};
use error_stack::ResultExt;
use router_env::logger;

use crate::{
    clickhouse::ClickhouseClient,
    query::{Aggregate, QueryBuilder, QueryFilter},
    types::{AnalyticsCollection, MetricsError, MetricsResult},
};

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct SankeyRow {
    pub count: i64,
    pub authentication_status: Option<AuthenticationStatus>,
    pub exemption_requested: Option<bool>,
    pub exemption_accepted: Option<bool>,
}

impl TryInto<SankeyRow> for serde_json::Value {
    type Error = error_stack::Report<ParsingError>;

    fn try_into(self) -> Result<SankeyRow, Self::Error> {
        logger::debug!("Parsing SankeyRow from {:?}", self);
        serde_json::from_value(self).change_context(ParsingError::StructParseFailure(
            "Failed to parse Sankey in clickhouse results",
        ))
    }
}

pub async fn get_sankey_data(
    clickhouse_client: &ClickhouseClient,
    auth: &AuthInfo,
    time_range: &TimeRange,
) -> MetricsResult<Vec<SankeyRow>> {
    let mut query_builder =
        QueryBuilder::<ClickhouseClient>::new(AnalyticsCollection::Authentications);

    query_builder
        .add_select_column(Aggregate::<String>::Count {
            field: None,
            alias: Some("count"),
        })
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("exemption_requested")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("exemption_accepted")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("authentication_status")
        .change_context(MetricsError::QueryBuildingError)?;

    auth.set_filter_clause(&mut query_builder)
        .change_context(MetricsError::QueryBuildingError)?;

    time_range
        .set_filter_clause(&mut query_builder)
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("exemption_requested")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("exemption_accepted")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("authentication_status")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .execute_query::<SankeyRow, _>(clickhouse_client)
        .await
        .change_context(MetricsError::QueryBuildingError)?
        .change_context(MetricsError::QueryExecutionFailure)?
        .into_iter()
        .map(Ok)
        .collect()
}


// File: crates/test_utils/tests/connectors/selenium.rs
// Module: test_utils
// Public functions: 5
// Public structs: 7

#![allow(
    clippy::expect_used,
    clippy::panic,
    clippy::unwrap_in_result,
    clippy::missing_panics_doc,
    clippy::unwrap_used
)]
use std::{
    collections::{HashMap, HashSet},
    env,
    io::Read,
    path::{MAIN_SEPARATOR, MAIN_SEPARATOR_STR},
    time::Duration,
};

use async_trait::async_trait;
use base64::Engine;
use serde::{Deserialize, Serialize};
use serde_json::json;
use test_utils::connector_auth;
use thirtyfour::{components::SelectElement, prelude::*, WebDriver};

#[derive(Clone)]
pub enum Event<'a> {
    RunIf(Assert<'a>, Vec<Event<'a>>),
    EitherOr(Assert<'a>, Vec<Event<'a>>, Vec<Event<'a>>),
    Assert(Assert<'a>),
    Trigger(Trigger<'a>),
}

#[derive(Clone)]
#[allow(dead_code)]
pub enum Trigger<'a> {
    Goto(&'a str),
    Click(By),
    ClickNth(By, usize),
    SelectOption(By, &'a str),
    ChangeQueryParam(&'a str, &'a str),
    SwitchTab(Position),
    SwitchFrame(By),
    Find(By),
    Query(By),
    SendKeys(By, &'a str),
    Sleep(u64),
}

#[derive(Clone)]
pub enum Position {
    Prev,
    Next,
}
#[derive(Clone)]
pub enum Selector {
    Title,
    QueryParamStr,
}

#[derive(Clone)]
pub enum Assert<'a> {
    Eq(Selector, &'a str),
    Contains(Selector, &'a str),
    ContainsAny(Selector, Vec<&'a str>),
    EitherOfThemExist(&'a str, &'a str),
    IsPresent(&'a str),
    IsElePresent(By),
    IsPresentNow(&'a str),
}

pub static CHECKOUT_BASE_URL: &str = "https://hs-payments-test.netlify.app";
#[async_trait]
pub trait SeleniumTest {
    fn get_saved_testcases(&self) -> serde_json::Value {
        get_saved_testcases()
    }
    fn get_configs(&self) -> connector_auth::ConnectorAuthentication {
        get_configs()
    }
    async fn retry_click(
        &self,
        times: i32,
        interval: u64,
        driver: &WebDriver,
        by: By,
    ) -> Result<(), WebDriverError> {
        let mut res = Ok(());
        for _i in 0..times {
            res = self.click_element(driver, by.clone()).await;
            if res.is_err() {
                tokio::time::sleep(Duration::from_secs(interval)).await;
            } else {
                break;
            }
        }
        return res;
    }
    fn get_connector_name(&self) -> String;
    async fn complete_actions(
        &self,
        driver: &WebDriver,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        for action in actions {
            match action {
                Event::Assert(assert) => match assert {
                    Assert::Contains(selector, text) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            assert!(url.query().unwrap().contains(text))
                        }
                        _ => assert!(driver.title().await?.contains(text)),
                    },
                    Assert::ContainsAny(selector, search_keys) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            assert!(search_keys
                                .iter()
                                .any(|key| url.query().unwrap().contains(key)))
                        }
                        _ => assert!(driver.title().await?.contains(search_keys.first().unwrap())),
                    },
                    Assert::EitherOfThemExist(text_1, text_2) => assert!(
                        is_text_present_now(driver, text_1).await?
                            || is_text_present_now(driver, text_2).await?
                    ),
                    Assert::Eq(_selector, text) => assert_eq!(driver.title().await?, text),
                    Assert::IsPresent(text) => {
                        assert!(is_text_present(driver, text).await?)
                    }
                    Assert::IsElePresent(selector) => {
                        assert!(is_element_present(driver, selector).await?)
                    }
                    Assert::IsPresentNow(text) => {
                        assert!(is_text_present_now(driver, text).await?)
                    }
                },
                Event::RunIf(con_event, events) => match con_event {
                    Assert::Contains(selector, text) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            if url.query().unwrap().contains(text) {
                                self.complete_actions(driver, events).await?;
                            }
                        }
                        _ => assert!(driver.title().await?.contains(text)),
                    },
                    Assert::ContainsAny(selector, keys) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            if keys.iter().any(|key| url.query().unwrap().contains(key)) {
                                self.complete_actions(driver, events).await?;
                            }
                        }
                        _ => assert!(driver.title().await?.contains(keys.first().unwrap())),
                    },
                    Assert::Eq(_selector, text) => {
                        if text == driver.title().await? {
                            self.complete_actions(driver, events).await?;
                        }
                    }
                    Assert::EitherOfThemExist(text_1, text_2) => {
                        if is_text_present_now(driver, text_1).await.is_ok()
                            || is_text_present_now(driver, text_2).await.is_ok()
                        {
                            self.complete_actions(driver, events).await?;
                        }
                    }
                    Assert::IsPresent(text) => {
                        if is_text_present(driver, text).await.is_ok() {
                            self.complete_actions(driver, events).await?;
                        }
                    }
                    Assert::IsElePresent(text) => {
                        if is_element_present(driver, text).await.is_ok() {
                            self.complete_actions(driver, events).await?;
                        }
                    }
                    Assert::IsPresentNow(text) => {
                        if is_text_present_now(driver, text).await.is_ok() {
                            self.complete_actions(driver, events).await?;
                        }
                    }
                },
                Event::EitherOr(con_event, success, failure) => match con_event {
                    Assert::Contains(selector, text) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            self.complete_actions(
                                driver,
                                if url.query().unwrap().contains(text) {
                                    success
                                } else {
                                    failure
                                },
                            )
                            .await?;
                        }
                        _ => assert!(driver.title().await?.contains(text)),
                    },
                    Assert::ContainsAny(selector, keys) => match selector {
                        Selector::QueryParamStr => {
                            let url = driver.current_url().await?;
                            self.complete_actions(
                                driver,
                                if keys.iter().any(|key| url.query().unwrap().contains(key)) {
                                    success
                                } else {
                                    failure
                                },
                            )
                            .await?;
                        }
                        _ => assert!(driver.title().await?.contains(keys.first().unwrap())),
                    },
                    Assert::Eq(_selector, text) => {
                        self.complete_actions(
                            driver,
                            if text == driver.title().await? {
                                success
                            } else {
                                failure
                            },
                        )
                        .await?;
                    }
                    Assert::EitherOfThemExist(text_1, text_2) => {
                        self.complete_actions(
                            driver,
                            if is_text_present_now(driver, text_1).await.is_ok()
                                || is_text_present_now(driver, text_2).await.is_ok()
                            {
                                success
                            } else {
                                failure
                            },
                        )
                        .await?;
                    }
                    Assert::IsPresent(text) => {
                        self.complete_actions(
                            driver,
                            if is_text_present(driver, text).await.is_ok() {
                                success
                            } else {
                                failure
                            },
                        )
                        .await?;
                    }
                    Assert::IsElePresent(by) => {
                        self.complete_actions(
                            driver,
                            if is_element_present(driver, by).await.is_ok() {
                                success
                            } else {
                                failure
                            },
                        )
                        .await?;
                    }
                    Assert::IsPresentNow(text) => {
                        self.complete_actions(
                            driver,
                            if is_text_present_now(driver, text).await.is_ok() {
                                success
                            } else {
                                failure
                            },
                        )
                        .await?;
                    }
                },
                Event::Trigger(trigger) => match trigger {
                    Trigger::Goto(url) => {
                        let saved_tests =
                            serde_json::to_string(&self.get_saved_testcases()).unwrap();
                        let conf = serde_json::to_string(&self.get_configs()).unwrap();
                        let configs = self.get_configs().automation_configs.unwrap();
                        let hs_base_url = configs
                            .hs_base_url
                            .unwrap_or_else(|| "http://localhost:8080".to_string());
                        let configs_url = configs.configs_url.unwrap();
                        let hs_api_keys = configs.hs_api_keys.unwrap();
                        let test_env = configs.hs_test_env.unwrap();
                        let script = &[
                            format!("localStorage.configs='{configs_url}'").as_str(),
                            format!("localStorage.current_env='{test_env}'").as_str(),
                            "localStorage.hs_api_key=''",
                            format!("localStorage.hs_api_keys='{hs_api_keys}'").as_str(),
                            format!("localStorage.base_url='{hs_base_url}'").as_str(),
                            format!("localStorage.hs_api_configs='{conf}'").as_str(),
                            format!("localStorage.saved_payments=JSON.stringify({saved_tests})")
                                .as_str(),
                            "localStorage.force_sync='true'",
                            format!(
                                "localStorage.current_connector=\"{}\";",
                                self.get_connector_name().clone()
                            )
                            .as_str(),
                        ]
                        .join(";");
                        driver.goto(url).await?;
                        driver.execute(script, Vec::new()).await?;
                    }
                    Trigger::Click(by) => {
                        self.retry_click(3, 5, driver, by.clone()).await?;
                    }
                    Trigger::ClickNth(by, n) => {
                        let ele = driver.query(by).all().await?.into_iter().nth(n).unwrap();
                        ele.wait_until().enabled().await?;
                        ele.wait_until().displayed().await?;
                        ele.wait_until().clickable().await?;
                        ele.scroll_into_view().await?;
                        ele.click().await?;
                    }
                    Trigger::Find(by) => {
                        driver.find(by).await?;
                    }
                    Trigger::Query(by) => {
                        driver.query(by).first().await?;
                    }
                    Trigger::SendKeys(by, input) => {
                        let ele = driver.query(by).first().await?;
                        ele.wait_until().displayed().await?;
                        ele.send_keys(&input).await?;
                    }
                    Trigger::SelectOption(by, input) => {
                        let ele = driver.query(by).first().await?;
                        let select_element = SelectElement::new(&ele).await?;
                        select_element.select_by_partial_text(input).await?;
                    }
                    Trigger::ChangeQueryParam(param, value) => {
                        let mut url = driver.current_url().await?;
                        let mut hash_query: HashMap<String, String> =
                            url.query_pairs().into_owned().collect();
                        hash_query.insert(param.to_string(), value.to_string());
                        let url_str = serde_urlencoded::to_string(hash_query)
                            .expect("Query Param update failed");
                        url.set_query(Some(&url_str));
                        driver.goto(url.as_str()).await?;
                    }
                    Trigger::Sleep(seconds) => {
                        tokio::time::sleep(Duration::from_secs(seconds)).await;
                    }
                    Trigger::SwitchTab(position) => match position {
                        Position::Next => {
                            let windows = driver.windows().await?;
                            if let Some(window) = windows.iter().next_back() {
                                driver.switch_to_window(window.to_owned()).await?;
                            }
                        }
                        Position::Prev => {
                            let windows = driver.windows().await?;
                            if let Some(window) = windows.into_iter().next() {
                                driver.switch_to_window(window.to_owned()).await?;
                            }
                        }
                    },
                    Trigger::SwitchFrame(by) => {
                        let iframe = driver.query(by).first().await?;
                        iframe.wait_until().displayed().await?;
                        iframe.clone().enter_frame().await?;
                    }
                },
            }
        }
        Ok(())
    }

    async fn click_element(&self, driver: &WebDriver, by: By) -> Result<(), WebDriverError> {
        let ele = driver.query(by).first().await?;
        ele.wait_until().enabled().await?;
        ele.wait_until().displayed().await?;
        ele.wait_until().clickable().await?;
        ele.scroll_into_view().await?;
        ele.click().await
    }

    async fn make_redirection_payment(
        &self,
        web_driver: WebDriver,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        // To support failure retries
        let result = self
            .execute_steps(web_driver.clone(), actions.clone())
            .await;
        if result.is_err() {
            self.execute_steps(web_driver, actions).await
        } else {
            result
        }
    }
    async fn execute_steps(
        &self,
        web_driver: WebDriver,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        let config = self.get_configs().automation_configs.unwrap();
        if config.run_minimum_steps.unwrap() {
            self.complete_actions(&web_driver, actions.get(..3).unwrap().to_vec())
                .await
        } else {
            self.complete_actions(&web_driver, actions).await
        }
    }
    async fn make_gpay_payment(
        &self,
        web_driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        self.execute_gpay_steps(web_driver, url, actions).await
    }
    async fn execute_gpay_steps(
        &self,
        web_driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        let config = self.get_configs().automation_configs.unwrap();
        let (email, pass) = (&config.gmail_email.unwrap(), &config.gmail_pass.unwrap());
        let default_actions = vec![
            Event::Trigger(Trigger::Goto(url)),
            Event::Trigger(Trigger::Click(By::Css(".gpay-button"))),
            Event::Trigger(Trigger::SwitchTab(Position::Next)),
            Event::Trigger(Trigger::Sleep(5)),
            Event::RunIf(
                Assert::EitherOfThemExist("Use your Google Account", "Sign in"),
                vec![
                    Event::Trigger(Trigger::SendKeys(By::Id("identifierId"), email)),
                    Event::Trigger(Trigger::ClickNth(By::Tag("button"), 2)),
                    Event::EitherOr(
                        Assert::IsPresent("Welcome"),
                        vec![
                            Event::Trigger(Trigger::SendKeys(By::Name("Passwd"), pass)),
                            Event::Trigger(Trigger::Sleep(2)),
                            Event::Trigger(Trigger::Click(By::Id("passwordNext"))),
                            Event::Trigger(Trigger::Sleep(10)),
                        ],
                        vec![
                            Event::Trigger(Trigger::SendKeys(By::Id("identifierId"), email)),
                            Event::Trigger(Trigger::ClickNth(By::Tag("button"), 2)),
                            Event::Trigger(Trigger::SendKeys(By::Name("Passwd"), pass)),
                            Event::Trigger(Trigger::Sleep(2)),
                            Event::Trigger(Trigger::Click(By::Id("passwordNext"))),
                            Event::Trigger(Trigger::Sleep(10)),
                        ],
                    ),
                ],
            ),
            Event::Trigger(Trigger::SwitchFrame(By::Css(
                ".bootstrapperIframeContainerElement iframe",
            ))),
            Event::Assert(Assert::IsPresent("Gpay Tester")),
            Event::Trigger(Trigger::Click(By::ClassName("jfk-button-action"))),
            Event::Trigger(Trigger::SwitchTab(Position::Prev)),
        ];
        self.complete_actions(&web_driver, default_actions).await?;
        self.complete_actions(&web_driver, actions).await
    }
    async fn make_affirm_payment(
        &self,
        driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        self.complete_actions(
            &driver,
            vec![
                Event::Trigger(Trigger::Goto(url)),
                Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            ],
        )
        .await?;
        let mut affirm_actions = vec![
            Event::RunIf(
                Assert::IsPresent("Big purchase? No problem."),
                vec![
                    Event::Trigger(Trigger::SendKeys(
                        By::Css("input[data-testid='phone-number-field']"),
                        "(833) 549-5574", // any test phone number accepted by affirm
                    )),
                    Event::Trigger(Trigger::Click(By::Css(
                        "button[data-testid='submit-button']",
                    ))),
                    Event::Trigger(Trigger::SendKeys(
                        By::Css("input[data-testid='phone-pin-field']"),
                        "1234",
                    )),
                ],
            ),
            Event::Trigger(Trigger::Click(By::Css(
                "button[data-testid='skip-payment-button']",
            ))),
            Event::Trigger(Trigger::Click(By::Css("div[data-testid='indicator']"))),
            Event::Trigger(Trigger::Click(By::Css(
                "button[data-testid='submit-button']",
            ))),
            Event::Trigger(Trigger::Click(By::Css("div[data-testid='indicator']"))),
            Event::Trigger(Trigger::Click(By::Css(
                "div[data-testid='disclosure-checkbox-indicator']",
            ))),
            Event::Trigger(Trigger::Click(By::Css(
                "button[data-testid='submit-button']",
            ))),
        ];
        affirm_actions.extend(actions);
        self.complete_actions(&driver, affirm_actions).await
    }
    async fn make_webhook_test(
        &self,
        web_driver: WebDriver,
        payment_url: &str,
        actions: Vec<Event<'_>>,
        webhook_retry_time: u64,
        webhook_status: &str,
    ) -> Result<(), WebDriverError> {
        self.complete_actions(
            &web_driver,
            vec![Event::Trigger(Trigger::Goto(payment_url))],
        )
        .await?;
        self.complete_actions(&web_driver, actions).await?; //additional actions needs to make a payment
        self.complete_actions(
            &web_driver,
            vec![Event::Trigger(Trigger::Goto(&format!(
                "{CHECKOUT_BASE_URL}/events"
            )))],
        )
        .await?;
        let element = web_driver.query(By::Css("h2.last-payment")).first().await?;
        let payment_id = element.text().await?;
        let retries = 3; // no of retry times
        for _i in 0..retries {
            let configs = self.get_configs().automation_configs.unwrap();
            let outgoing_webhook_url = configs.hs_webhook_url.unwrap().to_string();
            let client = reqwest::Client::new();
            let response = client.get(outgoing_webhook_url).send().await.unwrap(); // get events from outgoing webhook endpoint
            let body_text = response.text().await.unwrap();
            let data: WebhookResponse = serde_json::from_str(&body_text).unwrap();
            let last_three_events = data.data.get(data.data.len().saturating_sub(3)..).unwrap(); // Get the last three elements if available
            for last_event in last_three_events {
                let last_event_body = &last_event.step.request.body;
                let decoded_bytes = base64::engine::general_purpose::STANDARD //decode the encoded outgoing webhook event
                    .decode(last_event_body)
                    .unwrap();
                let decoded_str = String::from_utf8(decoded_bytes).unwrap();
                let webhook_response: HsWebhookResponse =
                    serde_json::from_str(&decoded_str).unwrap();
                if payment_id == webhook_response.content.object.payment_id
                    && webhook_status == webhook_response.content.object.status
                {
                    return Ok(());
                }
            }
            self.complete_actions(
                &web_driver,
                vec![Event::Trigger(Trigger::Sleep(webhook_retry_time))],
            )
            .await?;
        }
        Err(WebDriverError::CustomError("Webhook Not Found".to_string()))
    }
    async fn make_paypal_payment(
        &self,
        web_driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        let pypl_url = url.to_string();
        // To support failure retries
        let result = self
            .execute_paypal_steps(web_driver.clone(), &pypl_url, actions.clone())
            .await;
        if result.is_err() {
            self.execute_paypal_steps(web_driver.clone(), &pypl_url, actions.clone())
                .await
        } else {
            result
        }
    }
    async fn execute_paypal_steps(
        &self,
        web_driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        self.complete_actions(
            &web_driver,
            vec![
                Event::Trigger(Trigger::Goto(url)),
                Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            ],
        )
        .await?;
        let (email, pass) = (
            &self
                .get_configs()
                .automation_configs
                .unwrap()
                .pypl_email
                .unwrap(),
            &self
                .get_configs()
                .automation_configs
                .unwrap()
                .pypl_pass
                .unwrap(),
        );
        let mut pypl_actions = vec![
            Event::Trigger(Trigger::Sleep(8)),
            Event::RunIf(
                Assert::IsPresentNow("Enter your email address to get started"),
                vec![
                    Event::Trigger(Trigger::SendKeys(By::Id("email"), email)),
                    Event::Trigger(Trigger::Click(By::Id("btnNext"))),
                ],
            ),
            Event::RunIf(
                Assert::IsPresentNow("Password"),
                vec![
                    Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
                    Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
                ],
            ),
        ];
        pypl_actions.extend(actions);
        self.complete_actions(&web_driver, pypl_actions).await
    }
    async fn make_clearpay_payment(
        &self,
        driver: WebDriver,
        url: &str,
        actions: Vec<Event<'_>>,
    ) -> Result<(), WebDriverError> {
        self.complete_actions(
            &driver,
            vec![
                Event::Trigger(Trigger::Goto(url)),
                Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
                Event::Trigger(Trigger::Sleep(5)),
                Event::RunIf(
                    Assert::IsPresentNow("Manage Cookies"),
                    vec![
                        Event::Trigger(Trigger::Click(By::Css("button.cookie-setting-link"))),
                        Event::Trigger(Trigger::Click(By::Id("accept-recommended-btn-handler"))),
                    ],
                ),
            ],
        )
        .await?;
        let (email, pass) = (
            &self
                .get_configs()
                .automation_configs
                .unwrap()
                .clearpay_email
                .unwrap(),
            &self
                .get_configs()
                .automation_configs
                .unwrap()
                .clearpay_pass
                .unwrap(),
        );
        let mut clearpay_actions = vec![
            Event::Trigger(Trigger::Sleep(3)),
            Event::EitherOr(
                Assert::IsPresent("Please enter your password"),
                vec![
                    Event::Trigger(Trigger::SendKeys(By::Css("input[name='password']"), pass)),
                    Event::Trigger(Trigger::Click(By::Css("button[type='submit']"))),
                ],
                vec![
                    Event::Trigger(Trigger::SendKeys(
                        By::Css("input[name='identifier']"),
                        email,
                    )),
                    Event::Trigger(Trigger::Click(By::Css("button[type='submit']"))),
                    Event::Trigger(Trigger::Sleep(3)),
                    Event::Trigger(Trigger::SendKeys(By::Css("input[name='password']"), pass)),
                    Event::Trigger(Trigger::Click(By::Css("button[type='submit']"))),
                ],
            ),
            Event::Trigger(Trigger::Click(By::Css(
                "button[data-testid='summary-button']",
            ))),
        ];
        clearpay_actions.extend(actions);
        self.complete_actions(&driver, clearpay_actions).await
    }
}
async fn is_text_present_now(driver: &WebDriver, key: &str) -> WebDriverResult<bool> {
    let mut xpath = "//*[contains(text(),'".to_owned();
    xpath.push_str(key);
    xpath.push_str("')]");
    let result = driver.find(By::XPath(&xpath)).await?;
    let display: &str = &result.css_value("display").await?;
    if display.is_empty() || display == "none" {
        return Err(WebDriverError::CustomError("Element is hidden".to_string()));
    }
    result.is_present().await
}
async fn is_text_present(driver: &WebDriver, key: &str) -> WebDriverResult<bool> {
    let mut xpath = "//*[contains(text(),'".to_owned();
    xpath.push_str(key);
    xpath.push_str("')]");
    let result = driver.query(By::XPath(&xpath)).first().await?;
    result.is_present().await
}
async fn is_element_present(driver: &WebDriver, by: By) -> WebDriverResult<bool> {
    let element = driver.query(by).first().await?;
    element.is_present().await
}

#[macro_export]
macro_rules! tester_inner {
    ($execute:ident, $webdriver:expr) => {{
        use std::{
            sync::{Arc, Mutex},
            thread,
        };

        let driver = $webdriver;

        // we'll need the session_id from the thread
        // NOTE: even if it panics, so can't just return it
        let session_id = Arc::new(Mutex::new(None));

        // run test in its own thread to catch panics
        let sid = session_id.clone();
        let res = thread::spawn(move || {
            let runtime = tokio::runtime::Builder::new_current_thread()
                .enable_all()
                .build()
                .unwrap();
            let driver = runtime
                .block_on(driver)
                .expect("failed to construct test WebDriver");
            *sid.lock().unwrap() = runtime.block_on(driver.session_id()).ok();
            // make sure we close, even if an assertion fails
            let client = driver.clone();
            let x = runtime.block_on(async move {
                let run = tokio::spawn($execute(driver)).await;
                let _ = client.quit().await;
                run
            });
            drop(runtime);
            x.expect("test panicked")
        })
        .join();
        let success = handle_test_error(res);
        assert!(success);
    }};
}

#[macro_export]
macro_rules! function {
    () => {{
        fn f() {}
        fn type_name_of<T>(_: T) -> &'static str {
            std::any::type_name::<T>()
        }
        let name = type_name_of(f);
        &name.get(..name.len() - 3).unwrap()
    }};
}

#[macro_export]
macro_rules! tester {
    ($f:ident) => {{
        use $crate::{function, tester_inner};
        let test_name = format!("{:?}", function!());
        if (should_ignore_test(&test_name)) {
            return;
        }
        let browser = get_browser();
        let url = make_url(&browser);
        let caps = make_capabilities(&browser);
        tester_inner!($f, WebDriver::new(url, caps));
    }};
}

fn get_saved_testcases() -> serde_json::Value {
    let env_value = env::var("CONNECTOR_TESTS_FILE_PATH").ok();
    if env_value.is_none() {
        return serde_json::json!("");
    }
    let path = env_value.unwrap();
    let mut file = &std::fs::File::open(path).expect("Failed to open file");
    let mut contents = String::new();
    file.read_to_string(&mut contents)
        .expect("Failed to read file");

    // Parse the JSON data
    serde_json::from_str(&contents).expect("Failed to parse JSON")
}
fn get_configs() -> connector_auth::ConnectorAuthentication {
    let path =
        env::var("CONNECTOR_AUTH_FILE_PATH").expect("connector authentication file path not set");
    toml::from_str(
        &std::fs::read_to_string(path).expect("connector authentication config file not found"),
    )
    .expect("Failed to read connector authentication config file")
}

pub fn should_ignore_test(name: &str) -> bool {
    let conf = get_saved_testcases()
        .get("tests_to_ignore")
        .unwrap_or(&json!([]))
        .clone();
    let tests_to_ignore: HashSet<String> =
        serde_json::from_value(conf).unwrap_or_else(|_| HashSet::new());
    let modules: Vec<_> = name.split("::").collect();
    let file_match = format!(
        "{}::*",
        <&str>::clone(modules.get(1).expect("Error obtaining module path segment"))
    );
    let module_name = modules
        .get(1..3)
        .expect("Error obtaining module path segment")
        .join("::");
    // Ignore if it matches patterns like nuvei_ui::*, nuvei_ui::should_make_nuvei_eps_payment_test
    tests_to_ignore.contains(&file_match) || tests_to_ignore.contains(&module_name)
}

pub fn get_browser() -> String {
    "firefox".to_string()
}

// based on the browser settings build profile info
pub fn make_capabilities(browser: &str) -> Capabilities {
    match browser {
        "firefox" => {
            let mut caps = DesiredCapabilities::firefox();
            let ignore_profile = env::var("IGNORE_BROWSER_PROFILE").ok();
            if ignore_profile.is_none() || ignore_profile.unwrap() == "false" {
                let profile_path = &format!("-profile={}", get_firefox_profile_path().unwrap());
                caps.add_firefox_arg(profile_path).unwrap();
            } else {
                let profile_path = &format!("-profile={}", get_firefox_profile_path().unwrap());
                caps.add_firefox_arg(profile_path).unwrap();
                caps.add_firefox_arg("--headless").ok();
            }
            caps.into()
        }
        "chrome" => {
            let mut caps = DesiredCapabilities::chrome();
            let profile_path = &format!("user-data-dir={}", get_chrome_profile_path().unwrap());
            caps.add_chrome_arg(profile_path).unwrap();
            caps.into()
        }
        &_ => DesiredCapabilities::safari().into(),
    }
}

fn get_chrome_profile_path() -> Result<String, WebDriverError> {
    let exe = env::current_exe()?;
    let dir = exe.parent().expect("Executable must be in some directory");
    let mut base_path = dir
        .to_str()
        .map(|str| {
            let mut fp = str.split(MAIN_SEPARATOR).collect::<Vec<_>>();
            fp.truncate(3);
            fp.join(MAIN_SEPARATOR_STR)
        })
        .unwrap();
    if env::consts::OS == "macos" {
        base_path.push_str(r"/Library/Application\ Support/Google/Chrome/Default");
        //Issue: 1573
    } // We're only using Firefox on Ubuntu runner
    Ok(base_path)
}

fn get_firefox_profile_path() -> Result<String, WebDriverError> {
    let exe = env::current_exe()?;
    let dir = exe.parent().expect("Executable must be in some directory");
    let mut base_path = dir
        .to_str()
        .map(|str| {
            let mut fp = str.split(MAIN_SEPARATOR).collect::<Vec<_>>();
            fp.truncate(3);
            fp.join(MAIN_SEPARATOR_STR)
        })
        .unwrap();
    if env::consts::OS == "macos" {
        base_path.push_str(r#"/Library/Application Support/Firefox/Profiles/hs-test"#);
    //Issue: 1573
    } else if env::consts::OS == "linux" {
        if let Some(home_dir) = env::var_os("HOME") {
            if let Some(home_path) = home_dir.to_str() {
                let profile_path = format!("{home_path}/.mozilla/firefox/hs-test");
                return Ok(profile_path);
            }
        }
    }
    Ok(base_path)
}

pub fn make_url(browser: &str) -> &'static str {
    match browser {
        "firefox" => "http://localhost:4444",
        "chrome" => "http://localhost:9515",
        &_ => "",
    }
}

pub fn handle_test_error(
    res: Result<Result<(), WebDriverError>, Box<dyn std::any::Any + Send>>,
) -> bool {
    match res {
        Ok(Ok(_)) => true,
        Ok(Err(web_driver_error)) => {
            eprintln!("test future failed to resolve: {web_driver_error:?}");
            false
        }
        Err(e) => {
            if let Some(web_driver_error) = e.downcast_ref::<WebDriverError>() {
                eprintln!("test future panicked: {web_driver_error:?}");
            } else {
                eprintln!("test future panicked; an assertion probably failed");
            }
            false
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WebhookResponse {
    data: Vec<WebhookResponseData>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WebhookResponseData {
    step: WebhookRequestData,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WebhookRequestData {
    request: WebhookRequest,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WebhookRequest {
    body: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HsWebhookResponse {
    content: HsWebhookContent,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HsWebhookContent {
    object: HsWebhookObject,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HsWebhookObject {
    payment_id: String,
    status: String,
    connector: String,
}


// Struct: Proxy
// File: crates/hyperswitch_interfaces/src/types.rs
// Module: hyperswitch_interfaces
// Implementations: 1
// Traits: Default

pub struct Proxy


// Implementation: impl Responder
// File: crates/router/src/analytics.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Function: list_metadata_by_merchant_id
// File: crates/diesel_models/src/query/routing_algorithm.rs
// Module: diesel_models

pub fn list_metadata_by_merchant_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<RoutingProfileMetadata>>


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

pub struct RefundsData


// Trait: PayoutIndividualDetailsExt
// File: crates/router/src/types.rs
// Module: router

pub trait PayoutIndividualDetailsExt


// Struct: CardTestingGuardData
// File: crates/hyperswitch_domain_models/src/card_testing_guard_data.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct CardTestingGuardData


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

impl api::RefundSync for for Itaubank


// Module Structure
// File: crates/analytics/src/api_event/metrics.rs
// Module: analytics

// Public submodules:
pub mod latency;


// Function: to_num
// File: crates/euclid_macros/src/inner/enum_nums.rs
// Module: euclid_macros

pub fn to_num(&self) -> usize


// Implementation: impl DummySignal
// File: crates/common_utils/src/signals.rs
// Module: common_utils
// Methods: 2 total (2 public)

impl DummySignal


// Function: profile_create
// File: crates/openapi/src/routes/profile.rs
// Module: openapi

pub fn profile_create()


// Struct: CheckoutApplePayData
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutApplePayData


// File: crates/smithy-core/src/types.rs
// Module: smithy-core
// Public functions: 1
// Public structs: 5

// crates/smithy-core/types.rs

use std::collections::HashMap;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SmithyModel {
    pub namespace: String,
    pub shapes: HashMap<String, SmithyShape>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum SmithyShape {
    #[serde(rename = "structure")]
    Structure {
        members: HashMap<String, SmithyMember>,
        #[serde(skip_serializing_if = "Option::is_none")]
        documentation: Option<String>,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "string")]
    String {
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "integer")]
    Integer {
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "long")]
    Long {
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "boolean")]
    Boolean {
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "list")]
    List {
        member: Box<SmithyMember>,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "union")]
    Union {
        members: HashMap<String, SmithyMember>,
        #[serde(skip_serializing_if = "Option::is_none")]
        documentation: Option<String>,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
    #[serde(rename = "enum")]
    Enum {
        values: HashMap<String, SmithyEnumValue>,
        #[serde(skip_serializing_if = "Option::is_none")]
        documentation: Option<String>,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        traits: Vec<SmithyTrait>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SmithyMember {
    pub target: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub documentation: Option<String>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub traits: Vec<SmithyTrait>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SmithyEnumValue {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub documentation: Option<String>,
    pub is_default: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "trait")]
pub enum SmithyTrait {
    #[serde(rename = "smithy.api#pattern")]
    Pattern { pattern: String },
    #[serde(rename = "smithy.api#range")]
    Range { min: Option<i64>, max: Option<i64> },
    #[serde(rename = "smithy.api#required")]
    Required,
    #[serde(rename = "smithy.api#documentation")]
    Documentation { documentation: String },
    #[serde(rename = "smithy.api#length")]
    Length { min: Option<u64>, max: Option<u64> },
    #[serde(rename = "smithy.api#httpLabel")]
    HttpLabel,
    #[serde(rename = "smithy.api#httpQuery")]
    HttpQuery { name: String },
    #[serde(rename = "smithy.api#mixin")]
    Mixin,
}

#[derive(Debug, Clone)]
pub struct SmithyField {
    pub name: String,
    pub value_type: String,
    pub constraints: Vec<SmithyConstraint>,
    pub documentation: Option<String>,
    pub optional: bool,
    pub flatten: bool,
}

#[derive(Debug, Clone)]
pub struct SmithyEnumVariant {
    pub name: String,
    pub fields: Vec<SmithyField>,
    pub constraints: Vec<SmithyConstraint>,
    pub documentation: Option<String>,
}

#[derive(Debug, Clone)]
pub enum SmithyConstraint {
    Pattern(String),
    Range(Option<i64>, Option<i64>),
    Length(Option<u64>, Option<u64>),
    Required,
    HttpLabel,
    HttpQuery(String),
}

pub trait SmithyModelGenerator {
    fn generate_smithy_model() -> SmithyModel;
}

// Helper functions moved from the proc-macro crate to be accessible by it.

pub fn resolve_type_and_generate_shapes(
    value_type: &str,
    shapes: &mut HashMap<String, SmithyShape>,
) -> Result<(String, HashMap<String, SmithyShape>), syn::Error> {
    let value_type = value_type.trim();
    let value_type_span = proc_macro2::Span::call_site();
    let mut generated_shapes = HashMap::new();

    let target_type = match value_type {
        "String" | "str" => "smithy.api#String".to_string(),
        "i8" | "i16" | "i32" | "u8" | "u16" | "u32" => "smithy.api#Integer".to_string(),
        "i64" | "u64" | "isize" | "usize" => "smithy.api#Long".to_string(),
        "f32" => "smithy.api#Float".to_string(),
        "f64" => "smithy.api#Double".to_string(),
        "bool" => "smithy.api#Boolean".to_string(),
        "PrimitiveDateTime" | "time::PrimitiveDateTime" => "smithy.api#Timestamp".to_string(),
        "Amount" | "MinorUnit" => "smithy.api#Long".to_string(),
        "serde_json::Value" | "Value" | "Object" => "smithy.api#Document".to_string(),
        "Url" | "url::Url" => "smithy.api#String".to_string(),

        vt if vt.starts_with("Option<") && vt.ends_with('>') => {
            let inner_type = extract_generic_inner_type(vt, "Option")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (resolved_type, new_shapes) = resolve_type_and_generate_shapes(inner_type, shapes)?;
            generated_shapes.extend(new_shapes);
            resolved_type
        }

        vt if vt.starts_with("Vec<") && vt.ends_with('>') => {
            let inner_type = extract_generic_inner_type(vt, "Vec")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (inner_smithy_type, new_shapes) =
                resolve_type_and_generate_shapes(inner_type, shapes)?;
            generated_shapes.extend(new_shapes);

            let list_shape_name = format!(
                "{}List",
                inner_smithy_type
                    .split("::")
                    .last()
                    .unwrap_or(&inner_smithy_type)
                    .split('#')
                    .next_back()
                    .unwrap_or(&inner_smithy_type)
            );
            if !shapes.contains_key(&list_shape_name)
                && !generated_shapes.contains_key(&list_shape_name)
            {
                let list_shape = SmithyShape::List {
                    member: Box::new(SmithyMember {
                        target: inner_smithy_type,
                        documentation: None,
                        traits: vec![],
                    }),
                    traits: vec![],
                };
                generated_shapes.insert(list_shape_name.clone(), list_shape);
            }
            list_shape_name
        }

        vt if vt.starts_with("Box<") && vt.ends_with('>') => {
            let inner_type = extract_generic_inner_type(vt, "Box")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (resolved_type, new_shapes) = resolve_type_and_generate_shapes(inner_type, shapes)?;
            generated_shapes.extend(new_shapes);
            resolved_type
        }

        vt if vt.starts_with("Secret<") && vt.ends_with('>') => {
            let inner_type = extract_generic_inner_type(vt, "Secret")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (resolved_type, new_shapes) = resolve_type_and_generate_shapes(inner_type, shapes)?;
            generated_shapes.extend(new_shapes);
            resolved_type
        }

        vt if vt.starts_with("HashMap<") && vt.ends_with('>') => {
            let inner_types = extract_generic_inner_type(vt, "HashMap")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (key_type, value_type) =
                parse_map_types(inner_types).map_err(|e| syn::Error::new(value_type_span, e))?;
            let (key_smithy_type, key_shapes) = resolve_type_and_generate_shapes(key_type, shapes)?;
            generated_shapes.extend(key_shapes);
            let (value_smithy_type, value_shapes) =
                resolve_type_and_generate_shapes(value_type, shapes)?;
            generated_shapes.extend(value_shapes);
            format!(
                "smithy.api#Map<key: {}, value: {}>",
                key_smithy_type, value_smithy_type
            )
        }

        vt if vt.starts_with("BTreeMap<") && vt.ends_with('>') => {
            let inner_types = extract_generic_inner_type(vt, "BTreeMap")
                .map_err(|e| syn::Error::new(value_type_span, e))?;
            let (key_type, value_type) =
                parse_map_types(inner_types).map_err(|e| syn::Error::new(value_type_span, e))?;
            let (key_smithy_type, key_shapes) = resolve_type_and_generate_shapes(key_type, shapes)?;
            generated_shapes.extend(key_shapes);
            let (value_smithy_type, value_shapes) =
                resolve_type_and_generate_shapes(value_type, shapes)?;
            generated_shapes.extend(value_shapes);
            format!(
                "smithy.api#Map<key: {}, value: {}>",
                key_smithy_type, value_smithy_type
            )
        }

        _ => {
            if value_type.contains("::") {
                value_type.replace("::", ".")
            } else {
                value_type.to_string()
            }
        }
    };

    Ok((target_type, generated_shapes))
}

fn extract_generic_inner_type<'a>(full_type: &'a str, wrapper: &str) -> Result<&'a str, String> {
    let expected_start = format!("{}<", wrapper);

    if !full_type.starts_with(&expected_start) || !full_type.ends_with('>') {
        return Err(format!("Invalid {} type format: {}", wrapper, full_type));
    }

    let start_idx = expected_start.len();
    let end_idx = full_type.len() - 1;

    if start_idx >= end_idx {
        return Err(format!("Empty {} type: {}", wrapper, full_type));
    }

    if start_idx >= full_type.len() || end_idx > full_type.len() {
        return Err(format!(
            "Invalid index bounds for {} type: {}",
            wrapper, full_type
        ));
    }

    Ok(full_type
        .get(start_idx..end_idx)
        .ok_or_else(|| {
            format!(
                "Failed to extract inner type from {}: {}",
                wrapper, full_type
            )
        })?
        .trim())
}

fn parse_map_types(inner_types: &str) -> Result<(&str, &str), String> {
    // Handle nested generics by counting angle brackets
    let mut bracket_count = 0;
    let mut comma_pos = None;

    for (i, ch) in inner_types.char_indices() {
        match ch {
            '<' => bracket_count += 1,
            '>' => bracket_count -= 1,
            ',' if bracket_count == 0 => {
                comma_pos = Some(i);
                break;
            }
            _ => {}
        }
    }

    if let Some(pos) = comma_pos {
        let key_type = inner_types
            .get(..pos)
            .ok_or_else(|| format!("Invalid key type bounds in map: {}", inner_types))?
            .trim();
        let value_type = inner_types
            .get(pos + 1..)
            .ok_or_else(|| format!("Invalid value type bounds in map: {}", inner_types))?
            .trim();

        if key_type.is_empty() || value_type.is_empty() {
            return Err(format!("Invalid map type format: {}", inner_types));
        }

        Ok((key_type, value_type))
    } else {
        Err(format!(
            "Invalid map type format, missing comma: {}",
            inner_types
        ))
    }
}


// Function: list_user_authentication_methods_for_email_domain
// File: crates/diesel_models/src/query/user_authentication_method.rs
// Module: diesel_models

pub fn list_user_authentication_methods_for_email_domain(
        conn: &PgPooledConn,
        email_domain: &str,
    ) -> StorageResult<Vec<Self>>


// Function: get_customer_details_from_request
// File: crates/router/src/core/payouts/helpers.rs
// Module: router

pub fn get_customer_details_from_request(
    request: &payouts::PayoutCreateRequest,
) -> CustomerDetails


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

pub struct NovalnetPSyncResponse


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

pub struct WellsfargoRsyncResponse


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

pub fn link_routing_config_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    algorithm_id: common_utils::id_type::RoutingId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord>