// File: crates/router_derive/src/lib.rs
// Module: router_derive
// Public functions: 16
// Public structs: 3

//! Utility macros for the `router` crate.
#![warn(missing_docs)]
use syn::parse_macro_input;

use crate::macros::diesel::DieselEnumMeta;
mod macros;

/// Uses the [`Debug`][Debug] implementation of a type to derive its [`Display`][Display]
/// implementation.
///
/// Causes a compilation error if the type doesn't implement the [`Debug`][Debug] trait.
///
/// [Debug]: ::core::fmt::Debug
/// [Display]: ::core::fmt::Display
///
/// # Example
///
/// ```
/// use router_derive::DebugAsDisplay;
///
/// #[derive(Debug, DebugAsDisplay)]
/// struct Point {
///     x: f32,
///     y: f32,
/// }
///
/// #[derive(Debug, DebugAsDisplay)]
/// enum Color {
///     Red,
///     Green,
///     Blue,
/// }
/// ```
#[proc_macro_derive(DebugAsDisplay)]
pub fn debug_as_display_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(input as syn::DeriveInput);

    let tokens =
        macros::debug_as_display_inner(&ast).unwrap_or_else(|error| error.to_compile_error());
    tokens.into()
}

/// Derives the boilerplate code required for using an enum with `diesel` and a PostgreSQL database.
/// The enum is required to implement (or derive) the [`ToString`][ToString] and the
/// [`FromStr`][FromStr] traits for this derive macro to be used.
///
/// Works in tandem with the [`diesel_enum`][diesel_enum] attribute macro to achieve the desired
/// results.
///
/// [diesel_enum]: macro@crate::diesel_enum
/// [FromStr]: ::core::str::FromStr
/// [ToString]: ::std::string::ToString
///
/// # Example
///
/// ```
/// use router_derive::diesel_enum;
///
/// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it
/// // yourself if required.
/// #[derive(strum::Display, strum::EnumString)]
/// #[derive(Debug)]
/// #[diesel_enum(storage_type = "db_enum")]
/// enum Color {
///     Red,
///     Green,
///     Blue,
/// }
/// ```
#[proc_macro_derive(DieselEnum, attributes(storage_type))]
pub fn diesel_enum_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
    let tokens =
        macros::diesel_enum_derive_inner(&ast).unwrap_or_else(|error| error.to_compile_error());
    tokens.into()
}

/// Similar to [`DieselEnum`] but uses text when storing in the database, this is to avoid
/// making changes to the database when the enum variants are added or modified
///
/// # Example
/// [DieselEnum]: macro@crate::diesel_enum
///
/// ```
/// use router_derive::{diesel_enum};
///
/// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it
/// // yourself if required.
/// #[derive(strum::Display, strum::EnumString)]
/// #[derive(Debug)]
/// #[diesel_enum(storage_type = "text")]
/// enum Color {
///     Red,
///     Green,
///     Blue,
/// }
/// ```
#[proc_macro_derive(DieselEnumText)]
pub fn diesel_enum_derive_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
    let tokens = macros::diesel_enum_text_derive_inner(&ast)
        .unwrap_or_else(|error| error.to_compile_error());
    tokens.into()
}

/// Derives the boilerplate code required for using an enum with `diesel` and a PostgreSQL database.
///
/// Storage Type can either be "text" or "db_enum"
/// Choosing text will store the enum as text in the database, whereas db_enum will map it to the
/// corresponding database enum
///
/// Works in tandem with the [`DieselEnum`][DieselEnum] derive macro to achieve the desired results.
/// The enum is required to implement (or derive) the [`ToString`][ToString] and the
/// [`FromStr`][FromStr] traits for the [`DieselEnum`][DieselEnum] derive macro to be used.
///
/// [DieselEnum]: crate::DieselEnum
/// [FromStr]: ::core::str::FromStr
/// [ToString]: ::std::string::ToString
///
/// # Example
///
/// ```
/// use router_derive::{diesel_enum};
///
/// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it
/// // yourself if required. (Required by the DieselEnum derive macro.)
/// #[derive(strum::Display, strum::EnumString)]
/// #[derive(Debug)]
/// #[diesel_enum(storage_type = "text")]
/// enum Color {
///     Red,
///     Green,
///     Blue,
/// }
/// ```
#[proc_macro_attribute]
pub fn diesel_enum(
    args: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let args_parsed = parse_macro_input!(args as DieselEnumMeta);
    let item = syn::parse_macro_input!(item as syn::ItemEnum);

    macros::diesel::diesel_enum_attribute_macro(args_parsed, &item)
        .unwrap_or_else(|error| error.to_compile_error())
        .into()
}

/// A derive macro which generates the setter functions for any struct with fields
/// # Example
/// ```
/// use router_derive::Setter;
///
/// #[derive(Setter)]
/// struct Test {
///     test:u32
/// }
/// ```
/// The above Example will expand to
/// ```rust, ignore
/// impl Test {
///     fn set_test(&mut self, val: u32) -> &mut Self {
///         self.test = val;
///         self
///     }
/// }
/// ```
///
/// # Panics
///
/// Panics if a struct without named fields is provided as input to the macro
// FIXME: Remove allowed warnings, raise compile errors in a better manner instead of panicking
#[allow(clippy::panic, clippy::unwrap_used)]
#[proc_macro_derive(Setter, attributes(auth_based))]
pub fn setter(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let ident = &input.ident;
    // All the fields in the parent struct
    let fields = if let syn::Data::Struct(syn::DataStruct {
        fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
        ..
    }) = input.data
    {
        named
    } else {
        // FIXME: Use `compile_error!()` instead
        panic!("You can't use this proc-macro on structs without fields");
    };

    // Methods in the build struct like if the struct is
    // Struct i {n: u32}
    // this will be
    // pub fn set_n(&mut self,n: u32)
    let build_methods = fields.iter().map(|f| {
        let name = f.ident.as_ref().unwrap();
        let method_name = format!("set_{name}");
        let method_ident = syn::Ident::new(&method_name, name.span());
        let ty = &f.ty;
        if check_if_auth_based_attr_is_present(f, "auth_based") {
            quote::quote! {
                pub fn #method_ident(&mut self, val:#ty, is_merchant_flow: bool)->&mut Self{
                    if is_merchant_flow {
                        self.#name = val;
                    }
                    self
                }
            }
        } else {
            quote::quote! {
                pub fn #method_ident(&mut self, val:#ty)->&mut Self{
                    self.#name = val;
                    self
                }
            }
        }
    });
    let output = quote::quote! {
    #[automatically_derived]
    impl #ident {
            #(#build_methods)*
        }

    };
    output.into()
}

#[inline]
fn check_if_auth_based_attr_is_present(f: &syn::Field, ident: &str) -> bool {
    for i in f.attrs.iter() {
        if i.path().is_ident(ident) {
            return true;
        }
    }
    false
}

/// Derives the [`Serialize`][Serialize] implementation for error responses that are returned by
/// the API server.
///
/// This macro can be only used with enums. In addition to deriving [`Serialize`][Serialize], this
/// macro provides three methods: `error_type()`, `error_code()` and `error_message()`. Each enum
/// variant must have three required fields:
///
/// - `error_type`: This must be an enum variant which is returned by the `error_type()` method.
/// - `code`: A string error code, returned by the `error_code()` method.
/// - `message`: A string error message, returned by the `error_message()` method. The message
///   provided will directly be passed to `format!()`.
///
/// The return type of the `error_type()` method is provided by the `error_type_enum` field
/// annotated to the entire enum. Thus, all enum variants provided to the `error_type` field must
/// be variants of the enum provided to `error_type_enum` field. In addition, the enum passed to
/// the `error_type_enum` field must implement [`Serialize`][Serialize].
///
/// **NOTE:** This macro does not implement the [`Display`][Display] trait.
///
/// # Example
///
/// ```
/// use router_derive::ApiError;
///
/// #[derive(Clone, Debug, serde::Serialize)]
/// enum ErrorType {
///     StartupError,
///     InternalError,
///     SerdeError,
/// }
///
/// #[derive(Debug, ApiError)]
/// #[error(error_type_enum = ErrorType)]
/// enum MyError {
///     #[error(error_type = ErrorType::StartupError, code = "E001", message = "Failed to read configuration")]
///     ConfigurationError,
///     #[error(error_type = ErrorType::InternalError, code = "E002", message = "A database error occurred")]
///     DatabaseError,
///     #[error(error_type = ErrorType::SerdeError, code = "E003", message = "Failed to deserialize object")]
///     DeserializationError,
///     #[error(error_type = ErrorType::SerdeError, code = "E004", message = "Failed to serialize object")]
///     SerializationError,
/// }
///
/// impl ::std::fmt::Display for MyError {
///     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
///         f.write_str(&self.error_message())
///     }
/// }
/// ```
///
/// # The Generated `Serialize` Implementation
///
/// - For a simple enum variant with no fields, the generated [`Serialize`][Serialize]
///   implementation has only three fields, `type`, `code` and `message`:
///
/// ```
/// # use router_derive::ApiError;
/// # #[derive(Clone, Debug, serde::Serialize)]
/// # enum ErrorType {
/// #     StartupError,
/// # }
/// #[derive(Debug, ApiError)]
/// #[error(error_type_enum = ErrorType)]
/// enum MyError {
///     #[error(error_type = ErrorType::StartupError, code = "E001", message = "Failed to read configuration")]
///     ConfigurationError,
///     // ...
/// }
/// # impl ::std::fmt::Display for MyError {
/// #     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
/// #         f.write_str(&self.error_message())
/// #     }
/// # }
///
/// let json = serde_json::json!({
///     "type": "StartupError",
///     "code": "E001",
///     "message": "Failed to read configuration"
/// });
/// assert_eq!(serde_json::to_value(MyError::ConfigurationError).unwrap(), json);
/// ```
///
/// - For an enum variant with named fields, the generated [`Serialize`][Serialize] implementation
///   includes three mandatory fields, `type`, `code` and `message`, and any other fields not
///   included in the message:
///
/// ```
/// # use router_derive::ApiError;
/// # #[derive(Clone, Debug, serde::Serialize)]
/// # enum ErrorType {
/// #     StartupError,
/// # }
/// #[derive(Debug, ApiError)]
/// #[error(error_type_enum = ErrorType)]
/// enum MyError {
///     #[error(error_type = ErrorType::StartupError, code = "E001", message = "Failed to read configuration file: {file_path}")]
///     ConfigurationError { file_path: String, reason: String },
///     // ...
/// }
/// # impl ::std::fmt::Display for MyError {
/// #     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
/// #         f.write_str(&self.error_message())
/// #     }
/// # }
///
/// let json = serde_json::json!({
///     "type": "StartupError",
///     "code": "E001",
///     "message": "Failed to read configuration file: config.toml",
///     "reason": "File not found"
/// });
/// let error = MyError::ConfigurationError{
///     file_path: "config.toml".to_string(),
///     reason: "File not found".to_string(),
/// };
/// assert_eq!(serde_json::to_value(error).unwrap(), json);
/// ```
///
/// [Serialize]: https://docs.rs/serde/latest/serde/trait.Serialize.html
/// [Display]: ::core::fmt::Display
#[proc_macro_derive(ApiError, attributes(error))]
pub fn api_error_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(input as syn::DeriveInput);

    let tokens =
        macros::api_error_derive_inner(&ast).unwrap_or_else(|error| error.to_compile_error());
    tokens.into()
}

