// File: crates/redis_interface/src/lib.rs
// Module: redis_interface
// Public functions: 7
// Public structs: 4

//! Intermediate module for encapsulate all the redis related functionality
//!
//! Provides structs to represent redis connection and all functions that redis provides and
//! are used in the `router` crate. Abstractions for creating a new connection while also facilitating
//! redis connection pool and configuration based types.
//!
//!  # Examples
//! ```
//! use redis_interface::{types::RedisSettings, RedisConnectionPool};
//!
//! #[tokio::main]
//! async fn main() {
//!     let redis_conn = RedisConnectionPool::new(&RedisSettings::default()).await;
//!     // ... redis_conn ready to use
//! }
//! ```

pub mod commands;
pub mod errors;
pub mod types;

use std::sync::{atomic, Arc};

use common_utils::errors::CustomResult;
use error_stack::ResultExt;
pub use fred::interfaces::PubsubInterface;
use fred::{
    clients::Transaction,
    interfaces::ClientLike,
    prelude::{EventInterface, TransactionInterface},
};

pub use self::types::*;

pub struct RedisConnectionPool {
    pub pool: Arc<fred::prelude::RedisPool>,
    pub key_prefix: String,
    pub config: Arc<RedisConfig>,
    pub subscriber: Arc<SubscriberClient>,
    pub publisher: Arc<RedisClient>,
    pub is_redis_available: Arc<atomic::AtomicBool>,
}

pub struct RedisClient {
    inner: fred::prelude::RedisClient,
}

