// File: crates/api_models/src/api_keys.rs

use common_utils::custom_serde;
use masking::StrongSecret;
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;

/// The request body for creating an API Key.
#[derive(Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CreateApiKeyRequest {
    /// A unique name for the API Key to help you identify it.
    #[schema(max_length = 64, example = "Sandbox integration key")]
    pub name: String,

    /// A description to provide more context about the API Key.
    #[schema(
        max_length = 256,
        example = "Key used by our developers to integrate with the sandbox environment"
    )]
    pub description: Option<String>,

    /// An expiration date for the API Key. Although we allow keys to never expire, we recommend
    /// rotating your keys once every 6 months.
    #[schema(example = "2022-09-10T10:11:12Z")]
    pub expiration: ApiKeyExpiration,
}

/// The response body for creating an API Key.
#[derive(Debug, Serialize, ToSchema)]
pub struct CreateApiKeyResponse {
    /// The identifier for the API Key.
    #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
    pub key_id: common_utils::id_type::ApiKeyId,

    /// The identifier for the Merchant Account.
    #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,

    /// The unique name for the API Key to help you identify it.
    #[schema(max_length = 64, example = "Sandbox integration key")]
    pub name: String,

    /// The description to provide more context about the API Key.
    #[schema(
        max_length = 256,
        example = "Key used by our developers to integrate with the sandbox environment"
    )]
    pub description: Option<String>,

    /// The plaintext API Key used for server-side API access. Ensure you store the API Key
    /// securely as you will not be able to see it again.
    #[schema(value_type = String, max_length = 128)]
    pub api_key: StrongSecret<String>,

    /// The time at which the API Key was created.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created: PrimitiveDateTime,

    /// The expiration date for the API Key.
    #[schema(example = "2022-09-10T10:11:12Z")]
    pub expiration: ApiKeyExpiration,
    /*
    /// The date and time indicating when the API Key was last used.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub last_used: Option<PrimitiveDateTime>,
    */
}

/// The response body for retrieving an API Key.
#[derive(Debug, Serialize, ToSchema)]
pub struct RetrieveApiKeyResponse {
    /// The identifier for the API Key.
    #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
    pub key_id: common_utils::id_type::ApiKeyId,

    /// The identifier for the Merchant Account.
    #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,

    /// The unique name for the API Key to help you identify it.
    #[schema(max_length = 64, example = "Sandbox integration key")]
    pub name: String,

    /// The description to provide more context about the API Key.
    #[schema(
        max_length = 256,
        example = "Key used by our developers to integrate with the sandbox environment"
    )]
    pub description: Option<String>,

    /// The first few characters of the plaintext API Key to help you identify it.
    #[schema(value_type = String, max_length = 64)]
    pub prefix: StrongSecret<String>,

    /// The time at which the API Key was created.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created: PrimitiveDateTime,

    /// The expiration date for the API Key.
    #[schema(example = "2022-09-10T10:11:12Z")]
    pub expiration: ApiKeyExpiration,
    /*
    /// The date and time indicating when the API Key was last used.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub last_used: Option<PrimitiveDateTime>,
    */
}

/// The request body for updating an API Key.
#[derive(Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct UpdateApiKeyRequest {
    /// A unique name for the API Key to help you identify it.
    #[schema(max_length = 64, example = "Sandbox integration key")]
    pub name: Option<String>,

    /// A description to provide more context about the API Key.
    #[schema(
        max_length = 256,
        example = "Key used by our developers to integrate with the sandbox environment"
    )]
    pub description: Option<String>,

    /// An expiration date for the API Key. Although we allow keys to never expire, we recommend
    /// rotating your keys once every 6 months.
    #[schema(example = "2022-09-10T10:11:12Z")]
    pub expiration: Option<ApiKeyExpiration>,

    #[serde(skip_deserializing)]
    #[schema(value_type = String)]
    pub key_id: common_utils::id_type::ApiKeyId,

    #[serde(skip_deserializing)]
    #[schema(value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,
}

/// The response body for revoking an API Key.
#[derive(Debug, Serialize, ToSchema)]
pub struct RevokeApiKeyResponse {
    /// The identifier for the Merchant Account.
    #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,

    /// The identifier for the API Key.
    #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
    pub key_id: common_utils::id_type::ApiKeyId,
    /// Indicates whether the API key was revoked or not.
    #[schema(example = "true")]
    pub revoked: bool,
}

/// The constraints that are applicable when listing API Keys associated with a merchant account.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ListApiKeyConstraints {
    /// The maximum number of API Keys to include in the response.
    pub limit: Option<i64>,

    /// The number of API Keys to skip when retrieving the list of API keys.
    pub skip: Option<i64>,
}

/// The expiration date and time for an API Key.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum ApiKeyExpiration {
    /// The API Key does not expire.
    #[serde(with = "never")]
    Never,

    /// The API Key expires at the specified date and time.
    #[serde(with = "custom_serde::iso8601")]
    DateTime(PrimitiveDateTime),
}

impl From<ApiKeyExpiration> for Option<PrimitiveDateTime> {
    fn from(expiration: ApiKeyExpiration) -> Self {
        match expiration {
            ApiKeyExpiration::Never => None,
            ApiKeyExpiration::DateTime(date_time) => Some(date_time),
        }
    }
}

impl From<Option<PrimitiveDateTime>> for ApiKeyExpiration {
    fn from(date_time: Option<PrimitiveDateTime>) -> Self {
        date_time.map_or(Self::Never, Self::DateTime)
    }
}

// This implementation is required as otherwise, `serde` would serialize and deserialize
// `ApiKeyExpiration::Never` as `null`, which is not preferable.
// Reference: https://github.com/serde-rs/serde/issues/1560#issuecomment-506915291
mod never {
    const NEVER: &str = "never";

    pub fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(NEVER)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct NeverVisitor;

        impl serde::de::Visitor<'_> for NeverVisitor {
            type Value = ();

            fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(f, r#""{NEVER}""#)
            }

            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
                if value == NEVER {
                    Ok(())
                } else {
                    Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
                }
            }
        }

        deserializer.deserialize_str(NeverVisitor)
    }
}