/// Derives the `core::payments::Operation` trait on a type with a default base
/// implementation.
///
/// ## Usage
/// On deriving, the conversion functions to be implemented need to be specified in an helper
/// attribute `#[operation(..)]`. To derive all conversion functions, use `#[operation(all)]`. To
/// derive specific conversion functions, pass the required identifiers to the attribute.
/// `#[operation(validate_request, get_tracker)]`. Available conversions are listed below :-
///
/// - validate_request
/// - get_tracker
/// - domain
/// - update_tracker
///
/// ## Example
/// ```rust, ignore
/// use router_derive::Operation;
///
/// #[derive(Operation)]
/// #[operation(all)]
/// struct Point {
///     x: u64,
///     y: u64
/// }
///
/// // The above will expand to this
/// const _: () = {
///     use crate::core::errors::RouterResult;
///     use crate::core::payments::{GetTracker, PaymentData, UpdateTracker, ValidateRequest};
///     impl crate::core::payments::Operation for Point {
///         fn to_validate_request(&self) -> RouterResult<&dyn ValidateRequest> {
///             Ok(self)
///         }
///         fn to_get_tracker(&self) -> RouterResult<&dyn GetTracker<PaymentData>> {
///             Ok(self)
///         }
///         fn to_domain(&self) -> RouterResult<&dyn Domain> {
///             Ok(self)
///         }
///         fn to_update_tracker(&self) -> RouterResult<&dyn UpdateTracker<PaymentData>> {
///             Ok(self)
///         }
///     }
///     impl crate::core::payments::Operation for &Point {
///         fn to_validate_request(&self) -> RouterResult<&dyn ValidateRequest> {
///             Ok(*self)
///         }
///         fn to_get_tracker(&self) -> RouterResult<&dyn GetTracker<PaymentData>> {
///             Ok(*self)
///         }
///         fn to_domain(&self) -> RouterResult<&dyn Domain> {
///             Ok(*self)
///         }
///         fn to_update_tracker(&self) -> RouterResult<&dyn UpdateTracker<PaymentData>> {
///             Ok(*self)
///         }
///     }
/// };
///
/// #[derive(Operation)]
/// #[operation(validate_request, get_tracker)]
/// struct Point3 {
///     x: u64,
///     y: u64,
///     z: u64
/// }
///
/// // The above will expand to this
/// const _: () = {
///     use crate::core::errors::RouterResult;
///     use crate::core::payments::{GetTracker, PaymentData, UpdateTracker, ValidateRequest};
///     impl crate::core::payments::Operation for Point3 {
///         fn to_validate_request(&self) -> RouterResult<&dyn ValidateRequest> {
///             Ok(self)
///         }
///         fn to_get_tracker(&self) -> RouterResult<&dyn GetTracker<PaymentData>> {
///             Ok(self)
///         }
///     }
///     impl crate::core::payments::Operation for &Point3 {
///         fn to_validate_request(&self) -> RouterResult<&dyn ValidateRequest> {
///             Ok(*self)
///         }
///         fn to_get_tracker(&self) -> RouterResult<&dyn GetTracker<PaymentData>> {
///             Ok(*self)
///         }
///     }
/// };
///
/// ```
///
/// The `const _: () = {}` allows us to import stuff with `use` without affecting the module
/// imports, since use statements are not allowed inside of impl blocks. This technique is
/// used by `diesel`.
#[proc_macro_derive(PaymentOperation, attributes(operation))]
pub fn operation_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    macros::operation::operation_derive_inner(input)
        .unwrap_or_else(|err| err.to_compile_error().into())
}

/// Generates different schemas with the ability to mark few fields as mandatory for certain schema
/// Usage
/// ```
/// use router_derive::PolymorphicSchema;
///
/// #[derive(PolymorphicSchema)]
/// #[generate_schemas(PaymentsCreateRequest, PaymentsConfirmRequest)]
/// struct PaymentsRequest {
///     #[mandatory_in(PaymentsCreateRequest = u64)]
///     amount: Option<u64>,
///     #[mandatory_in(PaymentsCreateRequest = String)]
///     currency: Option<String>,
///     payment_method: String,
/// }
/// ```
///
/// This will create two structs `PaymentsCreateRequest` and `PaymentsConfirmRequest` as follows
/// It will retain all the other attributes that are used in the original struct, and only consume
/// the #[mandatory_in] attribute to generate schemas
///
/// ```
/// #[derive(utoipa::ToSchema)]
/// struct PaymentsCreateRequest {
///     #[schema(required = true)]
///     amount: Option<u64>,
///
///     #[schema(required = true)]
///     currency: Option<String>,
///
///     payment_method: String,
/// }
///
/// #[derive(utoipa::ToSchema)]
/// struct PaymentsConfirmRequest {
///     amount: Option<u64>,
///     currency: Option<String>,
///     payment_method: String,
/// }
/// ```
#[proc_macro_derive(
    PolymorphicSchema,
    attributes(mandatory_in, generate_schemas, remove_in)
)]
pub fn polymorphic_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::polymorphic_macro_derive_inner(input)
        .unwrap_or_else(|error| error.into_compile_error())
        .into()
}

/// Implements the `Validate` trait to check if the config variable is present
/// Usage
/// ```
/// use router_derive::ConfigValidate;
///
/// #[derive(ConfigValidate)]
/// struct ConnectorParams {
///     base_url: String,
/// }
///
/// enum ApplicationError {
///     InvalidConfigurationValueError(String),
/// }
///
/// #[derive(ConfigValidate)]
/// struct Connectors {
///     pub stripe: ConnectorParams,
///     pub checkout: ConnectorParams
/// }
/// ```
///
/// This will call the `validate()` function for all the fields in the struct
///
/// ```rust, ignore
/// impl Connectors {
///      fn validate(&self) -> Result<(), ApplicationError> {
///         self.stripe.validate()?;
///         self.checkout.validate()?;
///      }
/// }
/// ```
#[proc_macro_derive(ConfigValidate)]
pub fn validate_config(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::misc::validate_config(input)
        .unwrap_or_else(|error| error.into_compile_error())
        .into()
}

/// Generates the function to get the value out of enum variant
/// Usage
/// ```
/// use router_derive::TryGetEnumVariant;
///
/// impl std::fmt::Display for RedisError {
///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
///         match self {
///             Self::UnknownResult => write!(f, "Unknown result")
///         }
///     }
/// }
///
/// impl std::error::Error for RedisError {}
///
/// #[derive(Debug)]
/// enum RedisError {
///     UnknownResult
/// }
///
/// #[derive(TryGetEnumVariant)]
/// #[error(RedisError::UnknownResult)]
/// enum RedisResult {
///     Set(String),
///     Get(i32)
/// }
/// ```
///
/// This will generate the function to get `String` and `i32` out of the variants
///
/// ```rust, ignore
/// impl RedisResult {
///     fn try_into_get(&self)-> Result<i32, RedisError> {
///         match self {
///             Self::Get(a) => Ok(a),
///             _=>Err(RedisError::UnknownResult)
///         }
///     }
///
///     fn try_into_set(&self)-> Result<String, RedisError> {
///         match self {
///             Self::Set(a) => Ok(a),
///             _=> Err(RedisError::UnknownResult)
///         }
///     }
/// }
/// ```
#[proc_macro_derive(TryGetEnumVariant, attributes(error))]
pub fn try_get_enum_variant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::try_get_enum::try_get_enum_variant(input)
        .unwrap_or_else(|error| error.into_compile_error())
        .into()
}