impl std::ops::Deref for RedisClient {
    type Target = fred::prelude::RedisClient;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl RedisClient {
    pub async fn new(
        config: fred::types::RedisConfig,
        reconnect_policy: fred::types::ReconnectPolicy,
        perf: fred::types::PerformanceConfig,
    ) -> CustomResult<Self, errors::RedisError> {
        let client =
            fred::prelude::RedisClient::new(config, Some(perf), None, Some(reconnect_policy));
        client.connect();
        client
            .wait_for_connect()
            .await
            .change_context(errors::RedisError::RedisConnectionError)?;
        Ok(Self { inner: client })
    }
}

pub struct SubscriberClient {
    inner: fred::clients::SubscriberClient,
    pub is_subscriber_handler_spawned: Arc<atomic::AtomicBool>,
}

impl SubscriberClient {
    pub async fn new(
        config: fred::types::RedisConfig,
        reconnect_policy: fred::types::ReconnectPolicy,
        perf: fred::types::PerformanceConfig,
    ) -> CustomResult<Self, errors::RedisError> {
        let client =
            fred::clients::SubscriberClient::new(config, Some(perf), None, Some(reconnect_policy));
        client.connect();
        client
            .wait_for_connect()
            .await
            .change_context(errors::RedisError::RedisConnectionError)?;
        Ok(Self {
            inner: client,
            is_subscriber_handler_spawned: Arc::new(atomic::AtomicBool::new(false)),
        })
    }
}

impl std::ops::Deref for SubscriberClient {
    type Target = fred::clients::SubscriberClient;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl RedisConnectionPool {
    /// Create a new Redis connection
    pub async fn new(conf: &RedisSettings) -> CustomResult<Self, errors::RedisError> {
        let redis_connection_url = match conf.cluster_enabled {
            // Fred relies on this format for specifying cluster where the host port is ignored & only query parameters are used for node addresses
            // redis-cluster://username:password@host:port?node=bar.com:30002&node=baz.com:30003
            true => format!(
                "redis-cluster://{}:{}?{}",
                conf.host,
                conf.port,
                conf.cluster_urls
                    .iter()
                    .flat_map(|url| vec!["&", url])
                    .skip(1)
                    .collect::<String>()
            ),
            false => format!(
                "redis://{}:{}", //URI Schema
                conf.host, conf.port,
            ),
        };
        let mut config = fred::types::RedisConfig::from_url(&redis_connection_url)
            .change_context(errors::RedisError::RedisConnectionError)?;

        let perf = fred::types::PerformanceConfig {
            auto_pipeline: conf.auto_pipeline,
            default_command_timeout: std::time::Duration::from_secs(conf.default_command_timeout),
            max_feed_count: conf.max_feed_count,
            backpressure: fred::types::BackpressureConfig {
                disable_auto_backpressure: conf.disable_auto_backpressure,
                max_in_flight_commands: conf.max_in_flight_commands,
                policy: fred::types::BackpressurePolicy::Drain,
            },
        };

        let connection_config = fred::types::ConnectionConfig {
            unresponsive_timeout: std::time::Duration::from_secs(conf.unresponsive_timeout),
            ..fred::types::ConnectionConfig::default()
        };

        if !conf.use_legacy_version {
            config.version = fred::types::RespVersion::RESP3;
        }
        config.tracing = fred::types::TracingConfig::new(true);
        config.blocking = fred::types::Blocking::Error;
        let reconnect_policy = fred::types::ReconnectPolicy::new_constant(
            conf.reconnect_max_attempts,
            conf.reconnect_delay,
        );

        let subscriber =
            SubscriberClient::new(config.clone(), reconnect_policy.clone(), perf.clone()).await?;

        let publisher =
            RedisClient::new(config.clone(), reconnect_policy.clone(), perf.clone()).await?;

        let pool = fred::prelude::RedisPool::new(
            config,
            Some(perf),
            Some(connection_config),
            Some(reconnect_policy),
            conf.pool_size,
        )
        .change_context(errors::RedisError::RedisConnectionError)?;

        pool.connect();
        pool.wait_for_connect()
            .await
            .change_context(errors::RedisError::RedisConnectionError)?;

        let config = RedisConfig::from(conf);

        Ok(Self {
            pool: Arc::new(pool),
            config: Arc::new(config),
            is_redis_available: Arc::new(atomic::AtomicBool::new(true)),
            subscriber: Arc::new(subscriber),
            publisher: Arc::new(publisher),
            key_prefix: String::default(),
        })
    }
    pub fn clone(&self, key_prefix: &str) -> Self {
        Self {
            pool: Arc::clone(&self.pool),
            key_prefix: key_prefix.to_string(),
            config: Arc::clone(&self.config),
            subscriber: Arc::clone(&self.subscriber),
            publisher: Arc::clone(&self.publisher),
            is_redis_available: Arc::clone(&self.is_redis_available),
        }
    }
    pub async fn on_error(&self, tx: tokio::sync::oneshot::Sender<()>) {
        use futures::StreamExt;
        use tokio_stream::wrappers::BroadcastStream;

        let error_rxs: Vec<BroadcastStream<fred::error::RedisError>> = self
            .pool
            .clients()
            .iter()
            .map(|client| BroadcastStream::new(client.error_rx()))
            .collect();

        let mut error_rx = futures::stream::select_all(error_rxs);
        loop {
            if let Some(Ok(error)) = error_rx.next().await {
                tracing::error!(?error, "Redis protocol or connection error");
                if self.pool.state() == fred::types::ClientState::Disconnected {
                    if tx.send(()).is_err() {
                        tracing::error!("The redis shutdown signal sender failed to signal");
                    }
                    self.is_redis_available
                        .store(false, atomic::Ordering::SeqCst);
                    break;
                }
            }
        }
    }

    pub async fn on_unresponsive(&self) {
        let _ = self.pool.clients().iter().map(|client| {
            client.on_unresponsive(|server| {
                tracing::warn!(redis_server =?server.host, "Redis server is unresponsive");
                Ok(())
            })
        });
    }

    pub fn get_transaction(&self) -> Transaction {
        self.pool.next().multi()
    }
}

pub struct RedisConfig {
    default_ttl: u32,
    default_stream_read_count: u64,
    default_hash_ttl: u32,
    cluster_enabled: bool,
}

impl From<&RedisSettings> for RedisConfig {
    fn from(config: &RedisSettings) -> Self {
        Self {
            default_ttl: config.default_ttl,
            default_stream_read_count: config.stream_read_count,
            default_hash_ttl: config.default_hash_ttl,
            cluster_enabled: config.cluster_enabled,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_redis_error() {
        let x = errors::RedisError::ConsumerGroupClaimFailed.to_string();

        assert_eq!(x, "Failed to set Redis stream message owner".to_string())
    }
}


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

impl ApiEventMetric for for GenerateFingerprintResponsePayload


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

pub fn new(
        payment_method: Option<common_enums::PaymentMethod>,
        payment_method_type: Option<common_enums::PaymentMethodType>,
        authentication_type: Option<common_enums::AuthenticationType>,
        currency: Option<common_enums::Currency>,
        country: Option<common_enums::CountryAlpha2>,
        card_network: Option<String>,
        card_bin: Option<String>,
    ) -> Self


// Struct: ApplePayRegularBillingDetails
// File: crates/diesel_models/src/types.rs
// Module: diesel_models
// Implementations: 0

pub struct ApplePayRegularBillingDetails


// Trait: Vaultable
// File: crates/router/src/core/payment_methods/vault.rs
// Module: router

pub trait Vaultable: Sized


// Function: generate_event_id
// File: crates/router/src/core/webhooks/utils.rs
// Module: router

pub fn generate_event_id() -> String


// Struct: SantanderBoletoPSyncResponse
// File: crates/hyperswitch_connectors/src/connectors/santander/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SantanderBoletoPSyncResponse


// Struct: ApprovedAmount
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApprovedAmount


// Struct: GpaymentsAuthType
// File: crates/hyperswitch_connectors/src/connectors/gpayments/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GpaymentsAuthType


// Function: payment_intents_create
// File: crates/router/src/compatibility/stripe/payment_intents.rs
// Module: router

pub fn payment_intents_create(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
) -> HttpResponse


// Function: dummy_connector_refund_data
// File: crates/router/src/routes/dummy_connector.rs
// Module: router

pub fn dummy_connector_refund_data(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<String>,
) -> impl actix_web::Responder


// Implementation: impl ApiEventMetric for for FrmFulfillmentRequest
// File: crates/hyperswitch_domain_models/src/router_request_types/fraud_check.rs
// Module: hyperswitch_domain_models
// Methods: 1 total (0 public)

impl ApiEventMetric for for FrmFulfillmentRequest


// Function: should_call_frm
// File: crates/router/src/core/fraud_check.rs
// Module: router

pub fn should_call_frm<F, D>(
    merchant_context: &domain::MerchantContext,
    payment_data: &D,
    state: &SessionState,
) -> RouterResult<(
    bool,
    Option<FrmRoutingAlgorithm>,
    Option<common_utils::id_type::ProfileId>,
    Option<FrmConfigsObject>,
)>
where
    F: Send + Clone,
    D: payments::OperationSessionGetters<F> + Send + Sync + Clone,


// Struct: NuveiPaymentResponseData
// File: crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct NuveiPaymentResponseData


// Struct: InespayWebhookEvent
// File: crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct InespayWebhookEvent


// Function: get_url_encoded_string
// File: crates/external_services/src/grpc_client.rs
// Module: external_services

// Documentation: get url encoded string representation of LineageIds

pub fn get_url_encoded_string(self) -> Result<String, serde_urlencoded::ser::Error>


// Trait: RefundFilterAnalytics
// File: crates/analytics/src/refunds/filters.rs
// Module: analytics

pub trait RefundFilterAnalytics: LoadRow<RefundFilterRow>


// Struct: DecryptedWalletDetails
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DecryptedWalletDetails


// Struct: CardVerification
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardVerification


// Struct: CoingateWebhookBody
// File: crates/hyperswitch_connectors/src/connectors/coingate/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CoingateWebhookBody


// File: crates/router_derive/src/macros/try_get_enum.rs
// Module: router_derive
// Public functions: 1
// Public structs: 1

use proc_macro2::Span;
use quote::ToTokens;
use syn::{parse::Parse, punctuated::Punctuated};

mod try_get_keyword {
    use syn::custom_keyword;

    custom_keyword!(error_type);
}

#[derive(Debug)]
pub struct TryGetEnumMeta {
    error_type: syn::Ident,
    variant: syn::Ident,
}

impl Parse for TryGetEnumMeta {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let error_type = input.parse()?;
        _ = input.parse::<syn::Token![::]>()?;
        let variant = input.parse()?;

        Ok(Self {
            error_type,
            variant,
        })
    }
}

trait TryGetDeriveInputExt {
    /// Get all the error metadata associated with an enum.
    fn get_metadata(&self) -> syn::Result<Vec<TryGetEnumMeta>>;
}

impl TryGetDeriveInputExt for syn::DeriveInput {
    fn get_metadata(&self) -> syn::Result<Vec<TryGetEnumMeta>> {
        super::helpers::get_metadata_inner("error", &self.attrs)
    }
}

impl ToTokens for TryGetEnumMeta {
    fn to_tokens(&self, _: &mut proc_macro2::TokenStream) {}
}

/// Try and get the variants for an enum
pub fn try_get_enum_variant(
    input: syn::DeriveInput,
) -> Result<proc_macro2::TokenStream, syn::Error> {
    let name = &input.ident;
    let parsed_error_type = input.get_metadata()?;

    let (error_type, error_variant) = parsed_error_type
        .first()
        .ok_or(syn::Error::new(
            Span::call_site(),
            "One error should be specified",
        ))
        .map(|error_struct| (&error_struct.error_type, &error_struct.variant))?;

    let (impl_generics, generics, where_clause) = input.generics.split_for_impl();

    let variants = get_enum_variants(&input.data)?;

    let try_into_fns = variants.iter().map(|variant| {
        let variant_name = &variant.ident;
        let variant_field = get_enum_variant_field(variant)?;
        let variant_types = variant_field.iter().map(|f|f.ty.clone());

        let try_into_fn = syn::Ident::new(
            &format!("try_into_{}", variant_name.to_string().to_lowercase()),
            Span::call_site(),
        );

        Ok(quote::quote! {
            pub fn #try_into_fn(self)->Result<(#(#variant_types),*),error_stack::Report<#error_type>> {
                match self {
                    Self::#variant_name(inner) => Ok(inner),
                    _=> Err(error_stack::report!(#error_type::#error_variant)),
                }
            }
        })
    }).collect::<Result<Vec<proc_macro2::TokenStream>,syn::Error>>()?;

    let expanded = quote::quote! {
        impl #impl_generics #name #generics #where_clause {
            #(#try_into_fns)*
        }
    };

    Ok(expanded)
}

/// Get variants from Enum
fn get_enum_variants(data: &syn::Data) -> syn::Result<Punctuated<syn::Variant, syn::token::Comma>> {
    if let syn::Data::Enum(syn::DataEnum { variants, .. }) = data {
        Ok(variants.clone())
    } else {
        Err(super::helpers::non_enum_error())
    }
}

/// Get Field from an enum variant
fn get_enum_variant_field(
    variant: &syn::Variant,
) -> syn::Result<Punctuated<syn::Field, syn::token::Comma>> {
    let field = match variant.fields.clone() {
        syn::Fields::Unnamed(un) => un.unnamed,
        syn::Fields::Named(n) => n.named,
        syn::Fields::Unit => {
            return Err(super::helpers::syn_error(
                Span::call_site(),
                "The enum is a unit variant it's not supported",
            ))
        }
    };
    Ok(field)
}


// Struct: CalContractScoreEventRequest
// File: crates/router/src/core/payments/routing/utils.rs
// Module: router
// Implementations: 0

pub struct CalContractScoreEventRequest


// Module Structure
// File: crates/router/src/types/api/routing.rs
// Module: router

// Public exports:
pub use api_models::{
    enums as api_enums,
    routing::{
        ConnectorVolumeSplit, RoutableChoiceKind, RoutableConnectorChoice, RoutingAlgorithmKind,
        RoutingAlgorithmRef, RoutingConfigRequest, RoutingDictionary, RoutingDictionaryRecord,
        StaticRoutingAlgorithm, StraightThroughAlgorithm,
    },
};


// Function: initiate_payout_link
// File: crates/router/src/core/payout_link.rs
// Module: router

pub fn initiate_payout_link(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: payouts::PayoutLinkInitiateRequest,
    request_headers: &header::HeaderMap,
) -> RouterResponse<services::GenericLinkFormData>


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

// Public submodules:
pub mod transformers;


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

pub fn generic_find_by_id<T, Pk, R>(conn: &PgPooledConn, id: Pk) -> StorageResult<R>
where
    T: FindDsl<Pk> + HasTable<Table = T> + LimitDsl + Table + 'static,
    Find<T, Pk>: LimitDsl + QueryFragment<Pg> + RunQueryDsl<PgConnection> + Send + 'static,
    Limit<Find<T, Pk>>: LoadQuery<'static, PgConnection, R>,
    Pk: Clone + Debug,
    R: Send + 'static,


// Function: list_multiple_key_stores
// File: crates/diesel_models/src/query/merchant_key_store.rs
// Module: diesel_models

pub fn list_multiple_key_stores(
        conn: &PgPooledConn,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> StorageResult<Vec<Self>>


// Struct: StripePaymentMethod
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router
// Implementations: 0

pub struct StripePaymentMethod


// Function: create_customer
// File: crates/router/src/core/customers.rs
// Module: router

pub fn create_customer(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    customer_data: customers::CustomerRequest,
    connector_customer_details: Option<Vec<payment_methods_domain::ConnectorCustomerDetails>>,
) -> errors::CustomerResponse<customers::CustomerResponse>


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

pub struct NuveiAmountDetails


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

pub struct CancelTransactionData


// Implementation: impl api::MandateSetup for for Dwolla
// File: crates/hyperswitch_connectors/src/connectors/dwolla.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::MandateSetup for for Dwolla


// Struct: AdyenplatformIncomingWebhookData
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AdyenplatformIncomingWebhookData


// Implementation: impl FieldExt for for Field
// File: crates/router_derive/src/macros/schema/helpers.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl FieldExt for for Field


// File: crates/scheduler/src/env.rs
// Module: scheduler

#[doc(inline)]
pub use router_env::*;


// Struct: OpensearchSuccess
// File: crates/api_models/src/analytics/search.rs
// Module: api_models
// Implementations: 0

pub struct OpensearchSuccess


// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors
// Public functions: 4
// Public structs: 19

use common_enums::{enums, Currency};
use common_utils::{id_type::CustomerId, pii::Email, types::MinorUnit};
use hyperswitch_domain_models::{
    address::Address as DomainAddress,
    payment_method_data::PaymentMethodData,
    router_data::{
        AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
        RouterData,
    },
    router_flow_types::{
        payments::Capture,
        refunds::{Execute, RSync},
    },
    router_request_types::{PaymentsCaptureData, ResponseId},
    router_response_types::{MandateReference, PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    consts,
    errors::{self},
};
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{
        get_unimplemented_payment_method_error_message, AddressDetailsData,
        PaymentsAuthorizeRequestData, RefundsRequestData, RouterData as _,
    },
};

//TODO: Fill the struct with respective fields
pub struct CeleroRouterData<T> {
    pub amount: MinorUnit, // CeleroCommerce expects integer cents
    pub router_data: T,
}

impl<T> TryFrom<(MinorUnit, T)> for CeleroRouterData<T> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((amount, item): (MinorUnit, T)) -> Result<Self, Self::Error> {
        Ok(Self {
            amount,
            router_data: item,
        })
    }
}
// CeleroCommerce Search Request for sync operations - POST /api/transaction/search
#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroSearchRequest {
    transaction_id: String,
}

impl TryFrom<&PaymentsSyncRouterData> for CeleroSearchRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsSyncRouterData) -> Result<Self, Self::Error> {
        let transaction_id = match &item.request.connector_transaction_id {
            ResponseId::ConnectorTransactionId(id) => id.clone(),
            _ => {
                return Err(errors::ConnectorError::MissingConnectorTransactionID.into());
            }
        };
        Ok(Self { transaction_id })
    }
}