impl<'a> ToSchema<'a> for ApiKeyExpiration {
    fn schema() -> (
        &'a str,
        utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
    ) {
        use utoipa::openapi::{KnownFormat, ObjectBuilder, OneOfBuilder, SchemaFormat, SchemaType};

        (
            "ApiKeyExpiration",
            OneOfBuilder::new()
                .item(
                    ObjectBuilder::new()
                        .schema_type(SchemaType::String)
                        .enum_values(Some(["never"])),
                )
                .item(
                    ObjectBuilder::new()
                        .schema_type(SchemaType::String)
                        .format(Some(SchemaFormat::KnownFormat(KnownFormat::DateTime))),
                )
                .into(),
        )
    }
}

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

    #[test]
    fn test_serialization() {
        assert_eq!(
            serde_json::to_string(&ApiKeyExpiration::Never).unwrap(),
            r#""never""#
        );

        let date = time::Date::from_calendar_date(2022, time::Month::September, 10).unwrap();
        let time = time::Time::from_hms(11, 12, 13).unwrap();
        assert_eq!(
            serde_json::to_string(&ApiKeyExpiration::DateTime(PrimitiveDateTime::new(
                date, time
            )))
            .unwrap(),
            r#""2022-09-10T11:12:13.000Z""#
        );
    }

    #[test]
    fn test_deserialization() {
        assert_eq!(
            serde_json::from_str::<ApiKeyExpiration>(r#""never""#).unwrap(),
            ApiKeyExpiration::Never
        );

        let date = time::Date::from_calendar_date(2022, time::Month::September, 10).unwrap();
        let time = time::Time::from_hms(11, 12, 13).unwrap();
        assert_eq!(
            serde_json::from_str::<ApiKeyExpiration>(r#""2022-09-10T11:12:13.000Z""#).unwrap(),
            ApiKeyExpiration::DateTime(PrimitiveDateTime::new(date, time))
        );
    }

    #[test]
    fn test_null() {
        let result = serde_json::from_str::<ApiKeyExpiration>("null");
        assert!(result.is_err());

        let result = serde_json::from_str::<Option<ApiKeyExpiration>>("null").unwrap();
        assert_eq!(result, None);
    }
}


// File: crates/api_models/src/analytics.rs

use std::collections::HashSet;

pub use common_utils::types::TimeRange;
use common_utils::{events::ApiEventMetric, pii::EmailStrategy, types::authentication::AuthInfo};
use masking::Secret;

use self::{
    active_payments::ActivePaymentsMetrics,
    api_event::{ApiEventDimensions, ApiEventMetrics},
    auth_events::{AuthEventDimensions, AuthEventFilters, AuthEventMetrics},
    disputes::{DisputeDimensions, DisputeMetrics},
    frm::{FrmDimensions, FrmMetrics},
    payment_intents::{PaymentIntentDimensions, PaymentIntentMetrics},
    payments::{PaymentDimensions, PaymentDistributions, PaymentMetrics},
    refunds::{RefundDimensions, RefundDistributions, RefundMetrics},
    sdk_events::{SdkEventDimensions, SdkEventMetrics},
};
pub mod active_payments;
pub mod api_event;
pub mod auth_events;
pub mod connector_events;
pub mod disputes;
pub mod frm;
pub mod outgoing_webhook_event;
pub mod payment_intents;
pub mod payments;
pub mod refunds;
pub mod routing_events;
pub mod sdk_events;
pub mod search;

#[derive(Debug, serde::Serialize)]
pub struct NameDescription {
    pub name: String,
    pub desc: String,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetInfoResponse {
    pub metrics: Vec<NameDescription>,
    pub download_dimensions: Option<Vec<NameDescription>>,
    pub dimensions: Vec<NameDescription>,
}

#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)]
pub struct TimeSeries {
    pub granularity: Granularity,
}

#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)]
pub enum Granularity {
    #[serde(rename = "G_ONEMIN")]
    OneMin,
    #[serde(rename = "G_FIVEMIN")]
    FiveMin,
    #[serde(rename = "G_FIFTEENMIN")]
    FifteenMin,
    #[serde(rename = "G_THIRTYMIN")]
    ThirtyMin,
    #[serde(rename = "G_ONEHOUR")]
    OneHour,
    #[serde(rename = "G_ONEDAY")]
    OneDay,
}
pub trait ForexMetric {
    fn is_forex_metric(&self) -> bool;
}

#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AnalyticsRequest {
    pub payment_intent: Option<GetPaymentIntentMetricRequest>,
    pub payment_attempt: Option<GetPaymentMetricRequest>,
    pub refund: Option<GetRefundMetricRequest>,
    pub dispute: Option<GetDisputeMetricRequest>,
}

impl AnalyticsRequest {
    pub fn requires_forex_functionality(&self) -> bool {
        self.payment_attempt
            .as_ref()
            .map(|req| req.metrics.iter().any(|metric| metric.is_forex_metric()))
            .unwrap_or_default()
            || self
                .payment_intent
                .as_ref()
                .map(|req| req.metrics.iter().any(|metric| metric.is_forex_metric()))
                .unwrap_or_default()
            || self
                .refund
                .as_ref()
                .map(|req| req.metrics.iter().any(|metric| metric.is_forex_metric()))
                .unwrap_or_default()
            || self
                .dispute
                .as_ref()
                .map(|req| req.metrics.iter().any(|metric| metric.is_forex_metric()))
                .unwrap_or_default()
    }
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<PaymentDimensions>,
    #[serde(default)]
    pub filters: payments::PaymentFilters,
    pub metrics: HashSet<PaymentMetrics>,
    pub distribution: Option<PaymentDistributionBody>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)]
pub enum QueryLimit {
    #[serde(rename = "TOP_5")]
    Top5,
    #[serde(rename = "TOP_10")]
    Top10,
}

#[allow(clippy::from_over_into)]
impl Into<u64> for QueryLimit {
    fn into(self) -> u64 {
        match self {
            Self::Top5 => 5,
            Self::Top10 => 10,
        }
    }
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentDistributionBody {
    pub distribution_for: PaymentDistributions,
    pub distribution_cardinality: QueryLimit,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RefundDistributionBody {
    pub distribution_for: RefundDistributions,
    pub distribution_cardinality: QueryLimit,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReportRequest {
    pub time_range: TimeRange,
    pub emails: Option<Vec<Secret<String, EmailStrategy>>>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GenerateReportRequest {
    pub request: ReportRequest,
    pub merchant_id: Option<common_utils::id_type::MerchantId>,
    pub auth: AuthInfo,
    pub email: Secret<String, EmailStrategy>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentIntentMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<PaymentIntentDimensions>,
    #[serde(default)]
    pub filters: payment_intents::PaymentIntentFilters,
    pub metrics: HashSet<PaymentIntentMetrics>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetRefundMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<RefundDimensions>,
    #[serde(default)]
    pub filters: refunds::RefundFilters,
    pub metrics: HashSet<RefundMetrics>,
    pub distribution: Option<RefundDistributionBody>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetFrmMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<FrmDimensions>,
    #[serde(default)]
    pub filters: frm::FrmFilters,
    pub metrics: HashSet<FrmMetrics>,
    #[serde(default)]
    pub delta: bool,
}

impl ApiEventMetric for GetFrmMetricRequest {}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSdkEventMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<SdkEventDimensions>,
    #[serde(default)]
    pub filters: sdk_events::SdkEventFilters,
    pub metrics: HashSet<SdkEventMetrics>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAuthEventMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<AuthEventDimensions>,
    #[serde(default)]
    pub filters: AuthEventFilters,
    #[serde(default)]
    pub metrics: HashSet<AuthEventMetrics>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetActivePaymentsMetricRequest {
    #[serde(default)]
    pub metrics: HashSet<ActivePaymentsMetrics>,
    pub time_range: TimeRange,
}

#[derive(Debug, serde::Serialize)]
pub struct AnalyticsMetadata {
    pub current_time_range: TimeRange,
}

#[derive(Debug, serde::Serialize)]
pub struct PaymentsAnalyticsMetadata {
    pub total_payment_processed_amount: Option<u64>,
    pub total_payment_processed_amount_in_usd: Option<u64>,
    pub total_payment_processed_amount_without_smart_retries: Option<u64>,
    pub total_payment_processed_amount_without_smart_retries_usd: Option<u64>,
    pub total_payment_processed_count: Option<u64>,
    pub total_payment_processed_count_without_smart_retries: Option<u64>,
    pub total_failure_reasons_count: Option<u64>,
    pub total_failure_reasons_count_without_smart_retries: Option<u64>,
}

#[derive(Debug, serde::Serialize)]
pub struct PaymentIntentsAnalyticsMetadata {
    pub total_success_rate: Option<f64>,
    pub total_success_rate_without_smart_retries: Option<f64>,
    pub total_smart_retried_amount: Option<u64>,
    pub total_smart_retried_amount_without_smart_retries: Option<u64>,
    pub total_payment_processed_amount: Option<u64>,
    pub total_payment_processed_amount_without_smart_retries: Option<u64>,
    pub total_smart_retried_amount_in_usd: Option<u64>,
    pub total_smart_retried_amount_without_smart_retries_in_usd: Option<u64>,
    pub total_payment_processed_amount_in_usd: Option<u64>,
    pub total_payment_processed_amount_without_smart_retries_in_usd: Option<u64>,
    pub total_payment_processed_count: Option<u64>,
    pub total_payment_processed_count_without_smart_retries: Option<u64>,
}

#[derive(Debug, serde::Serialize)]
pub struct RefundsAnalyticsMetadata {
    pub total_refund_success_rate: Option<f64>,
    pub total_refund_processed_amount: Option<u64>,
    pub total_refund_processed_amount_in_usd: Option<u64>,
    pub total_refund_processed_count: Option<u64>,
    pub total_refund_reason_count: Option<u64>,
    pub total_refund_error_message_count: Option<u64>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentFiltersRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<PaymentDimensions>,
}

#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentFiltersResponse {
    pub query_data: Vec<FilterValue>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FilterValue {
    pub dimension: PaymentDimensions,
    pub values: Vec<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentIntentFiltersRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<PaymentIntentDimensions>,
}

#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentIntentFiltersResponse {
    pub query_data: Vec<PaymentIntentFilterValue>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentIntentFilterValue {
    pub dimension: PaymentIntentDimensions,
    pub values: Vec<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetRefundFilterRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<RefundDimensions>,
}

#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RefundFiltersResponse {
    pub query_data: Vec<RefundFilterValue>,
}

#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RefundFilterValue {
    pub dimension: RefundDimensions,
    pub values: Vec<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetFrmFilterRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<FrmDimensions>,
}

impl ApiEventMetric for GetFrmFilterRequest {}

#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FrmFiltersResponse {
    pub query_data: Vec<FrmFilterValue>,
}

impl ApiEventMetric for FrmFiltersResponse {}

#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FrmFilterValue {
    pub dimension: FrmDimensions,
    pub values: Vec<String>,
}