/// Uses the [`Serialize`] implementation of a type to derive a function implementation
/// for converting nested keys structure into a HashMap of key, value where key is in
/// the flattened form.
///
/// Example
///
/// ```
/// #[derive(Default, Serialize, FlatStruct)]
/// pub struct User {
///     name: String,
///     address: Address,
///     email: String,
/// }
///
/// #[derive(Default, Serialize)]
/// pub struct Address {
///     line1: String,
///     line2: String,
///     zip: String,
/// }
///
/// let user = User::default();
/// let flat_struct_map = user.flat_struct();
///
/// [
///     ("name", "Test"),
///     ("address.line1", "1397"),
///     ("address.line2", "Some street"),
///     ("address.zip", "941222"),
///     ("email", "test@example.com"),
/// ]
/// ```
#[proc_macro_derive(FlatStruct)]
pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as syn::DeriveInput);
    let name = &input.ident;

    let expanded = quote::quote! {
        impl #name {
            pub fn flat_struct(&self) -> std::collections::HashMap<String, String> {
                use serde_json::Value;
                use std::collections::HashMap;

                fn flatten_value(
                    value: &Value,
                    prefix: &str,
                    result: &mut HashMap<String, String>
                ) {
                    match value {
                        Value::Object(map) => {
                            for (key, val) in map {
                                let new_key = if prefix.is_empty() {
                                    key.to_string()
                                } else {
                                    format!("{}.{}", prefix, key)
                                };
                                flatten_value(val, &new_key, result);
                            }
                        }
                        Value::String(s) => {
                            result.insert(prefix.to_string(), s.clone());
                        }
                        Value::Number(n) => {
                            result.insert(prefix.to_string(), n.to_string());
                        }
                        Value::Bool(b) => {
                            result.insert(prefix.to_string(), b.to_string());
                        }
                        _ => {}
                    }
                }

                let mut result = HashMap::new();
                let value = serde_json::to_value(self).unwrap();
                flatten_value(&value, "", &mut result);
                result
            }
        }
    };

    proc_macro::TokenStream::from(expanded)
}

/// Generates the permissions enum and implematations for the permissions
///
/// **NOTE:** You have to make sure that all the identifiers used
/// in the macro input are present in the respective enums as well.
///
/// ## Usage
/// ```
/// use router_derive::generate_permissions;
///
/// enum Scope {
///     Read,
///     Write,
/// }
///
/// enum EntityType {
///    Profile,
///    Merchant,
///    Org,
/// }
///
/// enum Resource {
///    Payments,
///    Refunds,
/// }
///
/// generate_permissions! {
///     permissions: [
///         Payments: {
///             scopes: [Read, Write],
///             entities: [Profile, Merchant, Org]
///         },
///         Refunds: {
///             scopes: [Read],
///             entities: [Profile, Org]
///         }
///     ]
/// }
/// ```
/// This will generate the following enum.
/// ```
/// enum Permission {
///    ProfilePaymentsRead,
///    ProfilePaymentsWrite,
///    MerchantPaymentsRead,
///    MerchantPaymentsWrite,
///    OrgPaymentsRead,
///    OrgPaymentsWrite,
///    ProfileRefundsRead,
///    OrgRefundsRead,
/// ```
#[proc_macro]
pub fn generate_permissions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    macros::generate_permissions_inner(input)
}

/// Generates the ToEncryptable trait for a type
///
/// This macro generates the temporary structs which has the fields that needs to be encrypted
///
/// fn to_encryptable: Convert the temp struct to a hashmap that can be sent over the network
/// fn from_encryptable: Convert the hashmap back to temp struct
#[proc_macro_derive(ToEncryption, attributes(encrypt))]
pub fn derive_to_encryption_attr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::derive_to_encryption(input)
        .unwrap_or_else(|err| err.into_compile_error())
        .into()
}

/// Derives validation functionality for structs with string-based fields that have
/// schema attributes specifying constraints like minimum and maximum lengths.
///
/// This macro generates a `validate()` method that checks if string based fields
/// meet the length requirements specified in their schema attributes.
///
/// ## Supported Types
///   - Option<T> or T: where T: String or Url
///
/// ## Supported Schema Attributes
///
/// - `min_length`: Specifies the minimum allowed character length
/// - `max_length`: Specifies the maximum allowed character length
///
/// ## Example
///
/// ```
/// use utoipa::ToSchema;
/// use router_derive::ValidateSchema;
/// use url::Url;
///
/// #[derive(Default, ToSchema, ValidateSchema)]
/// pub struct PaymentRequest {
///     #[schema(min_length = 10, max_length = 255)]
///     pub description: String,
///
///     #[schema(example = "https://example.com/return", max_length = 255)]
///     pub return_url: Option<Url>,
///
///     // Field without constraints
///     pub amount: u64,
/// }
///
/// let payment = PaymentRequest {
///     description: "Too short".to_string(),
///     return_url: Some(Url::parse("https://very-long-domain.com/callback").unwrap()),
///     amount: 1000,
/// };
///
/// let validation_result = payment.validate();
/// assert!(validation_result.is_err());
/// assert_eq!(
///     validation_result.unwrap_err(),
///     "description must be at least 10 characters long. Received 9 characters"
/// );
/// ```
///
/// ## Notes
/// - For `Option` fields, validation is only performed when the value is `Some`
/// - Fields without schema attributes or with unsupported types are ignored
/// - The validation stops on the first error encountered
/// - The generated `validate()` method returns `Ok(())` if all validations pass, or
///   `Err(String)` with an error message if any validations fail.
#[proc_macro_derive(ValidateSchema, attributes(schema))]
pub fn validate_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::validate_schema_derive(input)
        .unwrap_or_else(|error| error.into_compile_error())
        .into()
}


// Function: update_target_time
// File: crates/api_models/src/routing.rs
// Module: api_models

pub fn update_target_time(&mut self, new: &Self)


// Implementation: impl ResponseId
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Methods: 1 total (1 public)

impl ResponseId


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

impl KafkaPaymentIntent


// Function: retrieve_gsm_rule
// File: crates/router/src/core/gsm.rs
// Module: router

pub fn retrieve_gsm_rule(
    state: SessionState,
    gsm_request: gsm_api_types::GsmRetrieveRequest,
) -> RouterResponse<gsm_api_types::GsmResponse>


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

pub fn from_conf(
        conf: DrainerSettings,
        stores: HashMap<id_type::TenantId, Arc<Store>>,
    ) -> Self


// Function: get_refund_id_as_string
// File: crates/api_models/src/refunds.rs
// Module: api_models

pub fn get_refund_id_as_string(&self) -> String


// Struct: Coupons
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Coupons


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

pub fn set_order_tax_amount(&mut self, order_tax_amount: Option<MinorUnit>)


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

pub fn should_call_retrieve(status: api_enums::PayoutStatus) -> bool


// Struct: TsysPaymentsCaptureRequest
// File: crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TsysPaymentsCaptureRequest


// Function: connector_update
// File: crates/openapi/src/routes/merchant_connector_account.rs
// Module: openapi

pub fn connector_update()


// Trait: OrganizationBridge
// File: crates/diesel_models/src/organization.rs
// Module: diesel_models

pub trait OrganizationBridge


// Struct: Bamboraapac
// File: crates/hyperswitch_connectors/src/connectors/bamboraapac.rs
// Module: hyperswitch_connectors
// Implementations: 17
// Traits: api::Payment, api::PaymentSession, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, api::PaymentToken, ConnectorValidation, ConnectorCommon, IncomingWebhook, ConnectorSpecifications

pub struct Bamboraapac

api::Payment api::PaymentSession api::ConnectorAccessToken api::MandateSetup api::PaymentAuthorize api::PaymentSync api::PaymentCapture api::PaymentVoid api::Refund api::RefundExecute api::RefundSync api::PaymentToken ConnectorValidation ConnectorCommon IncomingWebhook ConnectorSpecifications


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

pub struct ProfileResponse


// File: crates/hyperswitch_interfaces/src/api/fraud_check_v2.rs
// Module: hyperswitch_interfaces

//! FRM V2 interface
use hyperswitch_domain_models::{
    router_data_v2::flow_common_types::FrmFlowData,
    router_flow_types::{Checkout, Fulfillment, RecordReturn, Sale, Transaction},
    router_request_types::fraud_check::{
        FraudCheckCheckoutData, FraudCheckFulfillmentData, FraudCheckRecordReturnData,
        FraudCheckSaleData, FraudCheckTransactionData,
    },
    router_response_types::fraud_check::FraudCheckResponseData,
};

use crate::api::ConnectorIntegrationV2;

/// trait FraudCheckSaleV2
pub trait FraudCheckSaleV2:
    ConnectorIntegrationV2<Sale, FrmFlowData, FraudCheckSaleData, FraudCheckResponseData>
{
}

/// trait FraudCheckCheckoutV2
pub trait FraudCheckCheckoutV2:
    ConnectorIntegrationV2<Checkout, FrmFlowData, FraudCheckCheckoutData, FraudCheckResponseData>
{
}

/// trait FraudCheckTransactionV2
pub trait FraudCheckTransactionV2:
    ConnectorIntegrationV2<Transaction, FrmFlowData, FraudCheckTransactionData, FraudCheckResponseData>
{
}