impl TryFrom<&RefundSyncRouterData> for CeleroSearchRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &RefundSyncRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            transaction_id: item.request.get_connector_refund_id()?,
        })
    }
}

// CeleroCommerce Payment Request according to API specs
#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroPaymentsRequest {
    idempotency_key: String,
    #[serde(rename = "type")]
    transaction_type: TransactionType,
    amount: MinorUnit, // CeleroCommerce expects integer cents
    currency: Currency,
    payment_method: CeleroPaymentMethod,
    #[serde(skip_serializing_if = "Option::is_none")]
    billing_address: Option<CeleroAddress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    shipping_address: Option<CeleroAddress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    create_vault_record: Option<bool>,
    // CIT/MIT fields
    #[serde(skip_serializing_if = "Option::is_none")]
    card_on_file_indicator: Option<CardOnFileIndicator>,
    #[serde(skip_serializing_if = "Option::is_none")]
    initiated_by: Option<InitiatedBy>,
    #[serde(skip_serializing_if = "Option::is_none")]
    initial_transaction_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    stored_credential_indicator: Option<StoredCredentialIndicator>,
    #[serde(skip_serializing_if = "Option::is_none")]
    billing_method: Option<BillingMethod>,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroAddress {
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    address_line_1: Option<Secret<String>>,
    address_line_2: Option<Secret<String>>,
    city: Option<String>,
    state: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    country: Option<common_enums::CountryAlpha2>,
    phone: Option<Secret<String>>,
    email: Option<Email>,
}

impl TryFrom<&DomainAddress> for CeleroAddress {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(address: &DomainAddress) -> Result<Self, Self::Error> {
        let address_details = address.address.as_ref();
        match address_details {
            Some(address_details) => Ok(Self {
                first_name: address_details.get_optional_first_name(),
                last_name: address_details.get_optional_last_name(),
                address_line_1: address_details.get_optional_line1(),
                address_line_2: address_details.get_optional_line2(),
                city: address_details.get_optional_city(),
                state: address_details.get_optional_state(),
                postal_code: address_details.get_optional_zip(),
                country: address_details.get_optional_country(),
                phone: address
                    .phone
                    .as_ref()
                    .and_then(|phone| phone.number.clone()),
                email: address.email.clone(),
            }),
            None => Err(errors::ConnectorError::MissingRequiredField {
                field_name: "address_details",
            }
            .into()),
        }
    }
}

#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CeleroPaymentMethod {
    Card(CeleroCard),
    Customer(CeleroCustomer),
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroCustomer {
    id: Option<CustomerId>,
    payment_method_id: Option<String>,
}
#[derive(Debug, Serialize, PartialEq, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum CeleroEntryType {
    Keyed,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct CeleroCard {
    entry_type: CeleroEntryType,
    number: cards::CardNumber,
    expiration_date: Secret<String>,
    cvc: Secret<String>,
}

impl TryFrom<&PaymentMethodData> for CeleroPaymentMethod {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentMethodData) -> Result<Self, Self::Error> {
        match item {
            PaymentMethodData::Card(req_card) => {
                let card = CeleroCard {
                    entry_type: CeleroEntryType::Keyed,
                    number: req_card.card_number.clone(),
                    expiration_date: Secret::new(format!(
                        "{}/{}",
                        req_card.card_exp_month.peek(),
                        req_card.card_exp_year.peek()
                    )),
                    cvc: req_card.card_cvc.clone(),
                };
                Ok(Self::Card(card))
            }
            PaymentMethodData::CardDetailsForNetworkTransactionId(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::MobilePayment(_) => Err(errors::ConnectorError::NotImplemented(
                "Selected payment method through celero".to_string(),
            )
            .into()),
        }
    }
}

// Implementation for handling 3DS specifically
impl TryFrom<(&PaymentMethodData, bool)> for CeleroPaymentMethod {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((item, is_three_ds): (&PaymentMethodData, bool)) -> Result<Self, Self::Error> {
        // If 3DS is requested, return an error
        if is_three_ds {
            return Err(errors::ConnectorError::NotSupported {
                message: "Cards 3DS".to_string(),
                connector: "celero",
            }
            .into());
        }

        // Otherwise, delegate to the standard implementation
        Self::try_from(item)
    }
}

impl TryFrom<&CeleroRouterData<&PaymentsAuthorizeRouterData>> for CeleroPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CeleroRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let is_auto_capture = item.router_data.request.is_auto_capture()?;
        let transaction_type = if is_auto_capture {
            TransactionType::Sale
        } else {
            TransactionType::Authorize
        };

        let billing_address: Option<CeleroAddress> = item
            .router_data
            .get_optional_billing()
            .and_then(|address| address.try_into().ok());

        let shipping_address: Option<CeleroAddress> = item
            .router_data
            .get_optional_shipping()
            .and_then(|address| address.try_into().ok());

        // Determine CIT/MIT fields based on mandate data
        let (mandate_fields, payment_method) = determine_cit_mit_fields(item.router_data)?;

        let request = Self {
            idempotency_key: item.router_data.connector_request_reference_id.clone(),
            transaction_type,
            amount: item.amount,
            currency: item.router_data.request.currency,
            payment_method,
            billing_address,
            shipping_address,
            create_vault_record: Some(false),
            card_on_file_indicator: mandate_fields.card_on_file_indicator,
            initiated_by: mandate_fields.initiated_by,
            initial_transaction_id: mandate_fields.initial_transaction_id,
            stored_credential_indicator: mandate_fields.stored_credential_indicator,
            billing_method: mandate_fields.billing_method,
        };

        Ok(request)
    }
}

// Define a struct to hold CIT/MIT fields to avoid complex tuple return type
#[derive(Debug, Default)]
pub struct CeleroMandateFields {
    pub card_on_file_indicator: Option<CardOnFileIndicator>,
    pub initiated_by: Option<InitiatedBy>,
    pub initial_transaction_id: Option<String>,
    pub stored_credential_indicator: Option<StoredCredentialIndicator>,
    pub billing_method: Option<BillingMethod>,
}