impl ApiEventMetric for FrmFilterValue {}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSdkEventFiltersRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<SdkEventDimensions>,
}

#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SdkEventFiltersResponse {
    pub query_data: Vec<SdkEventFilterValue>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SdkEventFilterValue {
    pub dimension: SdkEventDimensions,
    pub values: Vec<String>,
}

#[derive(Debug, serde::Serialize)]
pub struct DisputesAnalyticsMetadata {
    pub total_disputed_amount: Option<u64>,
    pub total_dispute_lost_amount: Option<u64>,
}
#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [AnalyticsMetadata; 1],
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentsMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [PaymentsAnalyticsMetadata; 1],
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentIntentsMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [PaymentIntentsAnalyticsMetadata; 1],
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RefundsMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [RefundsAnalyticsMetadata; 1],
}
#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DisputesMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [DisputesAnalyticsMetadata; 1],
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetApiEventFiltersRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<ApiEventDimensions>,
}

#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiEventFiltersResponse {
    pub query_data: Vec<ApiEventFilterValue>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiEventFilterValue {
    pub dimension: ApiEventDimensions,
    pub values: Vec<String>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetApiEventMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<ApiEventDimensions>,
    #[serde(default)]
    pub filters: api_event::ApiEventFilters,
    pub metrics: HashSet<ApiEventMetrics>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDisputeFilterRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<DisputeDimensions>,
}

#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DisputeFiltersResponse {
    pub query_data: Vec<DisputeFilterValue>,
}

#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DisputeFilterValue {
    pub dimension: DisputeDimensions,
    pub values: Vec<String>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDisputeMetricRequest {
    pub time_series: Option<TimeSeries>,
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<DisputeDimensions>,
    #[serde(default)]
    pub filters: disputes::DisputeFilters,
    pub metrics: HashSet<DisputeMetrics>,
    #[serde(default)]
    pub delta: bool,
}

#[derive(Clone, Debug, Default, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub struct SankeyResponse {
    pub count: i64,
    pub status: String,
    pub refunds_status: Option<String>,
    pub dispute_status: Option<String>,
    pub first_attempt: i64,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAuthEventFilterRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<AuthEventDimensions>,
}

#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventFiltersResponse {
    pub query_data: Vec<AuthEventFilterValue>,
}

#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventFilterValue {
    pub dimension: AuthEventDimensions,
    pub values: Vec<String>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [AuthEventsAnalyticsMetadata; 1],
}

#[derive(Debug, serde::Serialize)]
pub struct AuthEventsAnalyticsMetadata {
    pub total_error_message_count: Option<u64>,
}


// File: crates/api_models/src/errors.rs

pub mod actix;
pub mod types;


// File: crates/api_models/src/customers.rs

use common_types::primitive_wrappers::CustomerListLimit;
use common_utils::{crypto, custom_serde, id_type, pii, types::Description};
use masking::Secret;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::payments;

/// The customer details
#[cfg(feature = "v1")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerRequest {
    /// The identifier for the customer object. If not provided the customer ID will be autogenerated.
    #[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: Option<id_type::CustomerId>,
    /// The identifier for the Merchant Account
    #[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
    #[serde(skip)]
    pub merchant_id: id_type::MerchantId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = Option<String>, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// Customer's tax registration ID
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerListRequest {
    /// Offset
    #[schema(example = 32)]
    pub offset: Option<u32>,
    /// Limit
    #[schema(example = 32)]
    pub limit: Option<u16>,
    pub customer_id: Option<id_type::CustomerId>,
}

#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerListRequestWithConstraints {
    /// Offset
    #[schema(example = 32)]
    pub offset: Option<u32>,
    /// Limit
    #[schema(example = 32)]
    pub limit: Option<CustomerListLimit>,
    /// Unique identifier for a customer
    pub customer_id: Option<id_type::CustomerId>,
    /// Filter with created time range
    #[serde(flatten)]
    pub time_range: Option<common_utils::types::TimeRange>,
}

#[cfg(feature = "v1")]
impl CustomerRequest {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        Some(
            self.customer_id
                .to_owned()
                .unwrap_or_else(common_utils::generate_customer_id_of_default_length),
        )
    }
    pub fn get_address(&self) -> Option<payments::AddressDetails> {
        self.address.clone()
    }
    pub fn get_optional_email(&self) -> Option<pii::Email> {
        self.email.clone()
    }
}

/// The customer details
#[cfg(feature = "v2")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomerRequest {
    /// The merchant identifier for the customer object.
    #[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// The customer's name
    #[schema(max_length = 255, value_type = String, example = "Jon Test")]
    pub name: Secret<String>,
    /// The customer's email address
    #[schema(value_type = String, max_length = 255, example = "JonTest@test.com")]
    pub email: pii::Email,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v2")]
impl CustomerRequest {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        self.merchant_reference_id.clone()
    }

    pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }

    pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }

    pub fn get_optional_email(&self) -> Option<pii::Email> {
        Some(self.email.clone())
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: crypto::OptionalEncryptableName,
    /// The customer's email address
    #[schema(value_type = Option<String>,max_length = 255, example = "JonTest@test.com")]
    pub email: crypto::OptionalEncryptableEmail,
    /// The customer's phone number
    #[schema(value_type = Option<String>,max_length = 255, example = "9123456789")]
    pub phone: crypto::OptionalEncryptablePhone,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    ///  A timestamp (ISO 8601 code) that determines when the customer was created
    #[schema(value_type = PrimitiveDateTime,example = "2023-01-18T11:04:09.922Z")]
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: time::PrimitiveDateTime,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The identifier for the default payment method.
    #[schema(max_length = 64, example = "pm_djh2837dwduh890123")]
    pub default_payment_method_id: Option<String>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: crypto::OptionalEncryptableSecretString,
}

#[cfg(feature = "v1")]
impl CustomerResponse {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        Some(self.customer_id.clone())
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
    /// Unique identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub id: id_type::GlobalCustomerId,
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// Connector specific customer reference ids
    #[schema(value_type = Option<Object>, example = json!({"mca_hwySG2NtpzX0qr7toOy8": "cus_Rnm2pDKGyQi506"}))]
    pub connector_customer_ids: Option<common_types::customers::ConnectorCustomerMap>,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: crypto::OptionalEncryptableName,
    /// The customer's email address
    #[schema(value_type = Option<String> ,max_length = 255, example = "JonTest@test.com")]
    pub email: crypto::OptionalEncryptableEmail,
    /// The customer's phone number
    #[schema(value_type = Option<String>,max_length = 255, example = "9123456789")]
    pub phone: crypto::OptionalEncryptablePhone,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    ///  A timestamp (ISO 8601 code) that determines when the customer was created
    #[schema(value_type = PrimitiveDateTime,example = "2023-01-18T11:04:09.922Z")]
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: time::PrimitiveDateTime,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The identifier for the default payment method.
    #[schema(value_type = Option<String>, max_length = 64, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
    pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: crypto::OptionalEncryptableSecretString,
}

#[cfg(feature = "v2")]
impl CustomerResponse {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        self.merchant_reference_id.clone()
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Deserialize, Serialize, ToSchema)]
pub struct CustomerDeleteResponse {
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// Whether customer was deleted or not
    #[schema(example = false)]
    pub customer_deleted: bool,
    /// Whether address was deleted or not
    #[schema(example = false)]
    pub address_deleted: bool,
    /// Whether payment methods deleted or not
    #[schema(example = false)]
    pub payment_methods_deleted: bool,
}