/// trait FraudCheckFulfillmentV2
pub trait FraudCheckFulfillmentV2:
    ConnectorIntegrationV2<Fulfillment, FrmFlowData, FraudCheckFulfillmentData, FraudCheckResponseData>
{
}

/// trait FraudCheckRecordReturnV2
pub trait FraudCheckRecordReturnV2:
    ConnectorIntegrationV2<
    RecordReturn,
    FrmFlowData,
    FraudCheckRecordReturnData,
    FraudCheckResponseData,
>
{
}

/// trait FraudCheckV2
pub trait FraudCheckV2:
    super::ConnectorCommon
    + FraudCheckSaleV2
    + FraudCheckTransactionV2
    + FraudCheckCheckoutV2
    + FraudCheckFulfillmentV2
    + FraudCheckRecordReturnV2
{
}


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

impl api::PaymentToken for for Loonio


// Implementation: impl GlobalStorageInterface for for Store
// File: crates/router/src/db.rs
// Module: router
// Methods: 1 total (0 public)

impl GlobalStorageInterface for for Store


// Struct: AffirmPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AffirmPaymentsResponse


// Function: set_validate_result
// File: crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
// Module: router

pub fn set_validate_result(
        self,
        customer: &'a api::CustomerDetails,
    ) -> NetworkTokenizationBuilder<'a, PmValidated>


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

pub fn new() -> &'static Self


// Struct: MonerisAuthType
// File: crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MonerisAuthType


// Implementation: impl webhooks::IncomingWebhook for for Payme
// File: crates/hyperswitch_connectors/src/connectors/payme.rs
// Module: hyperswitch_connectors
// Methods: 8 total (0 public)

impl webhooks::IncomingWebhook for for Payme


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

impl api::PaymentAuthorize for for Taxjar


// Struct: VerifyEmail
// File: crates/router/src/services/email/types.rs
// Module: router
// Implementations: 1
// Traits: EmailData

pub struct VerifyEmail


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

pub fn get_connector_name(&self) -> common_enums::connector_enums::Connector


// Implementation: impl Datatrans
// File: crates/hyperswitch_connectors/src/connectors/datatrans.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl Datatrans


// File: crates/scheduler/src/db/queue.rs
// Module: scheduler

use common_utils::errors::CustomResult;
use diesel_models::process_tracker as storage;
use redis_interface::{errors::RedisError, RedisEntryId, SetnxReply};
use router_env::logger;
use storage_impl::{mock_db::MockDb, redis::kv_store::RedisConnInterface};

use crate::{errors::ProcessTrackerError, scheduler::Store};

#[async_trait::async_trait]
pub trait QueueInterface {
    async fn fetch_consumer_tasks(
        &self,
        stream_name: &str,
        group_name: &str,
        consumer_name: &str,
    ) -> CustomResult<Vec<storage::ProcessTracker>, ProcessTrackerError>;

    async fn consumer_group_create(
        &self,
        stream: &str,
        group: &str,
        id: &RedisEntryId,
    ) -> CustomResult<(), RedisError>;

    async fn acquire_pt_lock(
        &self,
        tag: &str,
        lock_key: &str,
        lock_val: &str,
        ttl: i64,
    ) -> CustomResult<bool, RedisError>;

    async fn release_pt_lock(&self, tag: &str, lock_key: &str) -> CustomResult<bool, RedisError>;

    async fn stream_append_entry(
        &self,
        stream: &str,
        entry_id: &RedisEntryId,
        fields: Vec<(&str, String)>,
    ) -> CustomResult<(), RedisError>;

    async fn get_key(&self, key: &str) -> CustomResult<Vec<u8>, RedisError>;
}

#[async_trait::async_trait]
impl QueueInterface for Store {
    async fn fetch_consumer_tasks(
        &self,
        stream_name: &str,
        group_name: &str,
        consumer_name: &str,
    ) -> CustomResult<Vec<storage::ProcessTracker>, ProcessTrackerError> {
        crate::consumer::fetch_consumer_tasks(
            self,
            &self
                .get_redis_conn()
                .map_err(ProcessTrackerError::ERedisError)?
                .clone(),
            stream_name,
            group_name,
            consumer_name,
        )
        .await
    }

    async fn consumer_group_create(
        &self,
        stream: &str,
        group: &str,
        id: &RedisEntryId,
    ) -> CustomResult<(), RedisError> {
        self.get_redis_conn()?
            .consumer_group_create(&stream.into(), group, id)
            .await
    }

    async fn acquire_pt_lock(
        &self,
        tag: &str,
        lock_key: &str,
        lock_val: &str,
        ttl: i64,
    ) -> CustomResult<bool, RedisError> {
        let conn = self.get_redis_conn()?.clone();
        let is_lock_acquired = conn
            .set_key_if_not_exists_with_expiry(&lock_key.into(), lock_val, None)
            .await;
        Ok(match is_lock_acquired {
            Ok(SetnxReply::KeySet) => match conn.set_expiry(&lock_key.into(), ttl).await {
                Ok(()) => true,

                #[allow(unused_must_use)]
                Err(error) => {
                    logger::error!(?error);
                    conn.delete_key(&lock_key.into()).await;
                    false
                }
            },
            Ok(SetnxReply::KeyNotSet) => {
                logger::error!(%tag, "Lock not acquired, previous fetch still in progress");
                false
            }
            Err(error) => {
                logger::error!(?error, %tag, "Error while locking");
                false
            }
        })
    }

    async fn release_pt_lock(&self, tag: &str, lock_key: &str) -> CustomResult<bool, RedisError> {
        let is_lock_released = self.get_redis_conn()?.delete_key(&lock_key.into()).await;
        Ok(match is_lock_released {
            Ok(_del_reply) => true,
            Err(error) => {
                logger::error!(?error, %tag, "Error while releasing lock");
                false
            }
        })
    }

    async fn stream_append_entry(
        &self,
        stream: &str,
        entry_id: &RedisEntryId,
        fields: Vec<(&str, String)>,
    ) -> CustomResult<(), RedisError> {
        self.get_redis_conn()?
            .stream_append_entry(&stream.into(), entry_id, fields)
            .await
    }

    async fn get_key(&self, key: &str) -> CustomResult<Vec<u8>, RedisError> {
        self.get_redis_conn()?.get_key::<Vec<u8>>(&key.into()).await
    }
}

#[async_trait::async_trait]
impl QueueInterface for MockDb {
    async fn fetch_consumer_tasks(
        &self,
        _stream_name: &str,
        _group_name: &str,
        _consumer_name: &str,
    ) -> CustomResult<Vec<storage::ProcessTracker>, ProcessTrackerError> {
        // [#172]: Implement function for `MockDb`
        Err(ProcessTrackerError::ResourceFetchingFailed {
            resource_name: "consumer_tasks".to_string(),
        })?
    }

    async fn consumer_group_create(
        &self,
        _stream: &str,
        _group: &str,
        _id: &RedisEntryId,
    ) -> CustomResult<(), RedisError> {
        // [#172]: Implement function for `MockDb`
        Err(RedisError::ConsumerGroupCreateFailed)?
    }

    async fn acquire_pt_lock(
        &self,
        _tag: &str,
        _lock_key: &str,
        _lock_val: &str,
        _ttl: i64,
    ) -> CustomResult<bool, RedisError> {
        // [#172]: Implement function for `MockDb`
        Ok(false)
    }

    async fn release_pt_lock(&self, _tag: &str, _lock_key: &str) -> CustomResult<bool, RedisError> {
        // [#172]: Implement function for `MockDb`
        Ok(false)
    }

    async fn stream_append_entry(
        &self,
        _stream: &str,
        _entry_id: &RedisEntryId,
        _fields: Vec<(&str, String)>,
    ) -> CustomResult<(), RedisError> {
        // [#172]: Implement function for `MockDb`
        Err(RedisError::StreamAppendFailed)?
    }

    async fn get_key(&self, _key: &str) -> CustomResult<Vec<u8>, RedisError> {
        Err(RedisError::RedisConnectionError.into())
    }
}


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

impl Refund for for Payone


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

pub struct MerchantAdvice


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

pub struct MerchantAccountListRequest


// Struct: FinixRouterData
// File: crates/hyperswitch_connectors/src/connectors/finix/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FinixRouterData<T>


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

impl Responder


// Struct: CustomerUpdateRequest
// File: crates/router/src/compatibility/stripe/customers/types.rs
// Module: router
// Implementations: 0

pub struct CustomerUpdateRequest


// Struct: PaymentMethodNew
// File: crates/diesel_models/src/payment_method.rs
// Module: diesel_models
// Implementations: 1

pub struct PaymentMethodNew


// Implementation: impl CurrentFlow
// File: crates/router/src/types/domain/user/decision_manager.rs
// Module: router
// Methods: 2 total (1 public)

impl CurrentFlow


// Implementation: impl State for for CardInfoUpdate
// File: crates/router/src/core/cards_info.rs
// Module: router
// Methods: 0 total (0 public)

impl State for for CardInfoUpdate


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

impl api::RefundSync for for Authorizedotnet


// Struct: GigadatPaymentData
// File: crates/hyperswitch_connectors/src/connectors/gigadat/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GigadatPaymentData


// Function: diesel_enum_derive_string
// File: crates/router_derive/src/lib.rs
// Module: router_derive