// Helper function to determine CIT/MIT fields based on mandate data
fn determine_cit_mit_fields(
    router_data: &PaymentsAuthorizeRouterData,
) -> Result<(CeleroMandateFields, CeleroPaymentMethod), error_stack::Report<errors::ConnectorError>>
{
    // Default null values
    let mut mandate_fields = CeleroMandateFields::default();

    // First check if there's a mandate_id in the request
    match router_data
        .request
        .mandate_id
        .clone()
        .and_then(|mandate_ids| mandate_ids.mandate_reference_id)
    {
        // If there's a connector mandate ID, this is a MIT (Merchant Initiated Transaction)
        Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
            connector_mandate_id,
        )) => {
            mandate_fields.card_on_file_indicator = Some(CardOnFileIndicator::RecurringPayment);
            mandate_fields.initiated_by = Some(InitiatedBy::Merchant); // This is a MIT
            mandate_fields.stored_credential_indicator = Some(StoredCredentialIndicator::Used);
            mandate_fields.billing_method = Some(BillingMethod::Recurring);
            mandate_fields.initial_transaction_id =
                connector_mandate_id.get_connector_mandate_request_reference_id();
            Ok((
                mandate_fields,
                CeleroPaymentMethod::Customer(CeleroCustomer {
                    id: Some(router_data.get_customer_id()?),
                    payment_method_id: connector_mandate_id.get_payment_method_id(),
                }),
            ))
        }
        // For other mandate types that might not be supported
        Some(api_models::payments::MandateReferenceId::NetworkMandateId(_))
        | Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(_)) => {
            // These might need different handling or return an error
            Err(errors::ConnectorError::NotImplemented(
                get_unimplemented_payment_method_error_message("Celero"),
            )
            .into())
        }
        // If no mandate ID is present, check if it's a mandate payment
        None => {
            if router_data.request.is_mandate_payment() {
                // This is a customer-initiated transaction for a recurring payment
                mandate_fields.initiated_by = Some(InitiatedBy::Customer);
                mandate_fields.card_on_file_indicator = Some(CardOnFileIndicator::RecurringPayment);
                mandate_fields.billing_method = Some(BillingMethod::Recurring);
                mandate_fields.stored_credential_indicator = Some(StoredCredentialIndicator::Used);
            }
            let is_three_ds = router_data.is_three_ds();
            Ok((
                mandate_fields,
                CeleroPaymentMethod::try_from((
                    &router_data.request.payment_method_data,
                    is_three_ds,
                ))?,
            ))
        }
    }
}

// Auth Struct for CeleroCommerce API key authentication
pub struct CeleroAuthType {
    pub(super) api_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for CeleroAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                api_key: api_key.clone(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// CeleroCommerce API Response Structures
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CeleroResponseStatus {
    #[serde(alias = "success", alias = "Success", alias = "SUCCESS")]
    Success,
    #[serde(alias = "error", alias = "Error", alias = "ERROR")]
    Error,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum CeleroTransactionStatus {
    Approved,
    Declined,
    Error,
    Pending,
    PendingSettlement,
    Settled,
    Voided,
    Reversed,
}

impl From<CeleroTransactionStatus> for common_enums::AttemptStatus {
    fn from(item: CeleroTransactionStatus) -> Self {
        match item {
            CeleroTransactionStatus::Approved => Self::Authorized,
            CeleroTransactionStatus::Settled => Self::Charged,
            CeleroTransactionStatus::Declined | CeleroTransactionStatus::Error => Self::Failure,
            CeleroTransactionStatus::Pending | CeleroTransactionStatus::PendingSettlement => {
                Self::Pending
            }
            CeleroTransactionStatus::Voided | CeleroTransactionStatus::Reversed => Self::Voided,
        }
    }
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroCardResponse {
    pub status: CeleroTransactionStatus,
    pub auth_code: Option<String>,
    pub processor_response_code: Option<String>,
    pub avs_response_code: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CeleroPaymentMethodResponse {
    Card(CeleroCardResponse),
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TransactionType {
    Sale,
    Authorize,
}

// CIT/MIT related enums
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CardOnFileIndicator {
    #[serde(rename = "C")]
    GeneralPurposeStorage,
    #[serde(rename = "R")]
    RecurringPayment,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum InitiatedBy {
    Customer,
    Merchant,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StoredCredentialIndicator {
    Used,
    Stored,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum BillingMethod {
    Straight,
    #[serde(rename = "initial_recurring")]
    InitialRecurring,
    Recurring,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde_with::skip_serializing_none]
pub struct CeleroTransactionResponseData {
    pub id: String,
    #[serde(rename = "type")]
    pub transaction_type: TransactionType,
    pub amount: i64,
    pub currency: String,
    pub response: CeleroPaymentMethodResponse,
    pub billing_address: Option<CeleroAddressResponse>,
    pub shipping_address: Option<CeleroAddressResponse>,
    // Additional fields from the sample response
    pub status: Option<String>,
    pub response_code: Option<i32>,
    pub customer_id: Option<String>,
    pub payment_method_id: Option<String>,
}

impl CeleroTransactionResponseData {
    pub fn get_mandate_reference(&self) -> Box<Option<MandateReference>> {
        if self.payment_method_id.is_some() {
            Box::new(Some(MandateReference {
                connector_mandate_id: None,
                payment_method_id: self.payment_method_id.clone(),
                mandate_metadata: None,
                connector_mandate_request_reference_id: Some(self.id.clone()),
            }))
        } else {
            Box::new(None)
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct CeleroAddressResponse {
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    address_line_1: Option<Secret<String>>,
    address_line_2: Option<Secret<String>>,
    city: Option<String>,
    state: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    country: Option<common_enums::CountryAlpha2>,
    phone: Option<Secret<String>>,
    email: Option<Secret<String>>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct CeleroPaymentsResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<CeleroTransactionResponseData>,
}

impl<F, T> TryFrom<ResponseRouterData<F, CeleroPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, CeleroPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => {
                if let Some(data) = item.response.data {
                    let CeleroPaymentMethodResponse::Card(response) = &data.response;
                    // Check if transaction itself failed despite successful API call
                    match response.status {
                        CeleroTransactionStatus::Declined | CeleroTransactionStatus::Error => {
                            // Transaction failed - create error response with transaction details
                            let error_details = CeleroErrorDetails::from_transaction_response(
                                response,
                                item.response.msg,
                            );

                            Ok(Self {
                                status: common_enums::AttemptStatus::Failure,
                                response: Err(
                                    hyperswitch_domain_models::router_data::ErrorResponse {
                                        code: error_details
                                            .error_code
                                            .unwrap_or_else(|| "TRANSACTION_FAILED".to_string()),
                                        message: error_details.error_message,
                                        reason: error_details.decline_reason,
                                        status_code: item.http_code,
                                        attempt_status: None,
                                        connector_transaction_id: Some(data.id),
                                        network_decline_code: None,
                                        network_advice_code: None,
                                        network_error_message: None,
                                        connector_metadata: None,
                                    },
                                ),
                                ..item.data
                            })
                        }
                        _ => {
                            let connector_response_data =
                                convert_to_additional_payment_method_connector_response(
                                    response.avs_response_code.clone(),
                                )
                                .map(ConnectorResponseData::with_additional_payment_method_data);
                            let final_status: enums::AttemptStatus = response.status.into();
                            Ok(Self {
                                status: final_status,
                                response: Ok(PaymentsResponseData::TransactionResponse {
                                    resource_id: ResponseId::ConnectorTransactionId(
                                        data.id.clone(),
                                    ),
                                    redirection_data: Box::new(None),
                                    mandate_reference: data.get_mandate_reference(),
                                    connector_metadata: None,
                                    network_txn_id: None,
                                    connector_response_reference_id: response.auth_code.clone(),
                                    incremental_authorization_allowed: None,
                                    charges: None,
                                }),
                                connector_response: connector_response_data,
                                ..item.data
                            })
                        }
                    }
                } else {
                    // No transaction data in successful response
                    // We don't have a transaction ID in this case
                    Ok(Self {
                        status: common_enums::AttemptStatus::Failure,
                        response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                            code: "MISSING_DATA".to_string(),
                            message: "No transaction data in response".to_string(),
                            reason: Some(item.response.msg),
                            status_code: item.http_code,
                            attempt_status: None,
                            connector_transaction_id: None,
                            network_decline_code: None,
                            network_advice_code: None,
                            network_error_message: None,
                            connector_metadata: None,
                        }),
                        ..item.data
                    })
                }
            }
            CeleroResponseStatus::Error => {
                // Top-level API error
                let error_details =
                    CeleroErrorDetails::from_top_level_error(item.response.msg.clone());

                // Extract transaction ID from the top-level data if available
                let connector_transaction_id =
                    item.response.data.as_ref().map(|data| data.id.clone());

                Ok(Self {
                    status: common_enums::AttemptStatus::Failure,
                    response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                        code: error_details
                            .error_code
                            .unwrap_or_else(|| "API_ERROR".to_string()),
                        message: error_details.error_message,
                        reason: error_details.decline_reason,
                        status_code: item.http_code,
                        attempt_status: None,
                        connector_transaction_id,
                        network_decline_code: None,
                        network_advice_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    }),
                    ..item.data
                })
            }
        }
    }
}

// CAPTURE:
// Type definition for CaptureRequest
#[derive(Default, Debug, Serialize)]
pub struct CeleroCaptureRequest {
    pub amount: MinorUnit,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub order_id: Option<String>,
}

impl TryFrom<&CeleroRouterData<&PaymentsCaptureRouterData>> for CeleroCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &CeleroRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            order_id: Some(item.router_data.payment_id.clone()),
        })
    }
}

// CeleroCommerce Capture Response
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroCaptureResponse {
    pub status: CeleroResponseStatus,
    pub msg: Option<String>,
    pub data: Option<serde_json::Value>, // Usually null for capture responses
}

impl
    TryFrom<
        ResponseRouterData<
            Capture,
            CeleroCaptureResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    > for RouterData<Capture, PaymentsCaptureData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            Capture,
            CeleroCaptureResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                status: common_enums::AttemptStatus::Charged,
                response: Ok(PaymentsResponseData::TransactionResponse {
                    resource_id: ResponseId::ConnectorTransactionId(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    redirection_data: Box::new(None),
                    mandate_reference: Box::new(None),
                    connector_metadata: None,
                    network_txn_id: None,
                    connector_response_reference_id: None,
                    incremental_authorization_allowed: None,
                    charges: None,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                status: common_enums::AttemptStatus::Failure,
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "CAPTURE_FAILED".to_string(),
                    message: item
                        .response
                        .msg
                        .clone()
                        .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
                    reason: None,
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

// CeleroCommerce Void Response - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroVoidResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<serde_json::Value>, // Usually null for void responses
}

impl
    TryFrom<
        ResponseRouterData<
            hyperswitch_domain_models::router_flow_types::payments::Void,
            CeleroVoidResponse,
            hyperswitch_domain_models::router_request_types::PaymentsCancelData,
            PaymentsResponseData,
        >,
    >
    for RouterData<
        hyperswitch_domain_models::router_flow_types::payments::Void,
        hyperswitch_domain_models::router_request_types::PaymentsCancelData,
        PaymentsResponseData,
    >
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            hyperswitch_domain_models::router_flow_types::payments::Void,
            CeleroVoidResponse,
            hyperswitch_domain_models::router_request_types::PaymentsCancelData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                status: common_enums::AttemptStatus::Voided,
                response: Ok(PaymentsResponseData::TransactionResponse {
                    resource_id: ResponseId::ConnectorTransactionId(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    redirection_data: Box::new(None),
                    mandate_reference: Box::new(None),
                    connector_metadata: None,
                    network_txn_id: None,
                    connector_response_reference_id: None,
                    incremental_authorization_allowed: None,
                    charges: None,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                status: common_enums::AttemptStatus::Failure,
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "VOID_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}
#[derive(Default, Debug, Serialize)]
pub struct CeleroRefundRequest {
    pub amount: MinorUnit,
    pub surcharge: MinorUnit, // Required field as per API specification
}

impl<F> TryFrom<&CeleroRouterData<&RefundsRouterData<F>>> for CeleroRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &CeleroRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            surcharge: MinorUnit::zero(), // Default to 0 as per API specification
        })
    }
}

// CeleroCommerce Refund Response - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroRefundResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    pub data: Option<serde_json::Value>, // Usually null for refund responses
}

impl TryFrom<RefundsResponseRouterData<Execute, CeleroRefundResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, CeleroRefundResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                response: Ok(RefundsResponseData {
                    connector_refund_id: item.data.request.refund_id.clone(),
                    refund_status: enums::RefundStatus::Success,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "REFUND_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, CeleroRefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, CeleroRefundResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response.status {
            CeleroResponseStatus::Success => Ok(Self {
                response: Ok(RefundsResponseData {
                    connector_refund_id: item.data.request.refund_id.clone(),
                    refund_status: enums::RefundStatus::Success,
                }),
                ..item.data
            }),
            CeleroResponseStatus::Error => Ok(Self {
                response: Err(hyperswitch_domain_models::router_data::ErrorResponse {
                    code: "REFUND_SYNC_FAILED".to_string(),
                    message: item.response.msg.clone(),
                    reason: Some(item.response.msg),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: Some(
                        item.data.request.connector_transaction_id.clone(),
                    ),
                    network_decline_code: None,
                    network_advice_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ..item.data
            }),
        }
    }
}

// CeleroCommerce Error Response Structures

// Main error response structure - matches API spec format
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroErrorResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<serde_json::Value>,
}

// Error details that can be extracted from various response fields
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CeleroErrorDetails {
    pub error_code: Option<String>,
    pub error_message: String,
    pub processor_response_code: Option<String>,
    pub decline_reason: Option<String>,
}

impl From<CeleroErrorResponse> for CeleroErrorDetails {
    fn from(error_response: CeleroErrorResponse) -> Self {
        Self {
            error_code: Some("API_ERROR".to_string()),
            error_message: error_response.msg,
            processor_response_code: None,
            decline_reason: None,
        }
    }
}

// Function to extract error details from transaction response data
impl CeleroErrorDetails {
    pub fn from_transaction_response(response: &CeleroCardResponse, msg: String) -> Self {
        // Map specific error codes based on common response patterns
        let decline_reason = Self::map_processor_error(&response.processor_response_code, &msg);

        Self {
            error_code: None,
            error_message: msg,
            processor_response_code: response.processor_response_code.clone(),
            decline_reason,
        }
    }

