pub mod address;
pub mod api;
pub mod authentication;
pub mod behaviour;
pub mod bulk_tokenization;
pub mod business_profile;
pub mod callback_mapper;
pub mod card_issuer;
pub mod card_testing_guard_data;
pub mod cards_info;
pub mod chat;
pub mod configs;
pub mod connector_endpoints;
pub mod consts;
pub mod customer;
pub mod disputes;
pub mod errors;
pub mod ext_traits;
pub mod gsm;
pub mod invoice;
pub mod mandates;
pub mod master_key;
pub mod merchant_account;
pub mod merchant_connector_account;
pub mod merchant_key_store;
pub mod payment_address;
pub mod payment_method_data;
pub mod payment_methods;
pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod platform;
pub mod refunds;
pub mod relay;
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
pub mod revenue_recovery;
pub mod router_data;
pub mod router_data_v2;
pub mod router_flow_types;
pub mod router_request_types;
pub mod router_response_types;
pub mod routing;
pub mod sdk_auth;
pub mod subscription;
#[cfg(feature = "tokenization_v2")]
pub mod tokenization;
pub mod transformers;
pub mod type_encryption;
pub mod types;
pub mod vault;

#[cfg(not(feature = "payouts"))]
pub trait PayoutAttemptInterface {}

#[cfg(not(feature = "payouts"))]
pub trait PayoutsInterface {}

use api_models::payments::{
    ApplePayRecurringDetails as ApiApplePayRecurringDetails,
    ApplePayRegularBillingDetails as ApiApplePayRegularBillingDetails,
    FeatureMetadata as ApiFeatureMetadata, OrderDetailsWithAmount as ApiOrderDetailsWithAmount,
    RecurringPaymentIntervalUnit as ApiRecurringPaymentIntervalUnit,
    RedirectResponse as ApiRedirectResponse,
};
#[cfg(feature = "v2")]
use api_models::payments::{
    BillingConnectorAdditionalCardInfo as ApiBillingConnectorAdditionalCardInfo,
    BillingConnectorPaymentDetails as ApiBillingConnectorPaymentDetails,
    BillingConnectorPaymentMethodDetails as ApiBillingConnectorPaymentMethodDetails,
    PaymentRevenueRecoveryMetadata as ApiRevenueRecoveryMetadata,
};
use diesel_models::types::{
    ApplePayRecurringDetails, ApplePayRegularBillingDetails, FeatureMetadata,
    OrderDetailsWithAmount, RecurringPaymentIntervalUnit, RedirectResponse,
};
#[cfg(feature = "v2")]
use diesel_models::types::{
    BillingConnectorAdditionalCardInfo, BillingConnectorPaymentDetails,
    BillingConnectorPaymentMethodDetails, PaymentRevenueRecoveryMetadata,
};

#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub enum RemoteStorageObject<T: ForeignIDRef> {
    ForeignID(String),
    Object(T),
}

impl<T: ForeignIDRef> From<T> for RemoteStorageObject<T> {
    fn from(value: T) -> Self {
        Self::Object(value)
    }
}

pub trait ForeignIDRef {
    fn foreign_id(&self) -> String;
}

impl<T: ForeignIDRef> RemoteStorageObject<T> {
    pub fn get_id(&self) -> String {
        match self {
            Self::ForeignID(id) => id.clone(),
            Self::Object(i) => i.foreign_id(),
        }
    }
}

use std::fmt::Debug;

pub trait ApiModelToDieselModelConvertor<F> {
    /// Convert from a foreign type to the current type
    fn convert_from(from: F) -> Self;
    fn convert_back(self) -> F;
}