pub fn diesel_enum_derive_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream


// Implementation: impl GetCaptureMethod for for PaymentsSyncData
// File: crates/hyperswitch_connectors/src/connectors/aci/transformers.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl GetCaptureMethod for for PaymentsSyncData


// Struct: BankAccountCredentialsRequest
// File: crates/pm_auth/src/types.rs
// Module: pm_auth
// Implementations: 0

pub struct BankAccountCredentialsRequest


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

pub fn enable_platform_account(
    state: SessionState,
    merchant_id: id_type::MerchantId,
) -> RouterResponse<()>


// File: crates/common_utils/src/metrics/utils.rs
// Module: common_utils
// Public functions: 2

//! metric utility functions

use std::time;

use router_env::opentelemetry;

/// Record the time taken by the future to execute
#[inline]
pub async fn time_future<F, R>(future: F) -> (R, time::Duration)
where
    F: futures::Future<Output = R>,
{
    let start = time::Instant::now();
    let result = future.await;
    let time_spent = start.elapsed();
    (result, time_spent)
}

/// Record the time taken (in seconds) by the operation for the given context
#[inline]
pub async fn record_operation_time<F, R>(
    future: F,
    metric: &opentelemetry::metrics::Histogram<f64>,
    key_value: &[opentelemetry::KeyValue],
) -> R
where
    F: futures::Future<Output = R>,
{
    let (result, time) = time_future(future).await;
    metric.record(time.as_secs_f64(), key_value);
    result
}


// Function: kv_wrapper
// File: crates/storage_impl/src/redis/kv_store.rs
// Module: storage_impl

pub fn kv_wrapper<'a, T, D, S>(
    store: &KVRouterStore<D>,
    op: KvOperation<'a, S>,
    partition_key: PartitionKey<'a>,
) -> CustomResult<KvResult<T>, RedisError>
where
    T: de::DeserializeOwned,
    D: crate::database::store::DatabaseStore,
    S: serde::Serialize + Debug + KvStorePartition + UniqueConstraints + Sync,


// Struct: EpsRedirectionResponse
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EpsRedirectionResponse


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

pub fn routing_unlink_config()


// Struct: RefundResponseData
// File: crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponseData


// Struct: DisputesAggregateResponse
// File: crates/api_models/src/disputes.rs
// Module: api_models
// Implementations: 0

pub struct DisputesAggregateResponse


// File: crates/api_models/src/poll.rs
// Module: api_models
// Public structs: 1

use common_utils::events::{ApiEventMetric, ApiEventsType};
use serde::Serialize;
use utoipa::ToSchema;

#[derive(Debug, ToSchema, Clone, Serialize)]
pub struct PollResponse {
    /// The poll id
    pub poll_id: String,
    /// Status of the poll
    pub status: PollStatus,
}

#[derive(Debug, strum::Display, strum::EnumString, Clone, serde::Serialize, ToSchema)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum PollStatus {
    Pending,
    Completed,
    NotFound,
}

impl ApiEventMetric for PollResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Poll {
            poll_id: self.poll_id.clone(),
        })
    }
}


// Function: sdk_events_core
// File: crates/analytics/src/sdk_events/core.rs
// Module: analytics

pub fn sdk_events_core(
    pool: &AnalyticsProvider,
    req: SdkEventsRequest,
    publishable_key: &String,
) -> AnalyticsResult<Vec<SdkEventsResult>>


// Function: diesel_enum_db_enum_derive_inner
// File: crates/router_derive/src/macros/diesel.rs
// Module: router_derive

pub fn diesel_enum_db_enum_derive_inner(ast: &DeriveInput) -> syn::Result<TokenStream>


// Function: number_array_value
// File: crates/euclid/src/frontend/ast/parser.rs
// Module: euclid

pub fn number_array_value(input: &str) -> ParseResult<&str, ast::ValueType>


// Struct: RevenueRecoveryDataBackfillResponse
// File: crates/api_models/src/revenue_recovery_data_backfill.rs
// Module: api_models
// Implementations: 1
// Traits: ApiEventMetric

pub struct RevenueRecoveryDataBackfillResponse


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

impl ApiKeys


// Struct: CustomerPaymentMethodListResponse
// File: crates/router/src/compatibility/stripe/customers/types.rs
// Module: router
// Implementations: 0

pub struct CustomerPaymentMethodListResponse


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

impl api::PaymentCapture for for Barclaycard


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

impl api::PaymentToken for for Jpmorgan


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

impl behaviour::Conversion for for MerchantConnectorAccount


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

pub struct AuthenticationData


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

impl Shift4


// Struct: AuthenticationResponse
// File: crates/hyperswitch_connectors/src/connectors/netcetera/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AuthenticationResponse


// Struct: Customer
// File: crates/hyperswitch_domain_models/src/customer.rs
// Module: hyperswitch_domain_models
// Implementations: 3
// Traits: behaviour::Conversion, behaviour::Conversion

pub struct Customer


// Function: get_billing_handler
// File: crates/router/src/core/subscription.rs
// Module: router

pub fn get_billing_handler(
        &self,
        customer: hyperswitch_domain_models::customer::Customer,
    ) -> errors::RouterResult<BillingHandler>


// File: crates/hyperswitch_domain_models/src/router_flow_types/mandate_revoke.rs
// Module: hyperswitch_domain_models
// Public structs: 1

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


// Implementation: impl KVRouterStore
// File: crates/storage_impl/src/kv_router_store.rs
// Module: storage_impl
// Methods: 9 total (3 public)

impl KVRouterStore


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

pub struct VerifyWebhookSource


// Function: check_if_profile_id_is_present_in_payment_intent
// File: crates/router/src/core/verification/utils.rs
// Module: router

pub fn check_if_profile_id_is_present_in_payment_intent(
    payment_id: PaymentId,
    state: &SessionState,
    auth_data: &AuthenticationData,
) -> CustomResult<(), errors::ApiErrorResponse>


// Struct: TransactionFailedRequest
// File: crates/hyperswitch_connectors/src/connectors/riskified/transformers/api.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TransactionFailedRequest


// File: crates/router/src/core/unified_authentication_service/utils.rs
// Module: router
// Public functions: 5

use std::marker::PhantomData;

use common_enums::enums::PaymentMethod;
use common_utils::ext_traits::{AsyncExt, ValueExt};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    errors::api_error_response::ApiErrorResponse,
    ext_traits::OptionExt,
    payment_address::PaymentAddress,
    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
    router_data_v2::UasFlowData,
    router_request_types::unified_authentication_service::UasAuthenticationResponseData,
};
use masking::ExposeInterface;

use super::types::{
    IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW,
    IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW,
};
use crate::{
    consts::DEFAULT_SESSION_EXPIRY,
    core::{
        errors::{utils::ConnectorErrorExt, RouterResult},
        payments,
    },
    services::{self, execute_connector_processing_step},
    types::{api, transformers::ForeignFrom},
    SessionState,
};

pub async 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, UasFlowData, Req, Res>,
{
    let connector_data =
        api::AuthenticationConnectorData::get_connector_by_name(&authentication_connector_name)?;
    let connector_integration: services::BoxedUnifiedAuthenticationServiceInterface<F, Req, Res> =
        connector_data.connector.get_connector_integration();
    let router_data = execute_connector_processing_step(
        state,
        connector_integration,
        &router_data,
        payments::CallConnectorAction::Trigger,
        None,
        None,
    )
    .await
    .to_payment_failed_response()?;
    Ok(router_data)
}

#[allow(clippy::too_many_arguments)]
pub fn construct_uas_router_data<F: Clone, Req, Res>(
    state: &SessionState,
    authentication_connector_name: String,
    payment_method: PaymentMethod,
    merchant_id: common_utils::id_type::MerchantId,
    address: Option<PaymentAddress>,
    request_data: Req,
    merchant_connector_account: &payments::helpers::MerchantConnectorAccountType,
    authentication_id: Option<common_utils::id_type::AuthenticationId>,
    payment_id: Option<common_utils::id_type::PaymentId>,
) -> RouterResult<RouterData<F, Req, Res>> {
    let auth_type: ConnectorAuthType = merchant_connector_account
        .get_connector_account_details()
        .parse_value("ConnectorAuthType")
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Error while parsing ConnectorAuthType")?;
    Ok(RouterData {
        flow: PhantomData,
        merchant_id,
        customer_id: None,
        connector_customer: None,
        connector: authentication_connector_name,
        payment_id: payment_id
            .map(|id| id.get_string_repr().to_owned())
            .unwrap_or_default(),
        tenant_id: state.tenant.tenant_id.clone(),
        attempt_id: IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW.to_owned(),
        status: common_enums::AttemptStatus::default(),
        payment_method,
        connector_auth_type: auth_type,
        description: None,
        address: address.unwrap_or_default(),
        auth_type: common_enums::AuthenticationType::default(),
        connector_meta_data: merchant_connector_account.get_metadata().clone(),
        connector_wallets_details: merchant_connector_account.get_connector_wallets_details(),
        amount_captured: None,
        minor_amount_captured: None,
        access_token: None,
        session_token: None,
        reference_id: None,
        payment_method_token: None,
        recurring_mandate_payment_data: None,
        preprocessing_id: None,
        payment_method_balance: None,
        connector_api_version: None,
        request: request_data,
        response: Err(ErrorResponse::default()),
        connector_request_reference_id:
            IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW.to_owned(),
        #[cfg(feature = "payouts")]
        payout_method_data: None,
        #[cfg(feature = "payouts")]
        quote_id: None,
        test_mode: None,
        connector_http_status_code: None,
        external_latency: None,
        apple_pay_flow: None,
        frm_metadata: None,
        dispute_id: None,
        refund_id: None,
        payment_method_status: None,
        connector_response: None,
        integrity_check: Ok(()),
        additional_merchant_data: None,
        header_payload: None,
        connector_mandate_request_reference_id: None,
        authentication_id,
        psd2_sca_exemption_type: None,
        raw_connector_response: None,
        is_payment_id_from_merchant: None,
        l2_l3_data: None,
        minor_amount_capturable: None,
    })
}