    pub fn from_top_level_error(msg: String) -> Self {
        // Map specific error codes from top-level API errors

        Self {
            error_code: None,
            error_message: msg,
            processor_response_code: None,
            decline_reason: None,
        }
    }

    /// Map processor response codes and messages to specific Hyperswitch error codes
    fn map_processor_error(processor_code: &Option<String>, message: &str) -> Option<String> {
        let message_lower = message.to_lowercase();
        // Check processor response codes if available
        if let Some(code) = processor_code {
            match code.as_str() {
                "05" => Some("TRANSACTION_DECLINED".to_string()),
                "14" => Some("INVALID_CARD_DATA".to_string()),
                "51" => Some("INSUFFICIENT_FUNDS".to_string()),
                "54" => Some("EXPIRED_CARD".to_string()),
                "55" => Some("INCORRECT_CVC".to_string()),
                "61" => Some("Exceeds withdrawal amount limit".to_string()),
                "62" => Some("TRANSACTION_DECLINED".to_string()),
                "65" => Some("Exceeds withdrawal frequency limit".to_string()),
                "78" => Some("INVALID_CARD_DATA".to_string()),
                "91" => Some("PROCESSING_ERROR".to_string()),
                "96" => Some("PROCESSING_ERROR".to_string()),
                _ => {
                    router_env::logger::info!(
                        "Celero response error code ({:?}) is not mapped to any error state ",
                        code
                    );
                    Some("Transaction failed".to_string())
                }
            }
        } else {
            Some(message_lower)
        }
    }
}

pub fn get_avs_definition(code: &str) -> Option<&'static str> {
    match code {
        "0" => Some("AVS Not Available"),
        "A" => Some("Address match only"),
        "B" => Some("Address matches, ZIP not verified"),
        "C" => Some("Incompatible format"),
        "D" => Some("Exact match"),
        "F" => Some("Exact match, UK-issued cards"),
        "G" => Some("Non-U.S. Issuer does not participate"),
        "I" => Some("Not verified"),
        "M" => Some("Exact match"),
        "N" => Some("No address or ZIP match"),
        "P" => Some("Postal Code match"),
        "R" => Some("Issuer system unavailable"),
        "S" => Some("Service not supported"),
        "U" => Some("Address unavailable"),
        "W" => Some("9-character numeric ZIP match only"),
        "X" => Some("Exact match, 9-character numeric ZIP"),
        "Y" => Some("Exact match, 5-character numeric ZIP"),
        "Z" => Some("5-character ZIP match only"),
        "L" => Some("Partial match, Name and billing postal code match"),
        "1" => Some("Cardholder name and ZIP match"),
        "2" => Some("Cardholder name, address and ZIP match"),
        "3" => Some("Cardholder name and address match"),
        "4" => Some("Cardholder name matches"),
        "5" => Some("Cardholder name incorrect, ZIP matches"),
        "6" => Some("Cardholder name incorrect, address and zip match"),
        "7" => Some("Cardholder name incorrect, address matches"),
        "8" => Some("Cardholder name, address, and ZIP do not match"),
        _ => {
            router_env::logger::info!(
                "Celero avs response code ({:?}) is not mapped to any definition.",
                code
            );

            None
        } // No definition found for the given code
    }
}
fn convert_to_additional_payment_method_connector_response(
    response_code: Option<String>,
) -> Option<AdditionalPaymentMethodConnectorResponse> {
    match response_code {
        None => None,
        Some(code) => {
            let description = get_avs_definition(&code);
            let payment_checks = serde_json::json!({
                "avs_result_code": code,
                "description": description
            });
            Some(AdditionalPaymentMethodConnectorResponse::Card {
                authentication_data: None,
                payment_checks: Some(payment_checks),
                card_network: None,
                domestic_network: None,
            })
        }
    }
}