#[cfg(feature = "v2")]
#[derive(Debug, Deserialize, Serialize, ToSchema)]
pub struct CustomerDeleteResponse {
    /// Unique identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub id: id_type::GlobalCustomerId,
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// Whether customer was deleted or not
    #[schema(example = false)]
    pub customer_deleted: bool,
    /// Whether address was deleted or not
    #[schema(example = false)]
    pub address_deleted: bool,
    /// Whether payment methods deleted or not
    #[schema(example = false)]
    pub payment_methods_deleted: bool,
}

/// The identifier for the customer object. If not provided the customer ID will be autogenerated.
#[cfg(feature = "v1")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerUpdateRequest {
    /// The identifier for the Merchant Account
    #[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
    #[serde(skip)]
    pub merchant_id: id_type::MerchantId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = Option<String>, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// Customer's tax registration ID
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v1")]
impl CustomerUpdateRequest {
    pub fn get_address(&self) -> Option<payments::AddressDetails> {
        self.address.clone()
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomerUpdateRequest {
    /// The customer's name
    #[schema(max_length = 255, value_type = String, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = String, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The unique identifier of the payment method
    #[schema(value_type = Option<String>, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
    pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v2")]
impl CustomerUpdateRequest {
    pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }

    pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize)]
pub struct CustomerUpdateRequestInternal {
    pub customer_id: id_type::CustomerId,
    pub request: CustomerUpdateRequest,
}

#[cfg(feature = "v2")]
#[derive(Debug, Serialize)]
pub struct CustomerUpdateRequestInternal {
    pub id: id_type::GlobalCustomerId,
    pub request: CustomerUpdateRequest,
}

#[derive(Debug, Serialize, ToSchema)]
pub struct CustomerListResponse {
    /// List of customers
    pub data: Vec<CustomerResponse>,
    /// Total count of customers
    pub total_count: usize,
}


// File: crates/api_models/src/gsm.rs

use utoipa::ToSchema;

use crate::enums as api_enums;

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GsmCreateRequest {
    /// The connector through which payment has gone through
    #[schema(value_type = Connector)]
    pub connector: api_enums::Connector,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
    /// message received from the connector
    pub message: String,
    /// status provided by the router
    pub status: String,
    /// optional error provided by the router
    pub router_error: Option<String>,
    /// decision to be taken for auto retries flow
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    #[schema(value_type = GsmDecision)]
    pub decision: api_enums::GsmDecision,
    /// indicates if step_up retry is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub step_up_possible: bool,
    /// error code unified across the connectors
    pub unified_code: Option<String>,
    /// error message unified across the connectors
    pub unified_message: Option<String>,
    /// category in which error belongs to
    #[schema(value_type = Option<ErrorCategory>)]
    pub error_category: Option<api_enums::ErrorCategory>,
    /// indicates if retry with pan is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub clear_pan_possible: bool,
    /// Indicates the GSM feature associated with the request,
    /// such as retry mechanisms or other specific functionalities provided by the system.
    #[schema(value_type = Option<GsmFeature>)]
    pub feature: Option<api_enums::GsmFeature>,
    /// Contains the data relevant to the specified GSM feature, if applicable.
    /// For example, if the `feature` is `Retry`, this will include configuration
    /// details specific to the retry behavior.
    #[schema(value_type = Option<GsmFeatureData>)]
    pub feature_data: Option<common_types::domain::GsmFeatureData>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GsmRetrieveRequest {
    /// The connector through which payment has gone through
    #[schema(value_type = Connector)]
    pub connector: api_enums::Connector,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
    /// message received from the connector
    pub message: String,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GsmUpdateRequest {
    /// The connector through which payment has gone through
    pub connector: String,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
    /// message received from the connector
    pub message: String,
    /// status provided by the router
    pub status: Option<String>,
    /// optional error provided by the router
    pub router_error: Option<String>,
    /// decision to be taken for auto retries flow
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    #[schema(value_type = Option<GsmDecision>)]
    pub decision: Option<api_enums::GsmDecision>,
    /// indicates if step_up retry is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub step_up_possible: Option<bool>,
    /// error code unified across the connectors
    pub unified_code: Option<String>,
    /// error message unified across the connectors
    pub unified_message: Option<String>,
    /// category in which error belongs to
    #[schema(value_type = Option<ErrorCategory>)]
    pub error_category: Option<api_enums::ErrorCategory>,
    /// indicates if retry with pan is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub clear_pan_possible: Option<bool>,
    /// Indicates the GSM feature associated with the request,
    /// such as retry mechanisms or other specific functionalities provided by the system.
    #[schema(value_type = Option<GsmFeature>)]
    pub feature: Option<api_enums::GsmFeature>,
    /// Contains the data relevant to the specified GSM feature, if applicable.
    /// For example, if the `feature` is `Retry`, this will include configuration
    /// details specific to the retry behavior.
    #[schema(value_type = Option<GsmFeatureData>)]
    pub feature_data: Option<common_types::domain::GsmFeatureData>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct GsmDeleteRequest {
    /// The connector through which payment has gone through
    pub connector: String,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
    /// message received from the connector
    pub message: String,
}

#[derive(Debug, serde::Serialize, ToSchema)]
pub struct GsmDeleteResponse {
    pub gsm_rule_delete: bool,
    /// The connector through which payment has gone through
    pub connector: String,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
}

#[derive(serde::Serialize, Debug, ToSchema)]
pub struct GsmResponse {
    /// The connector through which payment has gone through
    pub connector: String,
    /// The flow in which the code and message occurred for a connector
    pub flow: String,
    /// The sub_flow in which the code and message occurred  for a connector
    pub sub_flow: String,
    /// code received from the connector
    pub code: String,
    /// message received from the connector
    pub message: String,
    /// status provided by the router
    pub status: String,
    /// optional error provided by the router
    pub router_error: Option<String>,
    /// decision to be taken for auto retries flow
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    #[schema(value_type = GsmDecision)]
    pub decision: api_enums::GsmDecision,
    /// indicates if step_up retry is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub step_up_possible: bool,
    /// error code unified across the connectors
    pub unified_code: Option<String>,
    /// error message unified across the connectors
    pub unified_message: Option<String>,
    /// category in which error belongs to
    #[schema(value_type = Option<ErrorCategory>)]
    pub error_category: Option<api_enums::ErrorCategory>,
    /// indicates if retry with pan is possible
    /// **Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.
    #[schema(deprecated)]
    pub clear_pan_possible: bool,
    /// Indicates the GSM feature associated with the request,
    /// such as retry mechanisms or other specific functionalities provided by the system.
    #[schema(value_type = GsmFeature)]
    pub feature: api_enums::GsmFeature,
    /// Contains the data relevant to the specified GSM feature, if applicable.
    /// For example, if the `feature` is `Retry`, this will include configuration
    /// details specific to the retry behavior.
    #[schema(value_type = GsmFeatureData)]
    pub feature_data: Option<common_types::domain::GsmFeatureData>,
}


// File: crates/api_models/src/currency.rs

use common_utils::{events::ApiEventMetric, types::MinorUnit};

/// QueryParams to be send to convert the amount -> from_currency -> to_currency
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct CurrencyConversionParams {
    pub amount: MinorUnit,
    pub to_currency: String,
    pub from_currency: String,
}

/// Response to be send for convert currency route
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct CurrencyConversionResponse {
    pub converted_amount: String,
    pub currency: String,
}

impl ApiEventMetric for CurrencyConversionResponse {}
impl ApiEventMetric for CurrencyConversionParams {}


// File: crates/api_models/src/profile_acquirer.rs

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ProfileAcquirerCreate {
    /// The merchant id assigned by the acquirer
    #[schema(value_type= String,example = "M123456789")]
    pub acquirer_assigned_merchant_id: String,
    /// merchant name
    #[schema(value_type= String,example = "NewAge Retailer")]
    pub merchant_name: String,
    /// Network provider
    #[schema(value_type= String,example = "VISA")]
    pub network: common_enums::enums::CardNetwork,
    /// Acquirer bin
    #[schema(value_type= String,example = "456789")]
    pub acquirer_bin: String,
    /// Acquirer ica provided by acquirer
    #[schema(value_type= Option<String>,example = "401288")]
    pub acquirer_ica: Option<String>,
    /// Fraud rate for the particular acquirer configuration
    #[schema(value_type= f64,example = 0.01)]
    pub acquirer_fraud_rate: f64,
    /// Parent profile id to link the acquirer account with
    #[schema(value_type= String,example = "pro_ky0yNyOXXlA5hF8JzE5q")]
    pub profile_id: common_utils::id_type::ProfileId,
}

#[derive(Debug, Serialize, Deserialize, ToSchema, Clone)]
pub struct ProfileAcquirerResponse {
    /// The unique identifier of the profile acquirer
    #[schema(value_type= String,example = "pro_acq_LCRdERuylQvNQ4qh3QE0")]
    pub profile_acquirer_id: common_utils::id_type::ProfileAcquirerId,
    /// The merchant id assigned by the acquirer
    #[schema(value_type= String,example = "M123456789")]
    pub acquirer_assigned_merchant_id: String,
    /// Merchant name
    #[schema(value_type= String,example = "NewAge Retailer")]
    pub merchant_name: String,
    /// Network provider
    #[schema(value_type= String,example = "VISA")]
    pub network: common_enums::enums::CardNetwork,
    /// Acquirer bin
    #[schema(value_type= String,example = "456789")]
    pub acquirer_bin: String,
    /// Acquirer ica provided by acquirer
    #[schema(value_type= Option<String>,example = "401288")]
    pub acquirer_ica: Option<String>,
    /// Fraud rate for the particular acquirer configuration
    #[schema(value_type= f64,example = 0.01)]
    pub acquirer_fraud_rate: f64,
    /// Parent profile id to link the acquirer account with
    #[schema(value_type= String,example = "pro_ky0yNyOXXlA5hF8JzE5q")]
    pub profile_id: common_utils::id_type::ProfileId,
}

impl common_utils::events::ApiEventMetric for ProfileAcquirerCreate {}
impl common_utils::events::ApiEventMetric for ProfileAcquirerResponse {}

impl
    From<(
        common_utils::id_type::ProfileAcquirerId,
        &common_utils::id_type::ProfileId,
        &common_types::domain::AcquirerConfig,
    )> for ProfileAcquirerResponse
{
    fn from(
        (profile_acquirer_id, profile_id, acquirer_config): (
            common_utils::id_type::ProfileAcquirerId,
            &common_utils::id_type::ProfileId,
            &common_types::domain::AcquirerConfig,
        ),
    ) -> Self {
        Self {
            profile_acquirer_id,
            profile_id: profile_id.clone(),
            acquirer_assigned_merchant_id: acquirer_config.acquirer_assigned_merchant_id.clone(),
            merchant_name: acquirer_config.merchant_name.clone(),
            network: acquirer_config.network.clone(),
            acquirer_bin: acquirer_config.acquirer_bin.clone(),
            acquirer_ica: acquirer_config.acquirer_ica.clone(),
            acquirer_fraud_rate: acquirer_config.acquirer_fraud_rate,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct ProfileAcquirerUpdate {
    #[schema(value_type = Option<String>, example = "M987654321")]
    pub acquirer_assigned_merchant_id: Option<String>,
    #[schema(value_type = Option<String>, example = "Updated Retailer Name")]
    pub merchant_name: Option<String>,
    #[schema(value_type = Option<String>, example = "MASTERCARD")]
    pub network: Option<common_enums::enums::CardNetwork>,
    #[schema(value_type = Option<String>, example = "987654")]
    pub acquirer_bin: Option<String>,
    #[schema(value_type = Option<String>, example = "501299")]
    pub acquirer_ica: Option<String>,
    #[schema(value_type = Option<f64>, example = "0.02")]
    pub acquirer_fraud_rate: Option<f64>,
}

impl common_utils::events::ApiEventMetric for ProfileAcquirerUpdate {}


// File: crates/api_models/src/authentication.rs

use common_enums::{enums, AuthenticationConnectors};
#[cfg(feature = "v1")]
use common_utils::errors::{self, CustomResult};
use common_utils::{
    events::{ApiEventMetric, ApiEventsType},
    id_type,
};
#[cfg(feature = "v1")]
use error_stack::ResultExt;
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;

#[cfg(feature = "v1")]
use crate::payments::{Address, BrowserInformation, PaymentMethodData};
use crate::payments::{
    ClickToPaySessionResponse, CustomerDetails, DeviceChannel, SdkInformation,
    ThreeDsCompletionIndicator,
};

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationCreateRequest {
    /// The unique identifier for this authentication.
    #[schema(value_type = Option<String>, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: Option<id_type::AuthenticationId>,

    /// The business profile that is associated with this authentication
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<id_type::ProfileId>,

    /// Customer details.
    #[schema(value_type = Option<CustomerDetails>)]
    pub customer: Option<CustomerDetails>,

    /// The amount for the transaction, required.
    #[schema(value_type = MinorUnit, example = 1000)]
    pub amount: common_utils::types::MinorUnit,

    /// The connector to be used for authentication, if known.
    #[schema(value_type = Option<AuthenticationConnectors>, example = "netcetera")]
    pub authentication_connector: Option<AuthenticationConnectors>,

    /// The currency for the transaction, required.
    #[schema(value_type = Currency)]
    pub currency: common_enums::Currency,

    /// The URL to which the user should be redirected after authentication.
    #[schema(value_type = Option<String>, example = "https://example.com/redirect")]
    pub return_url: Option<String>,

    /// Force 3DS challenge.
    #[serde(default)]
    pub force_3ds_challenge: Option<bool>,

    /// Choose what kind of sca exemption is required for this payment
    #[schema(value_type = Option<ScaExemptionType>)]
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,

    /// Profile Acquirer ID get from profile acquirer configuration
    #[schema(value_type = Option<String>)]
    pub profile_acquirer_id: Option<id_type::ProfileAcquirerId>,

    /// Acquirer details information
    #[schema(value_type = Option<AcquirerDetails>)]
    pub acquirer_details: Option<AcquirerDetails>,

    /// Customer details.
    #[schema(value_type = Option<CustomerDetails>)]
    pub customer_details: Option<CustomerDetails>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AcquirerDetails {
    /// The bin of the card.
    #[schema(value_type = Option<String>, example = "123456")]
    pub acquirer_bin: Option<String>,
    /// The merchant id of the card.
    #[schema(value_type = Option<String>, example = "merchant_abc")]
    pub acquirer_merchant_id: Option<String>,
    /// The country code of the card.
    #[schema(value_type = Option<String>, example = "US/34456")]
    pub merchant_country_code: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationResponse {
    /// The unique identifier for this authentication.
    #[schema(value_type = String, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: id_type::AuthenticationId,

    /// This is an identifier for the merchant account. This is inferred from the API key
    /// provided during the request
    #[schema(value_type = String, example = "merchant_abc")]
    pub merchant_id: id_type::MerchantId,

    /// The current status of the authentication (e.g., Started).
    #[schema(value_type = AuthenticationStatus)]
    pub status: common_enums::AuthenticationStatus,

    /// The client secret for this authentication, to be used for client-side operations.
    #[schema(value_type = Option<String>, example = "auth_mbabizu24mvu3mela5njyhpit4_secret_el9ksDkiB8hi6j9N78yo")]
    pub client_secret: Option<masking::Secret<String>>,

    /// The amount for the transaction.
    #[schema(value_type = MinorUnit, example = 1000)]
    pub amount: common_utils::types::MinorUnit,

    /// The currency for the transaction.
    #[schema(value_type = Currency)]
    pub currency: enums::Currency,

    /// The connector to be used for authentication, if known.
    #[schema(value_type = Option<AuthenticationConnectors>, example = "netcetera")]
    pub authentication_connector: Option<AuthenticationConnectors>,

    /// Whether 3DS challenge was forced.
    pub force_3ds_challenge: Option<bool>,

    /// The URL to which the user should be redirected after authentication, if provided.
    pub return_url: Option<String>,

    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub created_at: Option<PrimitiveDateTime>,

    #[schema(example = "E0001")]
    pub error_code: Option<String>,

    /// If there was an error while calling the connector the error message is received here
    #[schema(example = "Failed while verifying the card")]
    pub error_message: Option<String>,

    /// The business profile that is associated with this payment
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<id_type::ProfileId>,

    /// Choose what kind of sca exemption is required for this payment
    #[schema(value_type = Option<ScaExemptionType>)]
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,

    /// Acquirer details information
    #[schema(value_type = Option<AcquirerDetails>)]
    pub acquirer_details: Option<AcquirerDetails>,

    /// Profile Acquirer ID get from profile acquirer configuration
    #[schema(value_type = Option<String>)]
    pub profile_acquirer_id: Option<id_type::ProfileAcquirerId>,

    /// Customer details.
    #[schema(value_type = Option<CustomerDetails>)]
    pub customer_details: Option<CustomerDetails>,
}

impl ApiEventMetric for AuthenticationCreateRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        self.authentication_id
            .as_ref()
            .map(|id| ApiEventsType::Authentication {
                authentication_id: id.clone(),
            })
    }
}

impl ApiEventMetric for AuthenticationResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationEligibilityCheckRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationEligibilityCheckResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationRetrieveEligibilityCheckRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationRetrieveEligibilityCheckResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationEligibilityRequest {
    /// Payment method-specific data such as card details, wallet info, etc.
    /// This holds the raw information required to process the payment method.
    #[schema(value_type = PaymentMethodData)]
    pub payment_method_data: PaymentMethodData,

    /// Enum representing the type of payment method being used
    /// (e.g., Card, Wallet, UPI, BankTransfer, etc.).
    #[schema(value_type = PaymentMethod)]
    pub payment_method: common_enums::PaymentMethod,

    /// Can be used to specify the Payment Method Type
    #[schema(value_type = Option<PaymentMethodType>, example = "debit")]
    pub payment_method_type: Option<enums::PaymentMethodType>,

    /// Optional secret value used to identify and authorize the client making the request.
    /// This can help ensure that the payment session is secure and valid.
    #[schema(value_type = Option<String>)]
    pub client_secret: Option<masking::Secret<String>>,

    /// Optional identifier for the business profile associated with the payment.
    /// This determines which configurations, rules, and branding are applied to the transaction.
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<id_type::ProfileId>,

    /// Optional billing address of the customer.
    /// This can be used for fraud detection, authentication, or compliance purposes.
    #[schema(value_type = Option<Address>)]
    pub billing: Option<Address>,

    /// Optional shipping address of the customer.
    /// This can be useful for logistics, verification, or additional risk checks.
    #[schema(value_type = Option<Address>)]
    pub shipping: Option<Address>,

    /// Optional information about the customer's browser (user-agent, language, etc.).
    /// This is typically used to support 3DS authentication flows and improve risk assessment.
    #[schema(value_type = Option<BrowserInformation>)]
    pub browser_information: Option<BrowserInformation>,

    /// Optional email address of the customer.
    /// Used for customer identification, communication, and possibly for 3DS or fraud checks.
    #[schema(value_type = Option<String>)]
    pub email: Option<common_utils::pii::Email>,
}

#[cfg(feature = "v1")]
impl AuthenticationEligibilityRequest {
    pub fn get_next_action_api(
        &self,
        base_url: String,
        authentication_id: String,
    ) -> CustomResult<NextAction, errors::ParsingError> {
        let url = format!("{base_url}/authentication/{authentication_id}/authenticate");
        Ok(NextAction {
            url: url::Url::parse(&url).change_context(errors::ParsingError::UrlParsingError)?,
            http_method: common_utils::request::Method::Post,
        })
    }

    pub fn get_billing_address(&self) -> Option<Address> {
        self.billing.clone()
    }

    pub fn get_shipping_address(&self) -> Option<Address> {
        self.shipping.clone()
    }

    pub fn get_browser_information(&self) -> Option<BrowserInformation> {
        self.browser_information.clone()
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, ToSchema)]
pub struct AuthenticationEligibilityResponse {
    /// The unique identifier for this authentication.
    #[schema(value_type = String, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: id_type::AuthenticationId,
    /// The URL to which the user should be redirected after authentication.
    #[schema(value_type = NextAction)]
    pub next_action: NextAction,
    /// The current status of the authentication (e.g., Started).
    #[schema(value_type = AuthenticationStatus)]
    pub status: common_enums::AuthenticationStatus,
    /// The 3DS data for this authentication.
    #[schema(value_type = Option<EligibilityResponseParams>)]
    pub eligibility_response_params: Option<EligibilityResponseParams>,
    /// The metadata for this authentication.
    #[schema(value_type = serde_json::Value)]
    pub connector_metadata: Option<serde_json::Value>,
    /// The unique identifier for this authentication.
    #[schema(value_type = String)]
    pub profile_id: id_type::ProfileId,
    /// The error message for this authentication.
    #[schema(value_type = Option<String>)]
    pub error_message: Option<String>,
    /// The error code for this authentication.
    #[schema(value_type = Option<String>)]
    pub error_code: Option<String>,
    /// The connector used for this authentication.
    #[schema(value_type = Option<AuthenticationConnectors>)]
    pub authentication_connector: Option<AuthenticationConnectors>,
    /// Billing address
    #[schema(value_type = Option<Address>)]
    pub billing: Option<Address>,
    /// Shipping address
    #[schema(value_type = Option<Address>)]
    pub shipping: Option<Address>,
    /// Browser information
    #[schema(value_type = Option<BrowserInformation>)]
    pub browser_information: Option<BrowserInformation>,
    /// Email
    #[schema(value_type = Option<String>)]
    pub email: common_utils::crypto::OptionalEncryptableEmail,
    /// Acquirer details information.
    #[schema(value_type = Option<AcquirerDetails>)]
    pub acquirer_details: Option<AcquirerDetails>,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationEligibilityCheckRequest {
    /// The unique identifier for this authentication.
    /// Added in the request for api event metrics, populated from path parameter
    #[serde(skip)]
    pub authentication_id: id_type::AuthenticationId,
    /// Optional secret value used to identify and authorize the client making the request.
    /// This can help ensure that the payment session is secure and valid.
    #[schema(value_type = Option<String>)]
    pub client_secret: Option<masking::Secret<String>>,
    /// The data for this authentication eligibility check.
    pub eligibility_check_data: AuthenticationEligibilityCheckData,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, ToSchema)]
pub struct AuthenticationEligibilityCheckResponse {
    /// The unique identifier for this authentication.
    #[schema(value_type = String, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: id_type::AuthenticationId,
    // The next action for this authentication eligibility check.
    pub sdk_next_action: AuthenticationSdkNextAction,
}

#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AuthenticationSdkNextAction {
    /// The next action is to await for a merchant callback
    AwaitMerchantCallback,
    /// The next action is to deny the payment with an error message
    Deny { message: String },
    /// The next action is to proceed with the payment
    Proceed,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationRetrieveEligibilityCheckRequest {
    /// The unique identifier for this authentication.
    /// Added in the request for api event metrics, populated from path parameter
    #[serde(skip)]
    pub authentication_id: id_type::AuthenticationId,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationRetrieveEligibilityCheckResponse {
    /// The unique identifier for this authentication.
    /// Added in the request for api event metrics, populated from path parameter
    #[serde(skip)]
    pub authentication_id: id_type::AuthenticationId,
    /// The data for this authentication eligibility check.
    pub eligibility_check_data: AuthenticationEligibilityCheckResponseData,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AuthenticationEligibilityCheckData {
    ClickToPay(ClickToPayEligibilityCheckData),
}

#[cfg(feature = "v1")]
impl AuthenticationEligibilityCheckData {
    pub fn get_click_to_pay_data(&self) -> Option<&ClickToPayEligibilityCheckData> {
        match self {
            Self::ClickToPay(data) => Some(data),
        }
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AuthenticationEligibilityCheckResponseData {
    ClickToPayEnrollmentStatus(ClickToPayEligibilityCheckResponseData),
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ClickToPayEligibilityCheckData {
    // Visa specific eligibility check data
    pub visa: Option<VisaEligibilityCheckData>,
    // MasterCard specific eligibility check data
    pub mastercard: Option<MasterCardEligibilityCheckData>,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ClickToPayEligibilityCheckResponseData {
    // Visa specific eligibility check data
    pub visa: Option<bool>,
    // MasterCard specific eligibility check data
    pub mastercard: Option<bool>,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct VisaEligibilityCheckData {
    // Indicates whether the consumer is enrolled in Visa Secure program
    pub consumer_present: bool,
    // Status of the consumer in Visa Secure program]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consumer_status: Option<String>,
    // Additional data for eligibility check
    #[serde(skip_serializing_if = "Option::is_none")]
    #[schema(value_type = Option<BrowserInformation>)]
    pub custom_data: Option<common_utils::pii::SecretSerdeValue>,
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct MasterCardEligibilityCheckData {
    // Indicates whether the consumer is enrolled in MasterCard Identity Check program
    pub consumer_present: bool,
    // Session ID from MasterCard Identity Check program
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id_lookup_session_id: Option<String>,
    // Timestamp of the last time the card was used
    #[serde(skip_serializing_if = "Option::is_none")]
    pub last_used_card_timestamp: Option<String>,
}

#[derive(Debug, Serialize, ToSchema)]
pub enum EligibilityResponseParams {
    ThreeDsData(ThreeDsData),
}

#[derive(Debug, Serialize, ToSchema)]
pub struct ThreeDsData {
    /// The unique identifier for this authentication from the 3DS server.
    #[schema(value_type = String)]
    pub three_ds_server_transaction_id: Option<String>,
    /// The maximum supported 3DS version.
    #[schema(value_type = String)]
    pub maximum_supported_3ds_version: Option<common_utils::types::SemanticVersion>,
    /// The unique identifier for this authentication from the connector.
    #[schema(value_type = String)]
    pub connector_authentication_id: Option<String>,
    /// The data required to perform the 3DS method.
    #[schema(value_type = String)]
    pub three_ds_method_data: Option<String>,
    /// The URL to which the user should be redirected after authentication.
    #[schema(value_type = String, example = "https://example.com/redirect")]
    pub three_ds_method_url: Option<url::Url>,
    /// The version of the message.
    #[schema(value_type = String)]
    pub message_version: Option<common_utils::types::SemanticVersion>,
    /// The unique identifier for this authentication.
    #[schema(value_type = String)]
    pub directory_server_id: Option<String>,
}

#[derive(Debug, Serialize, ToSchema)]
pub struct NextAction {
    /// The URL for authenticatating the user.
    #[schema(value_type = String)]
    pub url: url::Url,
    /// The HTTP method to use for the request.
    #[schema(value_type = Method)]
    pub http_method: common_utils::request::Method,
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationEligibilityRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationEligibilityResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationAuthenticateRequest {
    /// Authentication ID for the authentication
    #[serde(skip_deserializing)]
    pub authentication_id: id_type::AuthenticationId,
    /// Client secret for the authentication
    #[schema(value_type = String)]
    pub client_secret: Option<masking::Secret<String>>,
    /// SDK Information if request is from SDK
    pub sdk_information: Option<SdkInformation>,
    /// Device Channel indicating whether request is coming from App or Browser
    pub device_channel: DeviceChannel,
    /// Indicates if 3DS method data was successfully completed or not
    pub threeds_method_comp_ind: ThreeDsCompletionIndicator,
}

impl ApiEventMetric for AuthenticationAuthenticateRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationAuthenticateResponse {
    /// Indicates the transaction status
    #[serde(rename = "trans_status")]
    #[schema(value_type = Option<TransactionStatus>)]
    pub transaction_status: Option<common_enums::TransactionStatus>,
    /// Access Server URL to be used for challenge submission
    #[schema(value_type = String, example = "https://example.com/redirect")]
    pub acs_url: Option<url::Url>,
    /// Challenge request which should be sent to acs_url
    pub challenge_request: Option<String>,
    /// Unique identifier assigned by the EMVCo(Europay, Mastercard and Visa)
    pub acs_reference_number: Option<String>,
    /// Unique identifier assigned by the ACS to identify a single transaction
    pub acs_trans_id: Option<String>,
    /// Unique identifier assigned by the 3DS Server to identify a single transaction
    pub three_ds_server_transaction_id: Option<String>,
    /// Contains the JWS object created by the ACS for the ARes(Authentication Response) message
    pub acs_signed_content: Option<String>,
    /// Three DS Requestor URL
    pub three_ds_requestor_url: String,
    /// Merchant app declaring their URL within the CReq message so that the Authentication app can call the Merchant app after OOB authentication has occurred
    pub three_ds_requestor_app_url: Option<String>,

    /// The error message for this authentication.
    #[schema(value_type = String)]
    pub error_message: Option<String>,
    /// The error code for this authentication.
    #[schema(value_type = String)]
    pub error_code: Option<String>,
    /// The authentication value for this authentication, only available in case of server to server request. Unavailable in case of client request due to security concern.
    #[schema(value_type = String)]
    pub authentication_value: Option<masking::Secret<String>>,

    /// The current status of the authentication (e.g., Started).
    #[schema(value_type = AuthenticationStatus)]
    pub status: common_enums::AuthenticationStatus,

    /// The connector to be used for authentication, if known.
    #[schema(value_type = Option<AuthenticationConnectors>, example = "netcetera")]
    pub authentication_connector: Option<AuthenticationConnectors>,

    /// The unique identifier for this authentication.
    #[schema(value_type = AuthenticationId, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: id_type::AuthenticationId,

    /// The ECI value for this authentication.
    #[schema(value_type = String)]
    pub eci: Option<String>,

    /// Acquirer details information.
    #[schema(value_type = Option<AcquirerDetails>)]
    pub acquirer_details: Option<AcquirerDetails>,
}

impl ApiEventMetric for AuthenticationAuthenticateResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct AuthenticationSyncResponse {
    // Core Authentication Fields (from AuthenticationResponse)
    /// The unique identifier for this authentication.
    #[schema(value_type = String, example = "auth_mbabizu24mvu3mela5njyhpit4")]
    pub authentication_id: id_type::AuthenticationId,

    /// This is an identifier for the merchant account.
    #[schema(value_type = String, example = "merchant_abc")]
    pub merchant_id: id_type::MerchantId,

    /// The current status of the authentication.
    #[schema(value_type = AuthenticationStatus)]
    pub status: common_enums::AuthenticationStatus,

    /// The client secret for this authentication.
    #[schema(value_type = Option<String>)]
    pub client_secret: Option<masking::Secret<String>>,

    /// The amount for the transaction.
    #[schema(value_type = MinorUnit, example = 1000)]
    pub amount: common_utils::types::MinorUnit,

    /// The currency for the transaction.
    #[schema(value_type = Currency)]
    pub currency: enums::Currency,

    /// The connector used for authentication.
    #[schema(value_type = Option<AuthenticationConnectors>)]
    pub authentication_connector: Option<AuthenticationConnectors>,

    /// Whether 3DS challenge was forced.
    pub force_3ds_challenge: Option<bool>,

    /// The URL to which the user should be redirected after authentication.
    pub return_url: Option<String>,

    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,

    /// The business profile that is associated with this authentication.
    #[schema(value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// SCA exemption type for this authentication.
    #[schema(value_type = Option<ScaExemptionType>)]
    pub psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,

    /// Acquirer details information.
    #[schema(value_type = Option<AcquirerDetails>)]
    pub acquirer_details: Option<AcquirerDetails>,

    /// The unique identifier from the 3DS server.
    #[schema(value_type = Option<String>)]
    pub threeds_server_transaction_id: Option<String>,

    /// The maximum supported 3DS version.
    #[schema(value_type = Option<String>)]
    pub maximum_supported_3ds_version: Option<common_utils::types::SemanticVersion>,

    /// The unique identifier from the connector.
    #[schema(value_type = Option<String>)]
    pub connector_authentication_id: Option<String>,

    /// The data required to perform the 3DS method.
    #[schema(value_type = Option<String>)]
    pub three_ds_method_data: Option<String>,

    /// The URL for the 3DS method.
    #[schema(value_type = Option<String>)]
    pub three_ds_method_url: Option<String>,

    /// The version of the message.
    #[schema(value_type = Option<String>)]
    pub message_version: Option<common_utils::types::SemanticVersion>,

    /// The metadata for this authentication.
    #[schema(value_type = Option<serde_json::Value>)]
    pub connector_metadata: Option<serde_json::Value>,

    /// The unique identifier for the directory server.
    #[schema(value_type = Option<String>)]
    pub directory_server_id: Option<String>,

    /// The insensitive payment method data
    pub payment_method_data: Option<AuthenticationPaymentMethodDataResponse>,

    /// The tokens for vaulted data
    pub vault_token_data: Option<AuthenticationVaultTokenData>,

    /// Billing address.
    #[schema(value_type = Option<Address>)]
    pub billing: Option<Address>,

    /// Shipping address.
    #[schema(value_type = Option<Address>)]
    pub shipping: Option<Address>,

    /// Browser information.
    #[schema(value_type = Option<BrowserInformation>)]
    pub browser_information: Option<BrowserInformation>,

    /// Email.
    #[schema(value_type = Option<String>)]
    pub email: common_utils::crypto::OptionalEncryptableEmail,

    /// Indicates the transaction status.
    #[serde(rename = "trans_status")]
    #[schema(value_type = Option<TransactionStatus>)]
    pub transaction_status: Option<common_enums::TransactionStatus>,

    /// Access Server URL for challenge submission.
    pub acs_url: Option<String>,

    /// Challenge request to be sent to acs_url.
    pub challenge_request: Option<String>,

    /// Unique identifier assigned by EMVCo.
    pub acs_reference_number: Option<String>,

    /// Unique identifier assigned by the ACS.
    pub acs_trans_id: Option<String>,

    /// JWS object created by the ACS for the ARes message.
    pub acs_signed_content: Option<String>,

    /// Three DS Requestor URL.
    pub three_ds_requestor_url: Option<String>,

    /// Merchant app URL for OOB authentication.
    pub three_ds_requestor_app_url: Option<String>,

    /// ECI value for this authentication, only available in case of server to server request. Unavailable in case of client request due to security concern.
    pub eci: Option<String>,

    // Common Error Fields (present in multiple responses)
    /// Error message if any.
    #[schema(value_type = Option<String>)]
    pub error_message: Option<String>,

    /// Error code if any.
    #[schema(value_type = Option<String>)]
    pub error_code: Option<String>,

    /// Profile Acquirer ID
    #[schema(value_type = Option<String>)]
    pub profile_acquirer_id: Option<id_type::ProfileAcquirerId>,
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AuthenticationPaymentMethodDataResponse {
    CardData {
        /// card expiry year
        #[schema(value_type = Option<String>)]
        card_expiry_year: Option<masking::Secret<String>>,

        /// card expiry month
        #[schema(value_type = Option<String>)]
        card_expiry_month: Option<masking::Secret<String>>,
    },
    NetworkTokenData {
        /// network token expiry month
        #[schema(value_type = Option<String>)]
        network_token_expiry_month: Option<masking::Secret<String>>,

        /// network token expiry year
        #[schema(value_type = Option<String>)]
        network_token_expiry_year: Option<masking::Secret<String>>,
    },
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AuthenticationVaultTokenData {
    CardData {
        /// token representing card_number
        #[schema(value_type = Option<String>)]
        #[serde(rename = "card_number")]
        tokenized_card_number: Option<masking::Secret<String>>,

        /// token representing card_expiry_year
        #[schema(value_type = Option<String>)]
        #[serde(rename = "card_expiry_year")]
        tokenized_card_expiry_year: Option<masking::Secret<String>>,

        /// token representing card_expiry_month
        #[schema(value_type = Option<String>)]
        #[serde(rename = "card_expiry_month")]
        tokenized_card_expiry_month: Option<masking::Secret<String>>,

        /// token representing card_cvc
        #[schema(value_type = Option<String>)]
        #[serde(rename = "card_cvc")]
        tokenized_card_cvc: Option<masking::Secret<String>>,
    },
    NetworkTokenData {
        /// token representing payment_token
        #[schema(value_type = Option<String>)]
        #[serde(rename = "network_token")]
        tokenized_network_token: Option<masking::Secret<String>>,

        /// token representing token_expiry_year
        #[schema(value_type = Option<String>)]
        #[serde(rename = "network_token_expiry_year")]
        tokenized_expiry_year: Option<masking::Secret<String>>,

        /// token representing token_expiry_month
        #[schema(value_type = Option<String>)]
        #[serde(rename = "network_token_expiry_month")]
        tokenized_expiry_month: Option<masking::Secret<String>>,

        /// token representing token_cryptogram
        #[schema(value_type = Option<String>)]
        #[serde(rename = "network_token_cryptogram")]
        tokenized_cryptogram: Option<masking::Secret<String>>,
    },
}

#[cfg(feature = "v1")]
impl ApiEventMetric for AuthenticationSyncResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationSyncRequest {
    /// The client secret for this authentication.
    #[schema(value_type = String)]
    pub client_secret: Option<masking::Secret<String>>,
    /// Payment method data for Post Authentication sync
    pub payment_method_details: Option<PostAuthenticationRequestPaymentMethodData>,
    /// Authentication ID for the authentication
    #[serde(skip_deserializing)]
    pub authentication_id: id_type::AuthenticationId,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PostAuthenticationRequestPaymentMethodData {
    pub payment_method_type: AuthenticationPaymentMethodType,
    pub payment_method_data: AuthenticationPaymentMethodData,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub enum AuthenticationPaymentMethodType {
    #[serde(rename = "ctp")]
    ClickToPay,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(untagged)]
pub enum AuthenticationPaymentMethodData {
    ClickToPayDetails(ClickToPayDetails),
}

impl AuthenticationPaymentMethodData {
    pub fn get_click_to_pay_details(&self) -> Option<&ClickToPayDetails> {
        match self {
            Self::ClickToPayDetails(details) => Some(details),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ClickToPayDetails {
    /// merchant transaction id
    pub merchant_transaction_id: Option<String>,
    /// network transaction correlation id
    pub correlation_id: Option<String>,
    /// session transaction flow id
    pub x_src_flow_id: Option<String>,
    /// provider Eg: Visa, Mastercard
    #[schema(value_type = Option<CtpServiceProvider>)]
    pub provider: Option<super::enums::CtpServiceProvider>,
    /// Encrypted payload
    #[schema(value_type = Option<String>)]
    pub encrypted_payload: Option<masking::Secret<String>>,
}

impl ApiEventMetric for AuthenticationSyncRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AuthenticationSyncPostUpdateRequest {
    /// Authentication ID for the authentication
    #[serde(skip_deserializing)]
    pub authentication_id: id_type::AuthenticationId,
}

impl ApiEventMetric for AuthenticationSyncPostUpdateRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
pub struct AuthenticationSessionTokenRequest {
    /// Authentication ID for the authentication
    #[serde(skip_deserializing)]
    pub authentication_id: id_type::AuthenticationId,
    /// Client Secret for the authentication
    #[schema(value_type = String)]
    pub client_secret: Option<masking::Secret<String>>,
}

#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct AuthenticationSessionResponse {
    /// The identifier for the payment
    #[schema(value_type = String)]
    pub authentication_id: id_type::AuthenticationId,
    /// The list of session token object
    pub session_token: Vec<AuthenticationSessionToken>,
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
#[serde(tag = "wallet_name")]
#[serde(rename_all = "snake_case")]
pub enum AuthenticationSessionToken {
    /// The sessions response structure for ClickToPay
    ClickToPay(Box<ClickToPaySessionResponse>),
    NoSessionTokenReceived,
}

impl ApiEventMetric for AuthenticationSessionTokenRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

impl ApiEventMetric for AuthenticationSessionResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}