#[allow(clippy::too_many_arguments)]
pub async fn external_authentication_update_trackers<F: Clone, Req>(
    state: &SessionState,
    router_data: RouterData<F, Req, UasAuthenticationResponseData>,
    authentication: diesel_models::authentication::Authentication,
    acquirer_details: Option<
        hyperswitch_domain_models::router_request_types::authentication::AcquirerDetails,
    >,
    merchant_key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
    billing_address: Option<common_utils::encryption::Encryption>,
    shipping_address: Option<common_utils::encryption::Encryption>,
    email: Option<common_utils::encryption::Encryption>,
    browser_info: Option<serde_json::Value>,
) -> RouterResult<diesel_models::authentication::Authentication> {
    let authentication_update = match router_data.response {
        Ok(response) => match response {
            UasAuthenticationResponseData::PreAuthentication {
                authentication_details,
            } => Ok(
                diesel_models::authentication::AuthenticationUpdate::PreAuthenticationUpdate {
                    threeds_server_transaction_id: authentication_details
                        .threeds_server_transaction_id
                        .ok_or(ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "missing threeds_server_transaction_id in PreAuthentication Details",
                        )?,
                    maximum_supported_3ds_version: authentication_details
                        .maximum_supported_3ds_version
                        .ok_or(ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "missing maximum_supported_3ds_version in PreAuthentication Details",
                        )?,
                    connector_authentication_id: authentication_details
                        .connector_authentication_id
                        .ok_or(ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "missing connector_authentication_id in PreAuthentication Details",
                        )?,
                    three_ds_method_data: authentication_details.three_ds_method_data,
                    three_ds_method_url: authentication_details.three_ds_method_url,
                    message_version: authentication_details
                        .message_version
                        .ok_or(ApiErrorResponse::InternalServerError)
                        .attach_printable("missing message_version in PreAuthentication Details")?,
                    connector_metadata: authentication_details.connector_metadata,
                    authentication_status: common_enums::AuthenticationStatus::Pending,
                    acquirer_bin: acquirer_details
                        .as_ref()
                        .map(|acquirer_details| acquirer_details.acquirer_bin.clone()),
                    acquirer_merchant_id: acquirer_details
                        .as_ref()
                        .map(|acquirer_details| acquirer_details.acquirer_merchant_id.clone()),
                    acquirer_country_code: acquirer_details
                        .and_then(|acquirer_details| acquirer_details.acquirer_country_code),
                    directory_server_id: authentication_details.directory_server_id,
                    browser_info: Box::new(browser_info),
                    email,
                    billing_address,
                    shipping_address,
                },
            ),
            UasAuthenticationResponseData::Authentication {
                authentication_details,
            } => {
                let authentication_status = common_enums::AuthenticationStatus::foreign_from(
                    authentication_details.trans_status.clone(),
                );
                authentication_details
                    .authentication_value
                    .async_map(|auth_val| {
                        crate::core::payment_methods::vault::create_tokenize(
                            state,
                            auth_val.expose(),
                            None,
                            authentication
                                .authentication_id
                                .get_string_repr()
                                .to_string(),
                            merchant_key_store.key.get_inner(),
                        )
                    })
                    .await
                    .transpose()?;
                Ok(
                    diesel_models::authentication::AuthenticationUpdate::AuthenticationUpdate {
                        trans_status: authentication_details.trans_status,
                        acs_url: authentication_details.authn_flow_type.get_acs_url(),
                        challenge_request: authentication_details
                            .authn_flow_type
                            .get_challenge_request(),
                        challenge_request_key: authentication_details
                            .authn_flow_type
                            .get_challenge_request_key(),
                        acs_reference_number: authentication_details
                            .authn_flow_type
                            .get_acs_reference_number(),
                        acs_trans_id: authentication_details.authn_flow_type.get_acs_trans_id(),
                        acs_signed_content: authentication_details
                            .authn_flow_type
                            .get_acs_signed_content(),
                        authentication_type: authentication_details
                            .authn_flow_type
                            .get_decoupled_authentication_type(),
                        authentication_status,
                        connector_metadata: authentication_details.connector_metadata,
                        ds_trans_id: authentication_details.ds_trans_id,
                        eci: authentication_details.eci,
                        challenge_code: authentication_details.challenge_code,
                        challenge_cancel: authentication_details.challenge_cancel,
                        challenge_code_reason: authentication_details.challenge_code_reason,
                        message_extension: authentication_details.message_extension,
                    },
                )
            }
            UasAuthenticationResponseData::PostAuthentication {
                authentication_details,
            } => {
                let trans_status = authentication_details
                    .trans_status
                    .ok_or(ApiErrorResponse::InternalServerError)
                    .attach_printable("missing trans_status in PostAuthentication Details")?;

                authentication_details
                    .dynamic_data_details
                    .and_then(|details| details.dynamic_data_value)
                    .map(ExposeInterface::expose)
                    .async_map(|auth_val| {
                        crate::core::payment_methods::vault::create_tokenize(
                            state,
                            auth_val,
                            None,
                            authentication
                                .authentication_id
                                .get_string_repr()
                                .to_string(),
                            merchant_key_store.key.get_inner(),
                        )
                    })
                    .await
                    .transpose()?;
                Ok(
                    diesel_models::authentication::AuthenticationUpdate::PostAuthenticationUpdate {
                        authentication_status: common_enums::AuthenticationStatus::foreign_from(
                            trans_status.clone(),
                        ),
                        trans_status,
                        eci: authentication_details.eci,
                        challenge_cancel: authentication_details.challenge_cancel,
                        challenge_code_reason: authentication_details.challenge_code_reason,
                    },
                )
            }

            UasAuthenticationResponseData::Confirmation { .. } => Err(
                ApiErrorResponse::InternalServerError,
            )
            .attach_printable("unexpected api confirmation in external authentication flow."),
        },
        Err(error) => Ok(
            diesel_models::authentication::AuthenticationUpdate::ErrorUpdate {
                connector_authentication_id: error.connector_transaction_id,
                authentication_status: common_enums::AuthenticationStatus::Failed,
                error_message: error
                    .reason
                    .map(|reason| format!("message: {}, reason: {}", error.message, reason))
                    .or(Some(error.message)),
                error_code: Some(error.code),
            },
        ),
    }?;

    state
        .store
        .update_authentication_by_merchant_id_authentication_id(
            authentication,
            authentication_update,
        )
        .await
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Error while updating authentication")
}

pub fn get_checkout_event_status_and_reason(
    attempt_status: common_enums::AttemptStatus,
) -> (Option<String>, Option<String>) {
    match attempt_status {
        common_enums::AttemptStatus::Charged | common_enums::AttemptStatus::Authorized => (
            Some("01".to_string()),
            Some("The payment was successful".to_string()),
        ),
        _ => (
            Some("03".to_string()),
            Some("The payment was not successful".to_string()),
        ),
    }
}

pub fn authenticate_authentication_client_secret_and_check_expiry(
    req_client_secret: &String,
    authentication: &diesel_models::authentication::Authentication,
) -> RouterResult<()> {
    let stored_client_secret = authentication
        .authentication_client_secret
        .clone()
        .get_required_value("authentication_client_secret")
        .change_context(ApiErrorResponse::MissingRequiredField {
            field_name: "client_secret",
        })
        .attach_printable("client secret not found in db")?;

    if req_client_secret != &stored_client_secret {
        Err(report!(ApiErrorResponse::ClientSecretInvalid))
    } else {
        let current_timestamp = common_utils::date_time::now();
        let session_expiry = authentication
            .created_at
            .saturating_add(time::Duration::seconds(DEFAULT_SESSION_EXPIRY));

        if current_timestamp > session_expiry {
            Err(report!(ApiErrorResponse::ClientSecretExpired))
        } else {
            Ok(())
        }
    }
}


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

pub struct CybersourceConsumerAuthInformationValidateRequest


// Struct: PhonepeCard
// File: crates/hyperswitch_connectors/src/connectors/phonepe/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PhonepeCard


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

pub fn server(config: AppState) -> Scope


// Implementation: impl super::behaviour::Conversion for for Tokenization
// File: crates/hyperswitch_domain_models/src/tokenization.rs
// Module: hyperswitch_domain_models
// Methods: 3 total (0 public)

impl super::behaviour::Conversion for for Tokenization


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

pub struct StripebillingWebhookLinesData


// Struct: TsysSyncRequest
// File: crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TsysSyncRequest


// Implementation: impl ProfileWrapper
// File: crates/router/src/core/admin.rs
// Module: router
// Methods: 8 total (4 public)

impl ProfileWrapper


// Implementation: impl DieselDeriveInputExt for for DeriveInput
// File: crates/router_derive/src/macros/diesel.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl DieselDeriveInputExt for for DeriveInput


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