// Struct: EbanxBankDetails
// File: crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EbanxBankDetails


// Struct: CreateRoleV2Request
// File: crates/api_models/src/user_role/role.rs
// Module: api_models
// Implementations: 0

pub struct CreateRoleV2Request


// Function: find_by_merchant_reference_id_merchant_id
// File: crates/diesel_models/src/query/customers.rs
// Module: diesel_models

pub fn find_by_merchant_reference_id_merchant_id(
        conn: &PgPooledConn,
        merchant_reference_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
    ) -> StorageResult<Self>


// Module Structure
// File: crates/router/src/services/api/client.rs
// Module: router

// Public exports:
pub use external_services::http_client::{self, client};


// Struct: WebhookProcessingResult
// File: crates/router/src/core/webhooks/incoming.rs
// Module: router
// Implementations: 0

// Documentation: Result type for webhook processing path determination

pub struct WebhookProcessingResult


// Struct: ConnectorMandateDetails
// File: crates/hyperswitch_domain_models/src/router_flow_types/webhooks.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct ConnectorMandateDetails


// Function: build_cloned_connector_create_request
// File: crates/router/src/utils/user.rs
// Module: router

pub fn build_cloned_connector_create_request(
    source_mca: DomainMerchantConnectorAccount,
    destination_profile_id: Option<id_type::ProfileId>,
    destination_connector_label: Option<String>,
) -> UserResult<admin_api::MerchantConnectorCreate>


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

impl ConnectorCommon for for Tokenio


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

pub fn server(state: AppState) -> Scope


// Implementation: impl super::disputes::metrics::DisputeMetricAnalytics for for ClickhouseClient
// File: crates/analytics/src/clickhouse.rs
// Module: analytics
// Methods: 0 total (0 public)

impl super::disputes::metrics::DisputeMetricAnalytics for for ClickhouseClient


// Function: add_default_headers
// File: crates/common_utils/src/request.rs
// Module: common_utils

pub fn add_default_headers(&mut self)


// Struct: OpenSearchIndexes
// File: crates/analytics/src/opensearch.rs
// Module: analytics
// Implementations: 1

pub struct OpenSearchIndexes


// Struct: StripebillingPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct StripebillingPaymentsRequest


// Function: do_auth_connector_call
// File: crates/router/src/core/authentication/utils.rs
// Module: router

pub fn do_auth_connector_call<F, Req, Res>(
    state: &SessionState,
    authentication_connector_name: String,
    router_data: RouterData<F, Req, Res>,
) -> RouterResult<RouterData<F, Req, Res>>
where
    Req: std::fmt::Debug + Clone + 'static,
    Res: std::fmt::Debug + Clone + 'static,
    F: std::fmt::Debug + Clone + 'static,
    dyn api::Connector + Sync: services::api::ConnectorIntegration<F, Req, Res>,
    dyn api::ConnectorV2 + Sync:
        services::api::ConnectorIntegrationV2<F, ExternalAuthenticationFlowData, Req, Res>,


// Struct: RuleMigrationQuery
// File: crates/api_models/src/routing.rs
// Module: api_models
// Implementations: 1

pub struct RuleMigrationQuery


// Implementation: impl Profile
// File: crates/hyperswitch_domain_models/src/business_profile.rs
// Module: hyperswitch_domain_models
// Methods: 14 total (14 public)

impl Profile


// File: crates/analytics/src/api_event/filters.rs
// Module: analytics
// Public functions: 1
// Public structs: 1

use api_models::analytics::{api_event::ApiEventDimensions, Granularity, TimeRange};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use crate::{
    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, FiltersError, FiltersResult, LoadRow},
};

pub trait ApiEventFilterAnalytics: LoadRow<ApiEventFilter> {}

pub async fn get_api_event_filter_for_dimension<T>(
    dimension: ApiEventDimensions,
    merchant_id: &common_utils::id_type::MerchantId,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<ApiEventFilter>>
where
    T: AnalyticsDataSource + ApiEventFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::ApiEvents);

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

    query_builder
        .add_filter_clause("merchant_id", merchant_id)
        .switch()?;

    query_builder.set_distinct();

    query_builder
        .execute_query::<ApiEventFilter, _>(pool)
        .await
        .change_context(FiltersError::QueryBuildingError)?
        .change_context(FiltersError::QueryExecutionFailure)
}

#[derive(Debug, serde::Serialize, Eq, PartialEq, serde::Deserialize)]
pub struct ApiEventFilter {
    pub status_code: Option<i32>,
    pub flow_type: Option<String>,
    pub api_flow: Option<String>,
}


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

pub fn delete_locker_payment_method_by_lookup_key(
        state: &routes::SessionState,
        lookup_key: &Option<String>,
    )


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

pub struct AciMandateResponse


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

impl api::PaymentToken for for Bitpay


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

pub struct VoidResponse


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

impl api::PaymentSync for for Payu


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

impl api::PaymentToken for for Fiserv


// Function: list_customer_payment_method_api
// File: crates/openapi/src/routes/payment_method.rs
// Module: openapi

pub fn list_customer_payment_method_api()


// Function: merchant_account_list
// File: crates/openapi/src/routes/organization.rs
// Module: openapi

pub fn merchant_account_list()


// Function: validate_create_request
// File: crates/router/src/core/payouts/validator.rs
// Module: router

pub fn validate_create_request(
    _state: &SessionState,
    _merchant_context: &domain::MerchantContext,
    _req: &payouts::PayoutCreateRequest,
) -> RouterResult<(
    String,
    Option<payouts::PayoutMethodData>,
    String,
    Option<domain::Customer>,
    Option<PaymentMethod>,
)>


// Implementation: impl auth_service::AuthServiceBankAccountCredentials for for Plaid
// File: crates/pm_auth/src/connector/plaid.rs
// Module: pm_auth
// Methods: 0 total (0 public)

impl auth_service::AuthServiceBankAccountCredentials for for Plaid


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

impl ConnectorCommon for for Tesouro


// Implementation: impl EmailData for for MagicLink
// File: crates/router/src/services/email/types.rs
// Module: router
// Methods: 1 total (0 public)

impl EmailData for for MagicLink


// Function: client_secret_delete
// File: crates/router/src/routes/ephemeral_key.rs
// Module: router

pub fn client_secret_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse


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

pub struct CaptureResponseData


// Struct: NordeaPaymentsInitiateResponseData
// File: crates/hyperswitch_connectors/src/connectors/nordea/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NordeaPaymentsInitiateResponseData


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

pub struct AciNetworkTokenData


// Function: create_profile_acquirer
// File: crates/router/src/routes/profile_acquirer.rs
// Module: router

pub fn create_profile_acquirer(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<ProfileAcquirerCreate>,
) -> HttpResponse


// Struct: PaymentCaptureData
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentCaptureData<F>


// File: crates/external_services/src/no_encryption/core.rs
// Module: external_services
// Public functions: 2
// Public structs: 1

//! No encryption core functionalities

/// No encryption type
#[derive(Debug, Clone)]
pub struct NoEncryption;

impl NoEncryption {
    /// Encryption functionality
    pub fn encrypt(&self, data: impl AsRef<[u8]>) -> Vec<u8> {
        data.as_ref().into()
    }

    /// Decryption functionality
    pub fn decrypt(&self, data: impl AsRef<[u8]>) -> Vec<u8> {
        data.as_ref().into()
    }
}


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

pub struct PaymentsApproveData


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

// Documentation: For backwards compatibility, whenever new business labels are passed in primary_business_details, create a profile