#[cfg(feature = "v1")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
    fn convert_from(from: ApiFeatureMetadata) -> Self {
        let ApiFeatureMetadata {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            pix_additional_details,
            boleto_additional_details,
            pix_automatico_additional_details,
            finix_additional_details,
            ..
        } = from;

        Self {
            redirect_response: redirect_response.map(RedirectResponse::convert_from),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(ApplePayRecurringDetails::convert_from),
            gateway_system: None,
            pix_additional_details: pix_additional_details
                .map(diesel_models::types::PixAdditionalDetails::convert_from),
            boleto_additional_details: boleto_additional_details
                .map(diesel_models::types::BoletoAdditionalDetails::convert_from),
            pix_automatico_additional_details: pix_automatico_additional_details
                .map(diesel_models::types::PixAutomaticoAdditionalDetails::convert_from),
            finix_additional_details: finix_additional_details
                .map(diesel_models::types::FinixAdditionalDetails::convert_from),
        }
    }

    fn convert_back(self) -> ApiFeatureMetadata {
        let Self {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            pix_additional_details,
            boleto_additional_details,
            pix_automatico_additional_details,
            finix_additional_details,
            ..
        } = self;

        ApiFeatureMetadata {
            redirect_response: redirect_response.map(|v| v.convert_back()),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details.map(|v| v.convert_back()),
            pix_additional_details: pix_additional_details.map(|v| v.convert_back()),
            boleto_additional_details: boleto_additional_details.map(|v| v.convert_back()),
            pix_automatico_additional_details: pix_automatico_additional_details
                .map(|v| v.convert_back()),
            finix_additional_details: finix_additional_details.map(|v| v.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::BoletoAdditionalDetails>
    for diesel_models::types::BoletoAdditionalDetails
{
    fn convert_from(from: api_models::payments::BoletoAdditionalDetails) -> Self {
        Self {
            due_date: from.due_date,
            document_kind: from.document_kind,
            payment_type: from.payment_type,
            covenant_code: from.covenant_code,
            pix_key: from.pix_key,
            discount_rules: from
                .discount_rules
                .map(diesel_models::types::SantanderPaymentDiscountRules::convert_from),
            penalties: from
                .penalties
                .map(diesel_models::types::PenaltyRules::convert_from),
            collection_actions: from
                .collection_actions
                .map(diesel_models::types::CollectionActions::convert_from),
            payment_constraints: from
                .payment_constraints
                .map(diesel_models::types::BoletoPaymentTypeConstraints::convert_from),
            beneficiary: from
                .beneficiary
                .map(diesel_models::types::BeneficiaryDetails::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::BoletoAdditionalDetails {
        api_models::payments::BoletoAdditionalDetails {
            due_date: self.due_date,
            document_kind: self.document_kind,
            payment_type: self.payment_type,
            covenant_code: self.covenant_code,
            pix_key: self.pix_key,
            discount_rules: self.discount_rules.map(|value| value.convert_back()),
            penalties: self.penalties.map(|value| value.convert_back()),
            collection_actions: self.collection_actions.map(|value| value.convert_back()),
            payment_constraints: self.payment_constraints.map(|value| value.convert_back()),
            beneficiary: self.beneficiary.map(|value| value.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::SantanderPaymentDiscountRules>
    for diesel_models::types::SantanderPaymentDiscountRules
{
    fn convert_from(from: api_models::payments::SantanderPaymentDiscountRules) -> Self {
        Self {
            discount_type: from
                .discount_type
                .map(diesel_models::types::DiscountType::convert_from),
            tiers: from
                .tiers
                .into_iter()
                .map(diesel_models::types::DiscountTier::convert_from)
                .collect(),
        }
    }

    fn convert_back(self) -> api_models::payments::SantanderPaymentDiscountRules {
        api_models::payments::SantanderPaymentDiscountRules {
            discount_type: self.discount_type.map(|value| value.convert_back()),
            tiers: self
                .tiers
                .into_iter()
                .map(|value| value.convert_back())
                .collect(),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::DiscountType>
    for diesel_models::types::DiscountType
{
    fn convert_from(from: api_models::payments::DiscountType) -> Self {
        match from {
            api_models::payments::DiscountType::Standard => Self::Standard,
            api_models::payments::DiscountType::FixedDate => Self::FixedDate,
            api_models::payments::DiscountType::DailyCalendar => Self::DailyCalendar,
            api_models::payments::DiscountType::DailyBusiness => Self::DailyBusiness,
        }
    }

    fn convert_back(self) -> api_models::payments::DiscountType {
        match self {
            Self::Standard => api_models::payments::DiscountType::Standard,
            Self::FixedDate => api_models::payments::DiscountType::FixedDate,
            Self::DailyCalendar => api_models::payments::DiscountType::DailyCalendar,
            Self::DailyBusiness => api_models::payments::DiscountType::DailyBusiness,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::DiscountTier>
    for diesel_models::types::DiscountTier
{
    fn convert_from(from: api_models::payments::DiscountTier) -> Self {
        Self {
            amount: from.amount,
            end_date: from.end_date,
        }
    }

    fn convert_back(self) -> api_models::payments::DiscountTier {
        api_models::payments::DiscountTier {
            amount: self.amount,
            end_date: self.end_date,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::PenaltyRules>
    for diesel_models::types::PenaltyRules
{
    fn convert_from(from: api_models::payments::PenaltyRules) -> Self {
        Self {
            fixed_penalty: from
                .fixed_penalty
                .map(diesel_models::types::PenaltyDetail::convert_from),
            interest: from
                .interest
                .map(diesel_models::types::InterestDetail::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::PenaltyRules {
        api_models::payments::PenaltyRules {
            fixed_penalty: self.fixed_penalty.map(|value| value.convert_back()),
            interest: self.interest.map(|value| value.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::InterestDetail>
    for diesel_models::types::InterestDetail
{
    fn convert_from(from: api_models::payments::InterestDetail) -> Self {
        Self {
            interest_percentage: from.interest_percentage,
            iof_percentage: from.iof_percentage,
        }
    }

    fn convert_back(self) -> api_models::payments::InterestDetail {
        api_models::payments::InterestDetail {
            interest_percentage: self.interest_percentage,
            iof_percentage: self.iof_percentage,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::PenaltyDetail>
    for diesel_models::types::PenaltyDetail
{
    fn convert_from(from: api_models::payments::PenaltyDetail) -> Self {
        Self {
            value: from.value,
            grace_period_days: from.grace_period_days,
        }
    }

    fn convert_back(self) -> api_models::payments::PenaltyDetail {
        api_models::payments::PenaltyDetail {
            value: self.value,
            grace_period_days: self.grace_period_days,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::CollectionActions>
    for diesel_models::types::CollectionActions
{
    fn convert_from(from: api_models::payments::CollectionActions) -> Self {
        Self {
            legal_protest: from
                .legal_protest
                .map(diesel_models::types::ProtestRules::convert_from),
            auto_write_off_days: from.auto_write_off_days,
        }
    }

    fn convert_back(self) -> api_models::payments::CollectionActions {
        api_models::payments::CollectionActions {
            legal_protest: self.legal_protest.map(|value| value.convert_back()),
            auto_write_off_days: self.auto_write_off_days,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::ProtestRules>
    for diesel_models::types::ProtestRules
{
    fn convert_from(from: api_models::payments::ProtestRules) -> Self {
        Self {
            protest_type: from
                .protest_type
                .map(diesel_models::types::ProtestType::convert_from),
            days_after_due_date: from.days_after_due_date,
        }
    }

    fn convert_back(self) -> api_models::payments::ProtestRules {
        api_models::payments::ProtestRules {
            protest_type: self.protest_type.map(|value| value.convert_back()),
            days_after_due_date: self.days_after_due_date,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::ProtestType>
    for diesel_models::types::ProtestType
{
    fn convert_from(from: api_models::payments::ProtestType) -> Self {
        match from {
            api_models::payments::ProtestType::Disabled => Self::Disabled,
            api_models::payments::ProtestType::CalendarDays => Self::CalendarDays,
            api_models::payments::ProtestType::BusinessDays => Self::BusinessDays,
            api_models::payments::ProtestType::ContractDefault => Self::ContractDefault,
        }
    }

    fn convert_back(self) -> api_models::payments::ProtestType {
        match self {
            Self::Disabled => api_models::payments::ProtestType::Disabled,
            Self::CalendarDays => api_models::payments::ProtestType::CalendarDays,
            Self::BusinessDays => api_models::payments::ProtestType::BusinessDays,
            Self::ContractDefault => api_models::payments::ProtestType::ContractDefault,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::BoletoPaymentTypeConstraints>
    for diesel_models::types::BoletoPaymentTypeConstraints
{
    fn convert_from(from: api_models::payments::BoletoPaymentTypeConstraints) -> Self {
        match from {
            api_models::payments::BoletoPaymentTypeConstraints::FixedAmount => Self::FixedAmount,
            api_models::payments::BoletoPaymentTypeConstraints::FlexibleAmount(details) => {
                Self::FlexibleAmount(diesel_models::types::FlexibleAmountDetails::convert_from(
                    details,
                ))
            }
            api_models::payments::BoletoPaymentTypeConstraints::Installment(details) => {
                Self::Installment(diesel_models::types::InstallmentDetails::convert_from(
                    details,
                ))
            }
        }
    }

    fn convert_back(self) -> api_models::payments::BoletoPaymentTypeConstraints {
        match self {
            Self::FixedAmount => api_models::payments::BoletoPaymentTypeConstraints::FixedAmount,
            Self::FlexibleAmount(details) => {
                api_models::payments::BoletoPaymentTypeConstraints::FlexibleAmount(
                    details.convert_back(),
                )
            }
            Self::Installment(details) => {
                api_models::payments::BoletoPaymentTypeConstraints::Installment(
                    details.convert_back(),
                )
            }
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::FlexibleAmountDetails>
    for diesel_models::types::FlexibleAmountDetails
{
    fn convert_from(from: api_models::payments::FlexibleAmountDetails) -> Self {
        Self {
            min_value: from.min_value,
            max_value: from.max_value,
            value_type: from
                .value_type
                .map(diesel_models::types::CalculationType::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::FlexibleAmountDetails {
        api_models::payments::FlexibleAmountDetails {
            min_value: self.min_value,
            max_value: self.max_value,
            value_type: self.value_type.map(|value| value.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::InstallmentDetails>
    for diesel_models::types::InstallmentDetails
{
    fn convert_from(from: api_models::payments::InstallmentDetails) -> Self {
        Self {
            max_partial_payments: from.max_partial_payments,
            value_type: from
                .value_type
                .map(diesel_models::types::CalculationType::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::InstallmentDetails {
        api_models::payments::InstallmentDetails {
            max_partial_payments: self.max_partial_payments,
            value_type: self.value_type.map(|value| value.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::CalculationType>
    for diesel_models::types::CalculationType
{
    fn convert_from(from: api_models::payments::CalculationType) -> Self {
        match from {
            api_models::payments::CalculationType::Percentage => Self::Percentage,
            api_models::payments::CalculationType::FlatAmount => Self::FlatAmount,
        }
    }

    fn convert_back(self) -> api_models::payments::CalculationType {
        match self {
            Self::Percentage => api_models::payments::CalculationType::Percentage,
            Self::FlatAmount => api_models::payments::CalculationType::FlatAmount,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::BeneficiaryDetails>
    for diesel_models::types::BeneficiaryDetails
{
    fn convert_from(from: api_models::payments::BeneficiaryDetails) -> Self {
        Self {
            name: from.name,
            document_number: from.document_number,
            document_type: from.document_type,
        }
    }

    fn convert_back(self) -> api_models::payments::BeneficiaryDetails {
        api_models::payments::BeneficiaryDetails {
            name: self.name,
            document_number: self.document_number,
            document_type: self.document_type,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::FinixAdditionalDetails>
    for diesel_models::types::FinixAdditionalDetails
{
    fn convert_from(from: api_models::payments::FinixAdditionalDetails) -> Self {
        Self {
            fraud_session_id: from.fraud_session_id,
        }
    }

    fn convert_back(self) -> api_models::payments::FinixAdditionalDetails {
        api_models::payments::FinixAdditionalDetails {
            fraud_session_id: self.fraud_session_id,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::SantanderMandatePeriodicity>
    for diesel_models::types::SantanderMandatePeriodicity
{
    fn convert_from(from: api_models::payments::SantanderMandatePeriodicity) -> Self {
        match from {
            api_models::payments::SantanderMandatePeriodicity::Weekly => Self::Weekly,
            api_models::payments::SantanderMandatePeriodicity::Monthly => Self::Monthly,
            api_models::payments::SantanderMandatePeriodicity::Quarterly => Self::Quarterly,
            api_models::payments::SantanderMandatePeriodicity::Semiannually => Self::Semiannually,
            api_models::payments::SantanderMandatePeriodicity::Annually => Self::Annually,
        }
    }

    fn convert_back(self) -> api_models::payments::SantanderMandatePeriodicity {
        match self {
            Self::Weekly => api_models::payments::SantanderMandatePeriodicity::Weekly,
            Self::Monthly => api_models::payments::SantanderMandatePeriodicity::Monthly,
            Self::Quarterly => api_models::payments::SantanderMandatePeriodicity::Quarterly,
            Self::Semiannually => api_models::payments::SantanderMandatePeriodicity::Semiannually,
            Self::Annually => api_models::payments::SantanderMandatePeriodicity::Annually,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::SantanderMandateDetails>
    for diesel_models::types::SantanderMandateDetails
{
    fn convert_from(m: api_models::payments::SantanderMandateDetails) -> Self {
        Self {
            fixed_recurring_amount: m.fixed_recurring_amount,
            min_recurring_amount: m.min_recurring_amount,
            start_date: m.start_date,
            end_date: m.end_date,
            periodicity: m
                .periodicity
                .map(diesel_models::types::SantanderMandatePeriodicity::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::SantanderMandateDetails {
        api_models::payments::SantanderMandateDetails {
            fixed_recurring_amount: self.fixed_recurring_amount,
            min_recurring_amount: self.min_recurring_amount,
            start_date: self.start_date,
            end_date: self.end_date,
            periodicity: self.periodicity.map(|p| p.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::SantanderPixAutomaticoReceiverDetails>
    for diesel_models::types::SantanderPixAutomaticoReceiverDetails
{
    fn convert_from(r: api_models::payments::SantanderPixAutomaticoReceiverDetails) -> Self {
        Self {
            branch_code: r.branch_code,
            account_number: r.account_number,
            account_type: r
                .account_type
                .map(diesel_models::types::AccountType::convert_from),
        }
    }

    fn convert_back(self) -> api_models::payments::SantanderPixAutomaticoReceiverDetails {
        api_models::payments::SantanderPixAutomaticoReceiverDetails {
            branch_code: self.branch_code,
            account_number: self.account_number,
            account_type: self.account_type.map(|a| a.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::AccountType>
    for diesel_models::types::AccountType
{
    fn convert_from(from: api_models::payments::AccountType) -> Self {
        match from {
            api_models::payments::AccountType::Current => Self::Current,
            api_models::payments::AccountType::Savings => Self::Savings,
            api_models::payments::AccountType::Payment => Self::Payment,
        }
    }

    fn convert_back(self) -> api_models::payments::AccountType {
        match self {
            Self::Current => api_models::payments::AccountType::Current,
            Self::Savings => api_models::payments::AccountType::Savings,
            Self::Payment => api_models::payments::AccountType::Payment,
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::PixAdditionalDetails>
    for diesel_models::types::PixAdditionalDetails
{
    fn convert_from(from: api_models::payments::PixAdditionalDetails) -> Self {
        match from {
            api_models::payments::PixAdditionalDetails::Immediate(v) => {
                Self::Immediate(diesel_models::types::ImmediateExpirationTime {
                    time: v.time,
                    pix_key: v.pix_key,
                })
            }
            api_models::payments::PixAdditionalDetails::Scheduled(v) => {
                Self::Scheduled(diesel_models::types::ScheduledExpirationTime {
                    date: v.date,
                    validity_after_expiration: v.validity_after_expiration,
                    pix_key: v.pix_key,
                })
            }
        }
    }

    fn convert_back(self) -> api_models::payments::PixAdditionalDetails {
        match self {
            Self::Immediate(v) => api_models::payments::PixAdditionalDetails::Immediate(
                api_models::payments::ImmediateExpirationTime {
                    time: v.time,
                    pix_key: v.pix_key,
                },
            ),
            Self::Scheduled(v) => api_models::payments::PixAdditionalDetails::Scheduled(
                api_models::payments::ScheduledExpirationTime {
                    date: v.date,
                    validity_after_expiration: v.validity_after_expiration,
                    pix_key: v.pix_key,
                },
            ),
        }
    }
}

impl ApiModelToDieselModelConvertor<api_models::payments::PixAutomaticoAdditionalDetails>
    for diesel_models::types::PixAutomaticoAdditionalDetails
{
    fn convert_from(from: api_models::payments::PixAutomaticoAdditionalDetails) -> Self {
        match from {
            api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoPush(push) => {
                Self::PixAutomaticoPush(diesel_models::types::PixAutomaticoPushData {
                    time: push.time,
                    retry_policy: push.retry_policy,
                    mandate_details: push
                        .mandate_details
                        .map(diesel_models::types::SantanderMandateDetails::convert_from),
                })
            }
            api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoQr(qr) => {
                Self::PixAutomaticoQr(diesel_models::types::PixAutomaticoQrData {
                    retry_policy: qr.retry_policy,
                    mandate_details: qr
                        .mandate_details
                        .map(diesel_models::types::SantanderMandateDetails::convert_from),
                })
            }
            api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoMit(mit) => {
                Self::PixAutomaticoMit(diesel_models::types::PixAutomaticoMitData {
                    receiver_details: mit.receiver_details.map(
                        diesel_models::types::SantanderPixAutomaticoReceiverDetails::convert_from,
                    ),
                    mandate_execution_date: mit.mandate_execution_date,
                    auto_adjust_date: mit.auto_adjust_date,
                })
            }
        }
    }

    fn convert_back(self) -> api_models::payments::PixAutomaticoAdditionalDetails {
        match self {
            Self::PixAutomaticoPush(push) => {
                api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoPush(
                    api_models::payments::PixAutomaticoPushData {
                        time: push.time,
                        retry_policy: push.retry_policy,
                        mandate_details: push.mandate_details.map(|m| m.convert_back()),
                    },
                )
            }
            Self::PixAutomaticoQr(qr) => {
                api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoQr(
                    api_models::payments::PixAutomaticoQrData {
                        retry_policy: qr.retry_policy,
                        mandate_details: qr.mandate_details.map(|m| m.convert_back()),
                    },
                )
            }
            Self::PixAutomaticoMit(mit) => {
                api_models::payments::PixAutomaticoAdditionalDetails::PixAutomaticoMit(
                    api_models::payments::PixAutomaticoMitData {
                        receiver_details: mit.receiver_details.map(|r| r.convert_back()),
                        mandate_execution_date: mit.mandate_execution_date,
                        auto_adjust_date: mit.auto_adjust_date,
                    },
                )
            }
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
    fn convert_from(from: ApiFeatureMetadata) -> Self {
        let ApiFeatureMetadata {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            revenue_recovery: payment_revenue_recovery_metadata,
            pix_additional_details,
            boleto_additional_details,
            pix_automatico_additional_details,
            finix_additional_details,
        } = from;

        Self {
            redirect_response: redirect_response.map(RedirectResponse::convert_from),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(ApplePayRecurringDetails::convert_from),
            payment_revenue_recovery_metadata: payment_revenue_recovery_metadata
                .map(PaymentRevenueRecoveryMetadata::convert_from),
            pix_additional_details: pix_additional_details
                .map(diesel_models::types::PixAdditionalDetails::convert_from),
            boleto_additional_details: boleto_additional_details
                .map(diesel_models::types::BoletoAdditionalDetails::convert_from),
            pix_automatico_additional_details: pix_automatico_additional_details
                .map(diesel_models::types::PixAutomaticoAdditionalDetails::convert_from),
            finix_additional_details: finix_additional_details
                .map(diesel_models::types::FinixAdditionalDetails::convert_from),
        }
    }

    fn convert_back(self) -> ApiFeatureMetadata {
        let Self {
            redirect_response,
            search_tags,
            apple_pay_recurring_details,
            payment_revenue_recovery_metadata,
            pix_additional_details,
            boleto_additional_details,
            pix_automatico_additional_details,
            finix_additional_details,
        } = self;

        ApiFeatureMetadata {
            redirect_response: redirect_response
                .map(|redirect_response| redirect_response.convert_back()),
            search_tags,
            apple_pay_recurring_details: apple_pay_recurring_details
                .map(|value| value.convert_back()),
            revenue_recovery: payment_revenue_recovery_metadata.map(|value| value.convert_back()),
            pix_additional_details: pix_additional_details.map(|v| v.convert_back()),
            boleto_additional_details: boleto_additional_details.map(|v| v.convert_back()),
            pix_automatico_additional_details: pix_automatico_additional_details
                .map(|v| v.convert_back()),
            finix_additional_details: finix_additional_details.map(|v| v.convert_back()),
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiRedirectResponse> for RedirectResponse {
    fn convert_from(from: ApiRedirectResponse) -> Self {
        let ApiRedirectResponse {
            param,
            json_payload,
        } = from;
        Self {
            param,
            json_payload,
        }
    }

    fn convert_back(self) -> ApiRedirectResponse {
        let Self {
            param,
            json_payload,
        } = self;
        ApiRedirectResponse {
            param,
            json_payload,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiRecurringPaymentIntervalUnit>
    for RecurringPaymentIntervalUnit
{
    fn convert_from(from: ApiRecurringPaymentIntervalUnit) -> Self {
        match from {
            ApiRecurringPaymentIntervalUnit::Year => Self::Year,
            ApiRecurringPaymentIntervalUnit::Month => Self::Month,
            ApiRecurringPaymentIntervalUnit::Day => Self::Day,
            ApiRecurringPaymentIntervalUnit::Hour => Self::Hour,
            ApiRecurringPaymentIntervalUnit::Minute => Self::Minute,
        }
    }
    fn convert_back(self) -> ApiRecurringPaymentIntervalUnit {
        match self {
            Self::Year => ApiRecurringPaymentIntervalUnit::Year,
            Self::Month => ApiRecurringPaymentIntervalUnit::Month,
            Self::Day => ApiRecurringPaymentIntervalUnit::Day,
            Self::Hour => ApiRecurringPaymentIntervalUnit::Hour,
            Self::Minute => ApiRecurringPaymentIntervalUnit::Minute,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiApplePayRegularBillingDetails>
    for ApplePayRegularBillingDetails
{
    fn convert_from(from: ApiApplePayRegularBillingDetails) -> Self {
        Self {
            label: from.label,
            recurring_payment_start_date: from.recurring_payment_start_date,
            recurring_payment_end_date: from.recurring_payment_end_date,
            recurring_payment_interval_unit: from
                .recurring_payment_interval_unit
                .map(RecurringPaymentIntervalUnit::convert_from),
            recurring_payment_interval_count: from.recurring_payment_interval_count,
        }
    }

    fn convert_back(self) -> ApiApplePayRegularBillingDetails {
        ApiApplePayRegularBillingDetails {
            label: self.label,
            recurring_payment_start_date: self.recurring_payment_start_date,
            recurring_payment_end_date: self.recurring_payment_end_date,
            recurring_payment_interval_unit: self
                .recurring_payment_interval_unit
                .map(|value| value.convert_back()),
            recurring_payment_interval_count: self.recurring_payment_interval_count,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiApplePayRecurringDetails> for ApplePayRecurringDetails {
    fn convert_from(from: ApiApplePayRecurringDetails) -> Self {
        Self {
            payment_description: from.payment_description,
            regular_billing: ApplePayRegularBillingDetails::convert_from(from.regular_billing),
            billing_agreement: from.billing_agreement,
            management_url: from.management_url,
        }
    }

    fn convert_back(self) -> ApiApplePayRecurringDetails {
        ApiApplePayRecurringDetails {
            payment_description: self.payment_description,
            regular_billing: self.regular_billing.convert_back(),
            billing_agreement: self.billing_agreement,
            management_url: self.management_url,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorAdditionalCardInfo>
    for BillingConnectorAdditionalCardInfo
{
    fn convert_from(from: ApiBillingConnectorAdditionalCardInfo) -> Self {
        Self {
            card_issuer: from.card_issuer,
            card_network: from.card_network,
        }
    }

    fn convert_back(self) -> ApiBillingConnectorAdditionalCardInfo {
        ApiBillingConnectorAdditionalCardInfo {
            card_issuer: self.card_issuer,
            card_network: self.card_network,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorPaymentMethodDetails>
    for BillingConnectorPaymentMethodDetails
{
    fn convert_from(from: ApiBillingConnectorPaymentMethodDetails) -> Self {
        match from {
            ApiBillingConnectorPaymentMethodDetails::Card(data) => {
                Self::Card(BillingConnectorAdditionalCardInfo::convert_from(data))
            }
        }
    }

    fn convert_back(self) -> ApiBillingConnectorPaymentMethodDetails {
        match self {
            Self::Card(data) => ApiBillingConnectorPaymentMethodDetails::Card(data.convert_back()),
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> for PaymentRevenueRecoveryMetadata {
    fn convert_from(from: ApiRevenueRecoveryMetadata) -> Self {
        Self {
            total_retry_count: from.total_retry_count,
            payment_connector_transmission: from.payment_connector_transmission.unwrap_or_default(),
            billing_connector_id: from.billing_connector_id,
            active_attempt_payment_connector_id: from.active_attempt_payment_connector_id,
            billing_connector_payment_details: BillingConnectorPaymentDetails::convert_from(
                from.billing_connector_payment_details,
            ),
            payment_method_type: from.payment_method_type,
            payment_method_subtype: from.payment_method_subtype,
            connector: from.connector,
            invoice_next_billing_time: from.invoice_next_billing_time,
            billing_connector_payment_method_details: from
                .billing_connector_payment_method_details
                .map(BillingConnectorPaymentMethodDetails::convert_from),
            first_payment_attempt_network_advice_code: from
                .first_payment_attempt_network_advice_code,
            first_payment_attempt_network_decline_code: from
                .first_payment_attempt_network_decline_code,
            first_payment_attempt_pg_error_code: from.first_payment_attempt_pg_error_code,
            invoice_billing_started_at_time: from.invoice_billing_started_at_time,
        }
    }

    fn convert_back(self) -> ApiRevenueRecoveryMetadata {
        ApiRevenueRecoveryMetadata {
            total_retry_count: self.total_retry_count,
            payment_connector_transmission: Some(self.payment_connector_transmission),
            billing_connector_id: self.billing_connector_id,
            active_attempt_payment_connector_id: self.active_attempt_payment_connector_id,
            billing_connector_payment_details: self
                .billing_connector_payment_details
                .convert_back(),
            payment_method_type: self.payment_method_type,
            payment_method_subtype: self.payment_method_subtype,
            connector: self.connector,
            invoice_next_billing_time: self.invoice_next_billing_time,
            billing_connector_payment_method_details: self
                .billing_connector_payment_method_details
                .map(|data| data.convert_back()),
            first_payment_attempt_network_advice_code: self
                .first_payment_attempt_network_advice_code,
            first_payment_attempt_network_decline_code: self
                .first_payment_attempt_network_decline_code,
            first_payment_attempt_pg_error_code: self.first_payment_attempt_pg_error_code,
            invoice_billing_started_at_time: self.invoice_billing_started_at_time,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiBillingConnectorPaymentDetails>
    for BillingConnectorPaymentDetails
{
    fn convert_from(from: ApiBillingConnectorPaymentDetails) -> Self {
        Self {
            payment_processor_token: from.payment_processor_token,
            connector_customer_id: from.connector_customer_id,
        }
    }

    fn convert_back(self) -> ApiBillingConnectorPaymentDetails {
        ApiBillingConnectorPaymentDetails {
            payment_processor_token: self.payment_processor_token,
            connector_customer_id: self.connector_customer_id,
        }
    }
}

impl ApiModelToDieselModelConvertor<ApiOrderDetailsWithAmount> for OrderDetailsWithAmount {
    fn convert_from(from: ApiOrderDetailsWithAmount) -> Self {
        let ApiOrderDetailsWithAmount {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
            discount_name,
            discount_percentage,
            discount_type,
        } = from;
        Self {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
            discount_name,
            discount_percentage,
            discount_type,
        }
    }

    fn convert_back(self) -> ApiOrderDetailsWithAmount {
        let Self {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
            discount_name,
            discount_percentage,
            discount_type,
        } = self;
        ApiOrderDetailsWithAmount {
            product_name,
            quantity,
            amount,
            requires_shipping,
            product_img_link,
            product_id,
            category,
            sub_category,
            brand,
            product_type,
            product_tax_code,
            tax_rate,
            total_tax_amount,
            description,
            sku,
            upc,
            commodity_code,
            unit_of_measure,
            total_amount,
            unit_discount_amount,
            discount_name,
            discount_percentage,
            discount_type,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkConfigRequest>
    for diesel_models::payment_intent::PaymentLinkConfigRequestForPayments
{
    fn convert_from(item: api_models::admin::PaymentLinkConfigRequest) -> Self {
        Self {
            theme: item.theme,
            logo: item.logo,
            seller_name: item.seller_name,
            sdk_layout: item.sdk_layout,
            display_sdk_only: item.display_sdk_only,
            enabled_saved_payment_method: item.enabled_saved_payment_method,
            hide_card_nickname_field: item.hide_card_nickname_field,
            show_card_form_by_default: item.show_card_form_by_default,
            details_layout: item.details_layout,
            transaction_details: item.transaction_details.map(|transaction_details| {
                transaction_details
                    .into_iter()
                    .map(|transaction_detail| {
                        diesel_models::PaymentLinkTransactionDetails::convert_from(
                            transaction_detail,
                        )
                    })
                    .collect()
            }),
            background_image: item.background_image.map(|background_image| {
                diesel_models::business_profile::PaymentLinkBackgroundImageConfig::convert_from(
                    background_image,
                )
            }),
            payment_button_text: item.payment_button_text,
            custom_message_for_card_terms: item.custom_message_for_card_terms,
            custom_message_for_payment_method_types: item.custom_message_for_payment_method_types,
            payment_button_colour: item.payment_button_colour,
            skip_status_screen: item.skip_status_screen,
            background_colour: item.background_colour,
            payment_button_text_colour: item.payment_button_text_colour,
            sdk_ui_rules: item.sdk_ui_rules,
            payment_link_ui_rules: item.payment_link_ui_rules,
            enable_button_only_on_form_ready: item.enable_button_only_on_form_ready,
            payment_form_header_text: item.payment_form_header_text,
            payment_form_label_type: item.payment_form_label_type,
            show_card_terms: item.show_card_terms,
            is_setup_mandate_flow: item.is_setup_mandate_flow,
            color_icon_card_cvc_error: item.color_icon_card_cvc_error,
            show_merchant_name: item.show_merchant_name,
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkConfigRequest {
        let Self {
            theme,
            logo,
            seller_name,
            sdk_layout,
            display_sdk_only,
            enabled_saved_payment_method,
            hide_card_nickname_field,
            show_card_form_by_default,
            transaction_details,
            background_image,
            details_layout,
            payment_button_text,
            custom_message_for_card_terms,
            custom_message_for_payment_method_types,
            payment_button_colour,
            skip_status_screen,
            background_colour,
            payment_button_text_colour,
            sdk_ui_rules,
            payment_link_ui_rules,
            enable_button_only_on_form_ready,
            payment_form_header_text,
            payment_form_label_type,
            show_card_terms,
            is_setup_mandate_flow,
            color_icon_card_cvc_error,
            show_merchant_name,
        } = self;
        api_models::admin::PaymentLinkConfigRequest {
            theme,
            logo,
            seller_name,
            sdk_layout,
            display_sdk_only,
            enabled_saved_payment_method,
            hide_card_nickname_field,
            show_card_form_by_default,
            details_layout,
            transaction_details: transaction_details.map(|transaction_details| {
                transaction_details
                    .into_iter()
                    .map(|transaction_detail| transaction_detail.convert_back())
                    .collect()
            }),
            background_image: background_image
                .map(|background_image| background_image.convert_back()),
            payment_button_text,
            custom_message_for_card_terms,
            custom_message_for_payment_method_types,
            payment_button_colour,
            skip_status_screen,
            background_colour,
            payment_button_text_colour,
            sdk_ui_rules,
            payment_link_ui_rules,
            enable_button_only_on_form_ready,
            payment_form_header_text,
            payment_form_label_type,
            show_card_terms,
            is_setup_mandate_flow,
            color_icon_card_cvc_error,
            show_merchant_name,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkTransactionDetails>
    for diesel_models::PaymentLinkTransactionDetails
{
    fn convert_from(from: api_models::admin::PaymentLinkTransactionDetails) -> Self {
        Self {
            key: from.key,
            value: from.value,
            ui_configuration: from
                .ui_configuration
                .map(diesel_models::TransactionDetailsUiConfiguration::convert_from),
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkTransactionDetails {
        let Self {
            key,
            value,
            ui_configuration,
        } = self;
        api_models::admin::PaymentLinkTransactionDetails {
            key,
            value,
            ui_configuration: ui_configuration
                .map(|ui_configuration| ui_configuration.convert_back()),
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::PaymentLinkBackgroundImageConfig>
    for diesel_models::business_profile::PaymentLinkBackgroundImageConfig
{
    fn convert_from(from: api_models::admin::PaymentLinkBackgroundImageConfig) -> Self {
        Self {
            url: from.url,
            position: from.position,
            size: from.size,
        }
    }
    fn convert_back(self) -> api_models::admin::PaymentLinkBackgroundImageConfig {
        let Self {
            url,
            position,
            size,
        } = self;
        api_models::admin::PaymentLinkBackgroundImageConfig {
            url,
            position,
            size,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<api_models::admin::TransactionDetailsUiConfiguration>
    for diesel_models::TransactionDetailsUiConfiguration
{
    fn convert_from(from: api_models::admin::TransactionDetailsUiConfiguration) -> Self {
        Self {
            position: from.position,
            is_key_bold: from.is_key_bold,
            is_value_bold: from.is_value_bold,
        }
    }
    fn convert_back(self) -> api_models::admin::TransactionDetailsUiConfiguration {
        let Self {
            position,
            is_key_bold,
            is_value_bold,
        } = self;
        api_models::admin::TransactionDetailsUiConfiguration {
            position,
            is_key_bold,
            is_value_bold,
        }
    }
}

#[cfg(feature = "v2")]
impl From<api_models::payments::AmountDetails> for payments::AmountDetails {
    fn from(amount_details: api_models::payments::AmountDetails) -> Self {
        Self {
            order_amount: amount_details.order_amount().into(),
            currency: amount_details.currency(),
            shipping_cost: amount_details.shipping_cost(),
            tax_details: amount_details.order_tax_amount().map(|order_tax_amount| {
                diesel_models::TaxDetails {
                    default: Some(diesel_models::DefaultTax { order_tax_amount }),
                    payment_method_type: None,
                }
            }),
            skip_external_tax_calculation: amount_details.skip_external_tax_calculation(),
            skip_surcharge_calculation: amount_details.skip_surcharge_calculation(),
            surcharge_amount: amount_details.surcharge_amount(),
            tax_on_surcharge: amount_details.tax_on_surcharge(),
            // We will not receive this in the request. This will be populated after calling the connector / processor
            amount_captured: None,
        }
    }
}

#[cfg(feature = "v2")]
impl From<payments::AmountDetails> for api_models::payments::AmountDetailsSetter {
    fn from(amount_details: payments::AmountDetails) -> Self {
        Self {
            order_amount: amount_details.order_amount.into(),
            currency: amount_details.currency,
            shipping_cost: amount_details.shipping_cost,
            order_tax_amount: amount_details
                .tax_details
                .and_then(|tax_detail| tax_detail.get_default_tax_amount()),
            skip_external_tax_calculation: amount_details.skip_external_tax_calculation,
            skip_surcharge_calculation: amount_details.skip_surcharge_calculation,
            surcharge_amount: amount_details.surcharge_amount,
            tax_on_surcharge: amount_details.tax_on_surcharge,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&api_models::payments::PaymentAttemptAmountDetails>
    for payments::payment_attempt::AttemptAmountDetailsSetter
{
    fn from(amount: &api_models::payments::PaymentAttemptAmountDetails) -> Self {
        Self {
            net_amount: amount.net_amount,
            amount_to_capture: amount.amount_to_capture,
            surcharge_amount: amount.surcharge_amount,
            tax_on_surcharge: amount.tax_on_surcharge,
            amount_capturable: amount.amount_capturable,
            shipping_cost: amount.shipping_cost,
            order_tax_amount: amount.order_tax_amount,
            amount_captured: amount.amount_captured,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&payments::payment_attempt::AttemptAmountDetailsSetter>
    for api_models::payments::PaymentAttemptAmountDetails
{
    fn from(amount: &payments::payment_attempt::AttemptAmountDetailsSetter) -> Self {
        Self {
            net_amount: amount.net_amount,
            amount_to_capture: amount.amount_to_capture,
            surcharge_amount: amount.surcharge_amount,
            tax_on_surcharge: amount.tax_on_surcharge,
            amount_capturable: amount.amount_capturable,
            shipping_cost: amount.shipping_cost,
            order_tax_amount: amount.order_tax_amount,
            amount_captured: amount.amount_captured,
        }
    }
}
#[cfg(feature = "v2")]
impl From<&api_models::payments::RecordAttemptErrorDetails>
    for payments::payment_attempt::ErrorDetails
{
    fn from(error: &api_models::payments::RecordAttemptErrorDetails) -> Self {
        Self {
            code: error.code.clone(),
            message: error.message.clone(),
            reason: Some(error.message.clone()),
            unified_code: None,
            unified_message: None,
            network_advice_code: error.network_advice_code.clone(),
            network_decline_code: error.network_decline_code.clone(),
            network_error_message: error.network_error_message.clone(),
        }
    }
}