pub fn get_card_from_locker(
    state: &routes::SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    card_reference: &str,
) -> errors::RouterResult<Card>


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

pub struct GetSdkEventFiltersRequest


// Struct: PaymentFields
// File: crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentFields


// Function: get_role_info
// File: crates/router/src/services/authorization.rs
// Module: router

pub fn get_role_info<A>(state: &A, token: &AuthToken) -> RouterResult<roles::RoleInfo>
where
    A: SessionStateInfo + Sync,


// Implementation: impl ApplePayPredecryptDataInternal
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models
// Methods: 2 total (0 public)

impl ApplePayPredecryptDataInternal


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

pub fn should_call_payout_connector_create_customer<'a>(
    state: &'a SessionState,
    connector: &'a api::ConnectorData,
    customer: &'a Option<domain::Customer>,
    merchant_connector_id: &'a domain::MerchantConnectorAccountTypeDetails,
) -> (bool, Option<&'a str>)


// Struct: TokenizedCardValue1
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct TokenizedCardValue1


// Function: sync_onboarding_status
// File: crates/router/src/routes/connector_onboarding.rs
// Module: router

pub fn sync_onboarding_status(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<api_types::OnboardingSyncRequest>,
) -> HttpResponse


// Struct: Rule
// File: crates/euclid/src/frontend/ast.rs
// Module: euclid
// Implementations: 0

pub struct Rule<O>


// Struct: ApiMetricsBucketResponse
// File: crates/api_models/src/analytics/api_event.rs
// Module: api_models
// Implementations: 0

pub struct ApiMetricsBucketResponse


// Struct: ActivePaymentsMetricsBucketValue
// File: crates/api_models/src/analytics/active_payments.rs
// Module: api_models
// Implementations: 0

pub struct ActivePaymentsMetricsBucketValue


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

pub struct BarclaycardConsumerAuthInformation


// File: crates/router/src/routes/dummy_connector/core.rs
// Module: router
// Public functions: 6

use app::SessionState;
use common_utils::generate_id_with_default_len;
use error_stack::ResultExt;

use super::{errors, types, utils};
use crate::{
    routes::{app, dummy_connector::consts},
    services::api,
    utils::OptionExt,
};

#[cfg(feature = "dummy_connector")]
pub async fn payment(
    state: SessionState,
    req: types::DummyConnectorPaymentRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorPaymentResponse> {
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.payment_duration,
        state.conf.dummy_connector.payment_tolerance,
    )
    .await;

    let payment_attempt: types::DummyConnectorPaymentAttempt = req.into();
    let payment_data =
        types::DummyConnectorPaymentData::process_payment_attempt(&state, payment_attempt)?;

    utils::store_data_in_redis(
        &state,
        payment_data.attempt_id.clone(),
        payment_data.payment_id.clone(),
        state.conf.dummy_connector.authorize_ttl,
    )
    .await?;
    utils::store_data_in_redis(
        &state,
        payment_data.payment_id.get_string_repr().to_owned(),
        payment_data.clone(),
        state.conf.dummy_connector.payment_ttl,
    )
    .await?;
    Ok(api::ApplicationResponse::Json(payment_data.into()))
}

pub async fn payment_data(
    state: SessionState,
    req: types::DummyConnectorPaymentRetrieveRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorPaymentResponse> {
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.payment_retrieve_duration,
        state.conf.dummy_connector.payment_retrieve_tolerance,
    )
    .await;

    let payment_data = utils::get_payment_data_from_payment_id(&state, req.payment_id).await?;
    Ok(api::ApplicationResponse::Json(payment_data.into()))
}

#[cfg(all(feature = "dummy_connector", feature = "v1"))]
pub async fn payment_authorize(
    state: SessionState,
    req: types::DummyConnectorPaymentConfirmRequest,
) -> types::DummyConnectorResponse<String> {
    let payment_data = utils::get_payment_data_by_attempt_id(&state, req.attempt_id.clone()).await;
    let dummy_connector_conf = &state.conf.dummy_connector;

    if let Ok(payment_data_inner) = payment_data {
        let return_url = format!(
            "{}/dummy-connector/complete/{}",
            state.base_url, req.attempt_id
        );
        Ok(api::ApplicationResponse::FileData((
            utils::get_authorize_page(payment_data_inner, return_url, dummy_connector_conf)
                .as_bytes()
                .to_vec(),
            mime::TEXT_HTML,
        )))
    } else {
        Ok(api::ApplicationResponse::FileData((
            utils::get_expired_page(dummy_connector_conf)
                .as_bytes()
                .to_vec(),
            mime::TEXT_HTML,
        )))
    }
}

#[cfg(all(feature = "dummy_connector", feature = "v1"))]
pub async fn payment_complete(
    state: SessionState,
    req: types::DummyConnectorPaymentCompleteRequest,
) -> types::DummyConnectorResponse<()> {
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.payment_duration,
        state.conf.dummy_connector.payment_tolerance,
    )
    .await;

    let payment_data = utils::get_payment_data_by_attempt_id(&state, req.attempt_id.clone()).await;

    let payment_status = if req.confirm {
        types::DummyConnectorStatus::Succeeded
    } else {
        types::DummyConnectorStatus::Failed
    };

    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::DummyConnectorErrors::InternalServerError)
        .attach_printable("Failed to get redis connection")?;

    let _ = redis_conn.delete_key(&req.attempt_id.as_str().into()).await;

    if let Ok(payment_data) = payment_data {
        let updated_payment_data = types::DummyConnectorPaymentData {
            status: payment_status,
            next_action: None,
            ..payment_data
        };
        utils::store_data_in_redis(
            &state,
            updated_payment_data.payment_id.get_string_repr().to_owned(),
            updated_payment_data.clone(),
            state.conf.dummy_connector.payment_ttl,
        )
        .await?;
        return Ok(api::ApplicationResponse::JsonForRedirection(
            api_models::payments::RedirectionResponse {
                return_url: String::new(),
                params: vec![],
                return_url_with_query_params: updated_payment_data
                    .return_url
                    .unwrap_or(state.conf.dummy_connector.default_return_url.clone()),
                http_method: "GET".to_string(),
                headers: vec![],
            },
        ));
    }
    Ok(api::ApplicationResponse::JsonForRedirection(
        api_models::payments::RedirectionResponse {
            return_url: String::new(),
            params: vec![],
            return_url_with_query_params: state.conf.dummy_connector.default_return_url.clone(),
            http_method: "GET".to_string(),
            headers: vec![],
        },
    ))
}

#[cfg(all(feature = "dummy_connector", feature = "v1"))]
pub async fn refund_payment(
    state: SessionState,
    req: types::DummyConnectorRefundRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorRefundResponse> {
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.refund_duration,
        state.conf.dummy_connector.refund_tolerance,
    )
    .await;

    let payment_id = req
        .payment_id
        .get_required_value("payment_id")
        .change_context(errors::DummyConnectorErrors::MissingRequiredField {
            field_name: "payment_id",
        })?;

    let mut payment_data =
        utils::get_payment_data_from_payment_id(&state, payment_id.get_string_repr().to_owned())
            .await?;

    payment_data.is_eligible_for_refund(req.amount)?;

    let refund_id = generate_id_with_default_len(consts::REFUND_ID_PREFIX);
    payment_data.eligible_amount -= req.amount;

    utils::store_data_in_redis(
        &state,
        payment_id.get_string_repr().to_owned(),
        payment_data.to_owned(),
        state.conf.dummy_connector.payment_ttl,
    )
    .await?;

    let refund_data = types::DummyConnectorRefundResponse::new(
        types::DummyConnectorStatus::Succeeded,
        refund_id.to_owned(),
        payment_data.currency,
        common_utils::date_time::now(),
        payment_data.amount,
        req.amount,
    );

    utils::store_data_in_redis(
        &state,
        refund_id,
        refund_data.to_owned(),
        state.conf.dummy_connector.refund_ttl,
    )
    .await?;
    Ok(api::ApplicationResponse::Json(refund_data))
}

#[cfg(all(feature = "dummy_connector", feature = "v1"))]
pub async fn refund_data(
    state: SessionState,
    req: types::DummyConnectorRefundRetrieveRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorRefundResponse> {
    let refund_id = req.refund_id;
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.refund_retrieve_duration,
        state.conf.dummy_connector.refund_retrieve_tolerance,
    )
    .await;

    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::DummyConnectorErrors::InternalServerError)
        .attach_printable("Failed to get redis connection")?;
    let refund_data = redis_conn
        .get_and_deserialize_key::<types::DummyConnectorRefundResponse>(
            &refund_id.as_str().into(),
            "DummyConnectorRefundResponse",
        )
        .await
        .change_context(errors::DummyConnectorErrors::RefundNotFound)?;
    Ok(api::ApplicationResponse::Json(refund_data))
}


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

impl PaymentSync for for Plaid


// Struct: FacilitapayRefundResponse
// File: crates/hyperswitch_connectors/src/connectors/facilitapay/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FacilitapayRefundResponse


// Implementation: impl Riskified
// File: crates/hyperswitch_connectors/src/connectors/riskified.rs
// Module: hyperswitch_connectors
// Methods: 2 total (2 public)

impl Riskified


// Function: update_with_specific_fields
// File: crates/diesel_models/src/query/merchant_account.rs
// Module: diesel_models