pub fn create_profile_from_business_labels(
    state: &SessionState,
    db: &dyn StorageInterface,
    key_store: &domain::MerchantKeyStore,
    merchant_id: &id_type::MerchantId,
    new_business_details: Vec<admin_types::PrimaryBusinessDetails>,
) -> RouterResult<()>


// Function: get_profile_payment_filters
// File: crates/router/src/analytics.rs
// Module: router

pub fn get_profile_payment_filters(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<GetPaymentFiltersRequest>,
    ) -> impl Responder


// File: crates/router/src/core/payments/operations/tax_calculation.rs
// Module: router
// Public structs: 1

use std::marker::PhantomData;

use api_models::enums::FrmSuggestion;
use async_trait::async_trait;
use common_utils::{ext_traits::AsyncExt, types::keymanager::KeyManagerState};
use error_stack::ResultExt;
use masking::PeekInterface;
use router_derive::PaymentOperation;
use router_env::{instrument, tracing};

use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, RouterResult, StorageErrorExt},
        payment_methods::cards::create_encrypted_data,
        payments::{self, helpers, operations, PaymentData, PaymentMethodChecker},
        utils as core_utils,
    },
    db::errors::ConnectorErrorExt,
    routes::{app::ReqState, SessionState},
    services,
    types::{
        self,
        api::{self, ConnectorCallType, PaymentIdTypeExt},
        domain,
        storage::{self, enums as storage_enums},
    },
    utils::OptionExt,
};

#[derive(Debug, Clone, Copy, PaymentOperation)]
#[operation(operations = "all", flow = "sdk_session_update")]
pub struct PaymentSessionUpdate;

type PaymentSessionUpdateOperation<'b, F> =
    BoxedOperation<'b, F, api::PaymentsDynamicTaxCalculationRequest, PaymentData<F>>;

#[async_trait]
impl<F: Send + Clone + Sync>
    GetTracker<F, PaymentData<F>, api::PaymentsDynamicTaxCalculationRequest>
    for PaymentSessionUpdate
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        payment_id: &api::PaymentIdType,
        request: &api::PaymentsDynamicTaxCalculationRequest,
        merchant_context: &domain::MerchantContext,
        _auth_flow: services::AuthFlow,
        _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<
        operations::GetTrackerResponse<
            'a,
            F,
            api::PaymentsDynamicTaxCalculationRequest,
            PaymentData<F>,
        >,
    > {
        let payment_id = payment_id
            .get_payment_intent_id()
            .change_context(errors::ApiErrorResponse::PaymentNotFound)?;

        let db = &*state.store;
        let key_manager_state: &KeyManagerState = &state.into();
        let merchant_id = merchant_context.get_merchant_account().get_id();
        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;

        let payment_intent = db
            .find_payment_intent_by_payment_id_merchant_id(
                &state.into(),
                &payment_id,
                merchant_id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved

        helpers::validate_payment_status_against_not_allowed_statuses(
            payment_intent.status,
            &[
                storage_enums::IntentStatus::Failed,
                storage_enums::IntentStatus::Succeeded,
            ],
            "create a session update for",
        )?;

        helpers::authenticate_client_secret(Some(request.client_secret.peek()), &payment_intent)?;

        let mut payment_attempt = db
            .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                &payment_intent.payment_id,
                merchant_id,
                payment_intent.active_attempt.get_id().as_str(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        let currency = payment_intent.currency.get_required_value("currency")?;

        let amount = payment_attempt.get_total_amount().into();

        payment_attempt.payment_method_type = Some(request.payment_method_type);

        let shipping_address = helpers::get_address_by_id(
            state,
            payment_intent.shipping_address_id.clone(),
            merchant_context.get_merchant_key_store(),
            &payment_intent.payment_id,
            merchant_id,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;

        let profile_id = payment_intent
            .profile_id
            .as_ref()
            .get_required_value("profile_id")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("'profile_id' not set in payment intent")?;

        let business_profile = db
            .find_business_profile_by_profile_id(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                profile_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
                id: profile_id.get_string_repr().to_owned(),
            })?;

        let tax_data = payments::TaxData {
            shipping_details: request.shipping.clone().into(),
            payment_method_type: request.payment_method_type,
        };

        let payment_data = PaymentData {
            flow: PhantomData,
            payment_intent,
            payment_attempt,
            currency,
            amount,
            email: None,
            mandate_id: None,
            mandate_connector: None,
            customer_acceptance: None,
            token: None,
            token_data: None,
            setup_mandate: None,
            address: payments::PaymentAddress::new(
                shipping_address.as_ref().map(From::from),
                None,
                None,
                business_profile.use_billing_as_payment_method_billing,
            ),
            confirm: None,
            payment_method_data: None,
            payment_method_token: None,
            payment_method_info: None,
            force_sync: None,
            all_keys_required: None,
            refunds: vec![],
            disputes: vec![],
            attempts: None,
            sessions_token: vec![],
            card_cvc: None,
            creds_identifier: None,
            pm_token: None,
            connector_customer_id: None,
            recurring_mandate_payment_data: None,
            ephemeral_key: None,
            multiple_capture_data: None,
            redirect_response: None,
            surcharge_details: None,
            frm_message: None,
            payment_link_data: None,
            incremental_authorization_details: None,
            authorizations: vec![],
            authentication: None,
            recurring_details: None,
            poll_config: None,
            tax_data: Some(tax_data),
            session_id: request.session_id.clone(),
            service_details: None,
            card_testing_guard_data: None,
            vault_operation: None,
            threeds_method_comp_ind: None,
            whole_connector_response: None,
            is_manual_retry_enabled: None,
        };
        let get_trackers_response = operations::GetTrackerResponse {
            operation: Box::new(self),
            customer_details: None,
            payment_data,
            business_profile,
            mandate_type: None,
        };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Send + Sync> Domain<F, api::PaymentsDynamicTaxCalculationRequest, PaymentData<F>>
    for PaymentSessionUpdate
{
    #[instrument(skip_all)]
    async fn get_or_create_customer_details<'a>(
        &'a self,
        _state: &SessionState,
        _payment_data: &mut PaymentData<F>,
        _request: Option<payments::CustomerDetails>,
        _merchant_key_store: &domain::MerchantKeyStore,
        _storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> errors::CustomResult<
        (
            PaymentSessionUpdateOperation<'a, F>,
            Option<domain::Customer>,
        ),
        errors::StorageError,
    > {
        Ok((Box::new(self), None))
    }

    async fn payments_dynamic_tax_calculation<'a>(
        &'a self,
        state: &SessionState,
        payment_data: &mut PaymentData<F>,
        _connector_call_type: &ConnectorCallType,
        business_profile: &domain::Profile,
        merchant_context: &domain::MerchantContext,
    ) -> errors::CustomResult<(), errors::ApiErrorResponse> {
        let is_tax_connector_enabled = business_profile.get_is_tax_connector_enabled();
        let skip_external_tax_calculation = payment_data
            .payment_intent
            .skip_external_tax_calculation
            .unwrap_or(false);
        if is_tax_connector_enabled && !skip_external_tax_calculation {
            let db = state.store.as_ref();
            let key_manager_state: &KeyManagerState = &state.into();

            let merchant_connector_id = business_profile
                .tax_connector_id
                .as_ref()
                .get_required_value("business_profile.tax_connector_id")?;

            #[cfg(feature = "v1")]
            let mca = db
                .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
                    key_manager_state,
                    &business_profile.merchant_id,
                    merchant_connector_id,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: merchant_connector_id.get_string_repr().to_string(),
                    },
                )?;

            #[cfg(feature = "v2")]
            let mca = db
                .find_merchant_connector_account_by_id(
                    key_manager_state,
                    merchant_connector_id,
                    key_store,
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: merchant_connector_id.get_string_repr().to_string(),
                    },
                )?;

            let connector_data =
                api::TaxCalculateConnectorData::get_connector_by_name(&mca.connector_name)?;

            let router_data = core_utils::construct_payments_dynamic_tax_calculation_router_data(
                state,
                merchant_context,
                payment_data,
                &mca,
            )
            .await?;
            let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
                api::CalculateTax,
                types::PaymentsTaxCalculationData,
                types::TaxCalculationResponseData,
            > = connector_data.connector.get_connector_integration();

            let response = services::execute_connector_processing_step(
                state,
                connector_integration,
                &router_data,
                payments::CallConnectorAction::Trigger,
                None,
                None,
            )
            .await
            .to_payment_failed_response()
            .attach_printable("Tax connector Response Failed")?;

            let tax_response = response.response.map_err(|err| {
                errors::ApiErrorResponse::ExternalConnectorError {
                    code: err.code,
                    message: err.message,
                    connector: connector_data.connector_name.clone().to_string(),
                    status_code: err.status_code,
                    reason: err.reason,
                }
            })?;

            let payment_method_type = payment_data
                .tax_data
                .clone()
                .map(|tax_data| tax_data.payment_method_type)
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("missing tax_data.payment_method_type")?;

            payment_data.payment_intent.tax_details = Some(diesel_models::TaxDetails {
                payment_method_type: Some(diesel_models::PaymentMethodTypeTax {
                    order_tax_amount: tax_response.order_tax_amount,
                    pmt: payment_method_type,
                }),
                default: None,
            });
            Ok(())
        } else {
            Ok(())
        }
    }

    #[instrument(skip_all)]
    async fn make_pm_data<'a>(
        &'a self,
        _state: &'a SessionState,
        _payment_data: &mut PaymentData<F>,
        _storage_scheme: storage_enums::MerchantStorageScheme,
        _merchant_key_store: &domain::MerchantKeyStore,
        _customer: &Option<domain::Customer>,
        _business_profile: &domain::Profile,
        _should_retry_with_pan: bool,
    ) -> RouterResult<(
        PaymentSessionUpdateOperation<'a, F>,
        Option<domain::PaymentMethodData>,
        Option<String>,
    )> {
        Ok((Box::new(self), None, None))
    }

    async fn get_connector<'a>(
        &'a self,
        _merchant_context: &domain::MerchantContext,
        state: &SessionState,
        _request: &api::PaymentsDynamicTaxCalculationRequest,
        _payment_intent: &storage::PaymentIntent,
    ) -> errors::CustomResult<api::ConnectorChoice, errors::ApiErrorResponse> {
        helpers::get_connector_default(state, None).await
    }

    #[instrument(skip_all)]
    async fn guard_payment_against_blocklist<'a>(
        &'a self,
        _state: &SessionState,
        _merchant_context: &domain::MerchantContext,
        _payment_data: &mut PaymentData<F>,
    ) -> errors::CustomResult<bool, errors::ApiErrorResponse> {
        Ok(false)
    }
}