pub fn update_with_specific_fields(
        conn: &PgPooledConn,
        identifier: &common_utils::id_type::MerchantId,
        merchant_account: MerchantAccountUpdateInternal,
    ) -> StorageResult<Self>


// Module Structure
// File: crates/injector/src/types.rs
// Module: injector

// Public exports:
pub use models::*;


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

pub fn create_platform_account(
    state: SessionState,
    user_from_token: auth::UserFromToken,
    req: user_api::PlatformAccountCreateRequest,
) -> UserResponse<user_api::PlatformAccountCreateResponse>


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

pub fn get_id(&self) -> Option<id_type::MerchantConnectorAccountId>


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

impl RetrieveFile for for Checkout


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

pub struct OrderInformation


// Struct: DisputeNew
// File: crates/diesel_models/src/dispute.rs
// Module: diesel_models
// Implementations: 0

pub struct DisputeNew


// Implementation: impl std::fmt::Debug for for Maskable
// File: crates/masking/src/maskable.rs
// Module: masking
// Methods: 1 total (0 public)

impl std::fmt::Debug for for Maskable


// Implementation: impl AdminApiAuthWithApiKeyFallbackAndMerchantIdFromRoute
// File: crates/router/src/services/authentication.rs
// Module: router
// Methods: 1 total (0 public)

impl AdminApiAuthWithApiKeyFallbackAndMerchantIdFromRoute


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

pub fn new() -> &'static Self


// Struct: ThreeDSecureResData
// File: crates/hyperswitch_connectors/src/connectors/dlocal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ThreeDSecureResData


// Function: get_routing_events
// File: crates/analytics/src/routing_events/events.rs
// Module: analytics

pub fn get_routing_events<T>(
    merchant_id: &common_utils::id_type::MerchantId,
    query_param: RoutingEventsRequest,
    pool: &T,
) -> FiltersResult<Vec<RoutingEventsResult>>
where
    T: AnalyticsDataSource + RoutingEventLogAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,


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

impl Cryptopay


// Implementation: impl State for for PmTokenStored
// File: crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
// Module: router
// Methods: 0 total (0 public)

impl State for for PmTokenStored


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

impl api::PaymentSession for for Jpmorgan


// Struct: IssuerData
// File: crates/api_models/src/three_ds_decision_rule.rs
// Module: api_models
// Implementations: 0

pub struct IssuerData


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

pub fn new() -> &'static Self


// Struct: CardDetailsAssigned
// File: crates/router/src/core/payment_methods/tokenize/card_executor.rs
// Module: router
// Implementations: 1
// Traits: State

pub struct CardDetailsAssigned


// File: crates/api_models/src/analytics/refunds.rs
// Module: api_models
// Public functions: 1
// Public structs: 10

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

use common_utils::id_type;

use crate::enums::{Currency, RefundStatus};

#[derive(
    Clone,
    Copy,
    Debug,
    Hash,
    Eq,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
)]
// TODO RefundType api_models_oss need to mapped to storage_model
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RefundType {
    InstantRefund,
    RegularRefund,
    RetryRefund,
}

use super::{ForexMetric, NameDescription, TimeRange};
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct RefundFilters {
    #[serde(default)]
    pub currency: Vec<Currency>,
    #[serde(default)]
    pub refund_status: Vec<RefundStatus>,
    #[serde(default)]
    pub connector: Vec<String>,
    #[serde(default)]
    pub refund_type: Vec<RefundType>,
    #[serde(default)]
    pub profile_id: Vec<id_type::ProfileId>,
    #[serde(default)]
    pub refund_reason: Vec<String>,
    #[serde(default)]
    pub refund_error_message: Vec<String>,
}

#[derive(
    Debug,
    serde::Serialize,
    serde::Deserialize,
    strum::AsRefStr,
    PartialEq,
    PartialOrd,
    Eq,
    Ord,
    strum::Display,
    strum::EnumIter,
    Clone,
    Copy,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RefundDimensions {
    Currency,
    RefundStatus,
    Connector,
    RefundType,
    ProfileId,
    RefundReason,
    RefundErrorMessage,
}

#[derive(
    Clone,
    Debug,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumIter,
    strum::AsRefStr,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum RefundMetrics {
    RefundSuccessRate,
    RefundCount,
    RefundSuccessCount,
    RefundProcessedAmount,
    SessionizedRefundSuccessRate,
    SessionizedRefundCount,
    SessionizedRefundSuccessCount,
    SessionizedRefundProcessedAmount,
    SessionizedRefundReason,
    SessionizedRefundErrorMessage,
}

#[derive(Debug, Default, serde::Serialize)]
pub struct ReasonsResult {
    pub reason: String,
    pub count: i64,
    pub percentage: f64,
}

#[derive(Debug, Default, serde::Serialize)]
pub struct ErrorMessagesResult {
    pub error_message: String,
    pub count: i64,
    pub percentage: f64,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumIter,
    strum::AsRefStr,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum RefundDistributions {
    #[strum(serialize = "refund_reason")]
    SessionizedRefundReason,
    #[strum(serialize = "refund_error_message")]
    SessionizedRefundErrorMessage,
}
impl ForexMetric for RefundMetrics {
    fn is_forex_metric(&self) -> bool {
        matches!(
            self,
            Self::RefundProcessedAmount | Self::SessionizedRefundProcessedAmount
        )
    }
}

pub mod metric_behaviour {
    pub struct RefundSuccessRate;
    pub struct RefundCount;
    pub struct RefundSuccessCount;
    pub struct RefundProcessedAmount;
}

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

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

#[derive(Debug, serde::Serialize, Eq)]
pub struct RefundMetricsBucketIdentifier {
    pub currency: Option<Currency>,
    pub refund_status: Option<String>,
    pub connector: Option<String>,
    pub refund_type: Option<String>,
    pub profile_id: Option<String>,
    pub refund_reason: Option<String>,
    pub refund_error_message: Option<String>,
    #[serde(rename = "time_range")]
    pub time_bucket: TimeRange,
    #[serde(rename = "time_bucket")]
    #[serde(with = "common_utils::custom_serde::iso8601custom")]
    pub start_time: time::PrimitiveDateTime,
}

impl Hash for RefundMetricsBucketIdentifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.currency.hash(state);
        self.refund_status.hash(state);
        self.connector.hash(state);
        self.refund_type.hash(state);
        self.profile_id.hash(state);
        self.refund_reason.hash(state);
        self.refund_error_message.hash(state);
        self.time_bucket.hash(state);
    }
}
impl PartialEq for RefundMetricsBucketIdentifier {
    fn eq(&self, other: &Self) -> bool {
        let mut left = DefaultHasher::new();
        self.hash(&mut left);
        let mut right = DefaultHasher::new();
        other.hash(&mut right);
        left.finish() == right.finish()
    }
}

impl RefundMetricsBucketIdentifier {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        currency: Option<Currency>,
        refund_status: Option<String>,
        connector: Option<String>,
        refund_type: Option<String>,
        profile_id: Option<String>,
        refund_reason: Option<String>,
        refund_error_message: Option<String>,
        normalized_time_range: TimeRange,
    ) -> Self {
        Self {
            currency,
            refund_status,
            connector,
            refund_type,
            profile_id,
            refund_reason,
            refund_error_message,
            time_bucket: normalized_time_range,
            start_time: normalized_time_range.start_time,
        }
    }
}
#[derive(Debug, serde::Serialize)]
pub struct RefundMetricsBucketValue {
    pub successful_refunds: Option<u32>,
    pub total_refunds: Option<u32>,
    pub refund_success_rate: Option<f64>,
    pub refund_count: Option<u64>,
    pub refund_success_count: Option<u64>,
    pub refund_processed_amount: Option<u64>,
    pub refund_processed_amount_in_usd: Option<u64>,
    pub refund_processed_count: Option<u64>,
    pub refund_reason_distribution: Option<Vec<ReasonsResult>>,
    pub refund_error_message_distribution: Option<Vec<ErrorMessagesResult>>,
    pub refund_reason_count: Option<u64>,
    pub refund_error_message_count: Option<u64>,
}
#[derive(Debug, serde::Serialize)]
pub struct RefundMetricsBucketResponse {
    #[serde(flatten)]
    pub values: RefundMetricsBucketValue,
    #[serde(flatten)]
    pub dimensions: RefundMetricsBucketIdentifier,
}


// Implementation: impl api::ConnectorAccessToken for for Loonio
// File: crates/hyperswitch_connectors/src/connectors/loonio.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Loonio


// Function: tenant_aware_key
// File: crates/redis_interface/src/types.rs
// Module: redis_interface

pub fn tenant_aware_key(&self, pool: &RedisConnectionPool) -> String


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

pub fn organization_retrieve()


// Function: remove_entry_from_blocklist
// File: crates/router/src/core/blocklist.rs
// Module: router

pub fn remove_entry_from_blocklist(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    body: api_blocklist::DeleteFromBlocklistRequest,
) -> RouterResponse<api_blocklist::DeleteFromBlocklistResponse>


// Struct: StorageSubscription
// File: crates/router_env/src/logger/storage.rs
// Module: router_env
// Implementations: 0

pub struct StorageSubscription


// Struct: Execute
// File: crates/hyperswitch_domain_models/src/router_flow_types/refunds.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct Execute


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

pub fn new() -> &'static Self


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

pub struct FrmPaymentMethod