#[async_trait]
impl<F: Clone + Sync> UpdateTracker<F, PaymentData<F>, api::PaymentsDynamicTaxCalculationRequest>
    for PaymentSessionUpdate
{
    #[instrument(skip_all)]
    async fn update_trackers<'b>(
        &'b self,
        state: &'b SessionState,
        _req_state: ReqState,
        mut payment_data: PaymentData<F>,
        _customer: Option<domain::Customer>,
        storage_scheme: storage_enums::MerchantStorageScheme,
        _updated_customer: Option<storage::CustomerUpdate>,
        key_store: &domain::MerchantKeyStore,
        _frm_suggestion: Option<FrmSuggestion>,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<(PaymentSessionUpdateOperation<'b, F>, PaymentData<F>)>
    where
        F: 'b + Send,
    {
        // For Google Pay and Apple Pay, we don’t need to call the connector again; we can directly confirm the payment after tax_calculation. So, we update the required fields in the database during the update_tracker call.
        if payment_data.should_update_in_update_tracker() {
            let shipping_address = payment_data
                .tax_data
                .clone()
                .map(|tax_data| tax_data.shipping_details);
            let key_manager_state = state.into();

            let shipping_details = shipping_address
                .clone()
                .async_map(|shipping_details| {
                    create_encrypted_data(&key_manager_state, key_store, shipping_details)
                })
                .await
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Unable to encrypt shipping details")?;

            let shipping_address = helpers::create_or_update_address_for_payment_by_request(
                state,
                shipping_address.map(From::from).as_ref(),
                payment_data.payment_intent.shipping_address_id.as_deref(),
                &payment_data.payment_intent.merchant_id,
                payment_data.payment_intent.customer_id.as_ref(),
                key_store,
                &payment_data.payment_intent.payment_id,
                storage_scheme,
            )
            .await?;

            let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::SessionResponseUpdate {
            tax_details: payment_data.payment_intent.tax_details.clone().ok_or(errors::ApiErrorResponse::InternalServerError).attach_printable("payment_intent.tax_details not found")?,
            shipping_address_id: shipping_address.map(|address| address.address_id),
            updated_by: payment_data.payment_intent.updated_by.clone(),
            shipping_details,
        };

            let db = &*state.store;
            let payment_intent = payment_data.payment_intent.clone();

            let updated_payment_intent = db
                .update_payment_intent(
                    &state.into(),
                    payment_intent,
                    payment_intent_update,
                    key_store,
                    storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

            payment_data.payment_intent = updated_payment_intent;
            Ok((Box::new(self), payment_data))
        } else {
            Ok((Box::new(self), payment_data))
        }
    }
}

impl<F: Send + Clone + Sync>
    ValidateRequest<F, api::PaymentsDynamicTaxCalculationRequest, PaymentData<F>>
    for PaymentSessionUpdate
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        request: &api::PaymentsDynamicTaxCalculationRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<(
        PaymentSessionUpdateOperation<'b, F>,
        operations::ValidateResult,
    )> {
        //paymentid is already generated and should be sent in the request
        let given_payment_id = request.payment_id.clone();

        Ok((
            Box::new(self),
            operations::ValidateResult {
                merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
                payment_id: api::PaymentIdType::PaymentIntentId(given_payment_id),
                storage_scheme: merchant_context.get_merchant_account().storage_scheme,
                requeue: false,
            },
        ))
    }
}


// Function: trim_from_stream
// File: crates/drainer/src/stream.rs
// Module: drainer

pub fn trim_from_stream(
        &self,
        stream_name: &str,
        minimum_entry_id: &str,
    ) -> errors::DrainerResult<usize>


// File: crates/hyperswitch_domain_models/src/router_flow_types/dispute.rs
// Module: hyperswitch_domain_models
// Public structs: 5

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

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

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

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


// File: crates/diesel_models/src/blocklist_fingerprint.rs
// Module: diesel_models
// Public structs: 2

use diesel::{Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};

use crate::schema::blocklist_fingerprint;

#[derive(Clone, Debug, Eq, Insertable, PartialEq, Serialize, Deserialize)]
#[diesel(table_name = blocklist_fingerprint)]
pub struct BlocklistFingerprintNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub fingerprint_id: String,
    pub data_kind: common_enums::BlocklistDataKind,
    pub encrypted_fingerprint: String,
    pub created_at: time::PrimitiveDateTime,
}

#[derive(
    Clone, Debug, Eq, PartialEq, Queryable, Identifiable, Selectable, Deserialize, Serialize,
)]
#[diesel(table_name = blocklist_fingerprint, primary_key(merchant_id, fingerprint_id), check_for_backend(diesel::pg::Pg))]
pub struct BlocklistFingerprint {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub fingerprint_id: String,
    pub data_kind: common_enums::BlocklistDataKind,
    pub encrypted_fingerprint: String,
    pub created_at: time::PrimitiveDateTime,
}


// Struct: ApplePayRecurringDetails
// File: crates/diesel_models/src/types.rs
// Module: diesel_models
// Implementations: 0

pub struct ApplePayRecurringDetails


// Function: get_connector_and_supporting_payment_method_type_for_session_call
// File: crates/hyperswitch_domain_models/src/merchant_connector_account.rs
// Module: hyperswitch_domain_models

pub fn get_connector_and_supporting_payment_method_type_for_session_call(
            &self,
        ) -> Vec<(&MerchantConnectorAccount, common_enums::PaymentMethodType, common_enums::PaymentMethod)>


// Struct: ProfileUpdate
// File: crates/api_models/src/admin.rs
// Module: api_models
// Implementations: 0

pub struct ProfileUpdate


// Function: get_status_field
// File: crates/analytics/src/opensearch.rs
// Module: analytics

pub fn get_status_field(&self, index: SearchIndex) -> &str


// Struct: StripePaymentMethodDetails
// File: crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct StripePaymentMethodDetails


// Trait: NetworkTokenWebhookResponseExt
// File: crates/router/src/core/webhooks/network_tokenization_incoming.rs
// Module: router

pub trait NetworkTokenWebhookResponseExt


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

pub fn update_business_profile_active_dynamic_algorithm_ref(
    db: &dyn StorageInterface,
    key_manager_state: &KeyManagerState,
    merchant_key_store: &domain::MerchantKeyStore,
    current_business_profile: domain::Profile,
    dynamic_routing_algorithm_ref: routing_types::DynamicRoutingAlgorithmRef,
) -> RouterResult<()>


// Function: search_results
// File: crates/analytics/src/search.rs
// Module: analytics

pub fn search_results(
    client: &OpenSearchClient,
    req: GetSearchRequestWithIndex,
    search_params: Vec<AuthInfo>,
) -> CustomResult<GetSearchResponse, OpenSearchError>


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

pub struct BarclaycardAuthEnrollmentRequest