// File: crates/kgraph_utils/src/mca.rs
// Module: kgraph_utils
// Public functions: 1

#[cfg(feature = "v1")]
use std::str::FromStr;

#[cfg(feature = "v1")]
use api_models::payment_methods::RequestPaymentMethodTypes;
use api_models::{admin as admin_api, enums as api_enums, refunds::MinorUnit};
use euclid::{
    dirval,
    frontend::{ast, dir},
    types::{NumValue, NumValueRefinement},
};
use hyperswitch_constraint_graph as cgraph;
use strum::IntoEnumIterator;

use crate::{error::KgraphError, transformers::IntoDirValue, types as kgraph_types};

pub const DOMAIN_IDENTIFIER: &str = "payment_methods_enabled_for_merchantconnectoraccount";

// #[cfg(feature = "v1")]
fn get_dir_value_payment_method(
    from: api_enums::PaymentMethodType,
) -> Result<dir::DirValue, KgraphError> {
    match from {
        api_enums::PaymentMethodType::AmazonPay => Ok(dirval!(WalletType = AmazonPay)),
        api_enums::PaymentMethodType::Skrill => Ok(dirval!(WalletType = Skrill)),
        api_enums::PaymentMethodType::Paysera => Ok(dirval!(WalletType = Paysera)),
        api_enums::PaymentMethodType::Credit => Ok(dirval!(CardType = Credit)),
        api_enums::PaymentMethodType::Debit => Ok(dirval!(CardType = Debit)),
        #[cfg(feature = "v2")]
        api_enums::PaymentMethodType::Card => Ok(dirval!(CardType = Card)),
        api_enums::PaymentMethodType::Giropay => Ok(dirval!(BankRedirectType = Giropay)),
        api_enums::PaymentMethodType::Ideal => Ok(dirval!(BankRedirectType = Ideal)),
        api_enums::PaymentMethodType::Sofort => Ok(dirval!(BankRedirectType = Sofort)),
        api_enums::PaymentMethodType::Eps => Ok(dirval!(BankRedirectType = Eps)),
        api_enums::PaymentMethodType::Eft => Ok(dirval!(BankRedirectType = Eft)),
        api_enums::PaymentMethodType::Klarna => Ok(dirval!(PayLaterType = Klarna)),
        api_enums::PaymentMethodType::Flexiti => Ok(dirval!(PayLaterType = Flexiti)),
        api_enums::PaymentMethodType::Affirm => Ok(dirval!(PayLaterType = Affirm)),
        api_enums::PaymentMethodType::AfterpayClearpay => {
            Ok(dirval!(PayLaterType = AfterpayClearpay))
        }
        api_enums::PaymentMethodType::GooglePay => Ok(dirval!(WalletType = GooglePay)),
        api_enums::PaymentMethodType::Bluecode => Ok(dirval!(WalletType = Bluecode)),
        api_enums::PaymentMethodType::ApplePay => Ok(dirval!(WalletType = ApplePay)),
        api_enums::PaymentMethodType::Paypal => Ok(dirval!(WalletType = Paypal)),
        api_enums::PaymentMethodType::CryptoCurrency => Ok(dirval!(CryptoType = CryptoCurrency)),
        api_enums::PaymentMethodType::Ach => Ok(dirval!(BankDebitType = Ach)),

        api_enums::PaymentMethodType::Bacs => Ok(dirval!(BankDebitType = Bacs)),

        api_enums::PaymentMethodType::Becs => Ok(dirval!(BankDebitType = Becs)),
        api_enums::PaymentMethodType::Sepa => Ok(dirval!(BankDebitType = Sepa)),

        api_enums::PaymentMethodType::AliPay => Ok(dirval!(WalletType = AliPay)),
        api_enums::PaymentMethodType::AliPayHk => Ok(dirval!(WalletType = AliPayHk)),
        api_enums::PaymentMethodType::BancontactCard => {
            Ok(dirval!(BankRedirectType = BancontactCard))
        }
        api_enums::PaymentMethodType::Blik => Ok(dirval!(BankRedirectType = Blik)),
        api_enums::PaymentMethodType::MbWay => Ok(dirval!(WalletType = MbWay)),
        api_enums::PaymentMethodType::MobilePay => Ok(dirval!(WalletType = MobilePay)),
        api_enums::PaymentMethodType::Cashapp => Ok(dirval!(WalletType = Cashapp)),
        api_enums::PaymentMethodType::Multibanco => Ok(dirval!(BankTransferType = Multibanco)),
        api_enums::PaymentMethodType::Pix => Ok(dirval!(BankTransferType = Pix)),
        api_enums::PaymentMethodType::Pse => Ok(dirval!(BankTransferType = Pse)),
        api_enums::PaymentMethodType::Interac => Ok(dirval!(BankRedirectType = Interac)),
        api_enums::PaymentMethodType::OnlineBankingCzechRepublic => {
            Ok(dirval!(BankRedirectType = OnlineBankingCzechRepublic))
        }
        api_enums::PaymentMethodType::OnlineBankingFinland => {
            Ok(dirval!(BankRedirectType = OnlineBankingFinland))
        }
        api_enums::PaymentMethodType::OnlineBankingPoland => {
            Ok(dirval!(BankRedirectType = OnlineBankingPoland))
        }
        api_enums::PaymentMethodType::OnlineBankingSlovakia => {
            Ok(dirval!(BankRedirectType = OnlineBankingSlovakia))
        }
        api_enums::PaymentMethodType::Swish => Ok(dirval!(WalletType = Swish)),
        api_enums::PaymentMethodType::Trustly => Ok(dirval!(BankRedirectType = Trustly)),
        api_enums::PaymentMethodType::Bizum => Ok(dirval!(BankRedirectType = Bizum)),

        api_enums::PaymentMethodType::PayBright => Ok(dirval!(PayLaterType = PayBright)),
        api_enums::PaymentMethodType::Walley => Ok(dirval!(PayLaterType = Walley)),
        api_enums::PaymentMethodType::Przelewy24 => Ok(dirval!(BankRedirectType = Przelewy24)),
        api_enums::PaymentMethodType::WeChatPay => Ok(dirval!(WalletType = WeChatPay)),

        api_enums::PaymentMethodType::ClassicReward => Ok(dirval!(RewardType = ClassicReward)),
        api_enums::PaymentMethodType::Evoucher => Ok(dirval!(RewardType = Evoucher)),
        api_enums::PaymentMethodType::SamsungPay => Ok(dirval!(WalletType = SamsungPay)),
        api_enums::PaymentMethodType::GoPay => Ok(dirval!(WalletType = GoPay)),
        api_enums::PaymentMethodType::KakaoPay => Ok(dirval!(WalletType = KakaoPay)),
        api_enums::PaymentMethodType::Twint => Ok(dirval!(WalletType = Twint)),
        api_enums::PaymentMethodType::Gcash => Ok(dirval!(WalletType = Gcash)),
        api_enums::PaymentMethodType::Vipps => Ok(dirval!(WalletType = Vipps)),
        api_enums::PaymentMethodType::Momo => Ok(dirval!(WalletType = Momo)),
        api_enums::PaymentMethodType::Alma => Ok(dirval!(PayLaterType = Alma)),
        api_enums::PaymentMethodType::Dana => Ok(dirval!(WalletType = Dana)),
        api_enums::PaymentMethodType::OnlineBankingFpx => {
            Ok(dirval!(BankRedirectType = OnlineBankingFpx))
        }
        api_enums::PaymentMethodType::OnlineBankingThailand => {
            Ok(dirval!(BankRedirectType = OnlineBankingThailand))
        }
        api_enums::PaymentMethodType::LocalBankRedirect => {
            Ok(dirval!(BankRedirectType = LocalBankRedirect))
        }
        api_enums::PaymentMethodType::TouchNGo => Ok(dirval!(WalletType = TouchNGo)),
        api_enums::PaymentMethodType::Atome => Ok(dirval!(PayLaterType = Atome)),
        api_enums::PaymentMethodType::Boleto => Ok(dirval!(VoucherType = Boleto)),
        api_enums::PaymentMethodType::Efecty => Ok(dirval!(VoucherType = Efecty)),
        api_enums::PaymentMethodType::PagoEfectivo => Ok(dirval!(VoucherType = PagoEfectivo)),
        api_enums::PaymentMethodType::RedCompra => Ok(dirval!(VoucherType = RedCompra)),
        api_enums::PaymentMethodType::RedPagos => Ok(dirval!(VoucherType = RedPagos)),
        api_enums::PaymentMethodType::Alfamart => Ok(dirval!(VoucherType = Alfamart)),
        api_enums::PaymentMethodType::BcaBankTransfer => {
            Ok(dirval!(BankTransferType = BcaBankTransfer))
        }
        api_enums::PaymentMethodType::BniVa => Ok(dirval!(BankTransferType = BniVa)),
        api_enums::PaymentMethodType::BriVa => Ok(dirval!(BankTransferType = BriVa)),
        api_enums::PaymentMethodType::Breadpay => Ok(dirval!(PayLaterType = Breadpay)),
        api_enums::PaymentMethodType::CimbVa => Ok(dirval!(BankTransferType = CimbVa)),
        api_enums::PaymentMethodType::DanamonVa => Ok(dirval!(BankTransferType = DanamonVa)),
        api_enums::PaymentMethodType::Indomaret => Ok(dirval!(VoucherType = Indomaret)),
        api_enums::PaymentMethodType::MandiriVa => Ok(dirval!(BankTransferType = MandiriVa)),
        api_enums::PaymentMethodType::LocalBankTransfer => {
            Ok(dirval!(BankTransferType = LocalBankTransfer))
        }
        api_enums::PaymentMethodType::InstantBankTransfer => {
            Ok(dirval!(BankTransferType = InstantBankTransfer))
        }
        api_enums::PaymentMethodType::InstantBankTransferFinland => {
            Ok(dirval!(BankTransferType = InstantBankTransferFinland))
        }
        api_enums::PaymentMethodType::InstantBankTransferPoland => {
            Ok(dirval!(BankTransferType = InstantBankTransferPoland))
        }
        api_enums::PaymentMethodType::SepaBankTransfer => {
            Ok(dirval!(BankTransferType = SepaBankTransfer))
        }
        api_enums::PaymentMethodType::PermataBankTransfer => {
            Ok(dirval!(BankTransferType = PermataBankTransfer))
        }
        api_enums::PaymentMethodType::IndonesianBankTransfer => {
            Ok(dirval!(BankTransferType = IndonesianBankTransfer))
        }
        api_enums::PaymentMethodType::PaySafeCard => Ok(dirval!(GiftCardType = PaySafeCard)),
        api_enums::PaymentMethodType::SevenEleven => Ok(dirval!(VoucherType = SevenEleven)),
        api_enums::PaymentMethodType::Lawson => Ok(dirval!(VoucherType = Lawson)),
        api_enums::PaymentMethodType::MiniStop => Ok(dirval!(VoucherType = MiniStop)),
        api_enums::PaymentMethodType::FamilyMart => Ok(dirval!(VoucherType = FamilyMart)),
        api_enums::PaymentMethodType::Seicomart => Ok(dirval!(VoucherType = Seicomart)),
        api_enums::PaymentMethodType::PayEasy => Ok(dirval!(VoucherType = PayEasy)),
        api_enums::PaymentMethodType::Givex => Ok(dirval!(GiftCardType = Givex)),
        api_enums::PaymentMethodType::BhnCardNetwork => Ok(dirval!(GiftCardType = BhnCardNetwork)),
        api_enums::PaymentMethodType::Benefit => Ok(dirval!(CardRedirectType = Benefit)),
        api_enums::PaymentMethodType::Knet => Ok(dirval!(CardRedirectType = Knet)),
        api_enums::PaymentMethodType::OpenBankingUk => {
            Ok(dirval!(BankRedirectType = OpenBankingUk))
        }
        api_enums::PaymentMethodType::MomoAtm => Ok(dirval!(CardRedirectType = MomoAtm)),
        api_enums::PaymentMethodType::Oxxo => Ok(dirval!(VoucherType = Oxxo)),
        api_enums::PaymentMethodType::CardRedirect => Ok(dirval!(CardRedirectType = CardRedirect)),
        api_enums::PaymentMethodType::Venmo => Ok(dirval!(WalletType = Venmo)),
        api_enums::PaymentMethodType::UpiIntent => Ok(dirval!(UpiType = UpiIntent)),
        api_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)),
        api_enums::PaymentMethodType::Mifinity => Ok(dirval!(WalletType = Mifinity)),
        api_enums::PaymentMethodType::Fps => Ok(dirval!(RealTimePaymentType = Fps)),
        api_enums::PaymentMethodType::DuitNow => Ok(dirval!(RealTimePaymentType = DuitNow)),
        api_enums::PaymentMethodType::PromptPay => Ok(dirval!(RealTimePaymentType = PromptPay)),
        api_enums::PaymentMethodType::VietQr => Ok(dirval!(RealTimePaymentType = VietQr)),
        api_enums::PaymentMethodType::OpenBankingPIS => {
            Ok(dirval!(OpenBankingType = OpenBankingPIS))
        }
        api_enums::PaymentMethodType::Paze => Ok(dirval!(WalletType = Paze)),
        api_enums::PaymentMethodType::DirectCarrierBilling => {
            Ok(dirval!(MobilePaymentType = DirectCarrierBilling))
        }
        api_enums::PaymentMethodType::RevolutPay => Ok(dirval!(WalletType = RevolutPay)),
    }
}

#[cfg(feature = "v2")]
fn compile_request_pm_types(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    pm_types: common_types::payment_methods::RequestPaymentMethodTypes,
    pm: api_enums::PaymentMethod,
) -> Result<cgraph::NodeId, KgraphError> {
    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();

    let pmt_info = "PaymentMethodType";
    let pmt_id = builder.make_value_node(
        (pm_types.payment_method_subtype, pm)
            .into_dir_value()
            .map(Into::into)?,
        Some(pmt_info),
        None::<()>,
    );
    agg_nodes.push((
        pmt_id,
        cgraph::Relation::Positive,
        match pm_types.payment_method_subtype {
            api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => {
                cgraph::Strength::Weak
            }

            _ => cgraph::Strength::Strong,
        },
    ));

    if let Some(card_networks) = pm_types.card_networks {
        if !card_networks.is_empty() {
            let dir_vals: Vec<dir::DirValue> = card_networks
                .into_iter()
                .map(IntoDirValue::into_dir_value)
                .collect::<Result<_, _>>()?;

            let card_network_info = "Card Networks";
            let card_network_id = builder
                .make_in_aggregator(dir_vals, Some(card_network_info), None::<()>)
                .map_err(KgraphError::GraphConstructionError)?;

            agg_nodes.push((
                card_network_id,
                cgraph::Relation::Positive,
                cgraph::Strength::Weak,
            ));
        }
    }

    let currencies_data = pm_types
        .accepted_currencies
        .and_then(|accepted_currencies| match accepted_currencies {
            common_types::payment_methods::AcceptedCurrencies::EnableOnly(curr)
                if !curr.is_empty() =>
            {
                Some((
                    curr.into_iter()
                        .map(IntoDirValue::into_dir_value)
                        .collect::<Result<_, _>>()
                        .ok()?,
                    cgraph::Relation::Positive,
                ))
            }

            common_types::payment_methods::AcceptedCurrencies::DisableOnly(curr)
                if !curr.is_empty() =>
            {
                Some((
                    curr.into_iter()
                        .map(IntoDirValue::into_dir_value)
                        .collect::<Result<_, _>>()
                        .ok()?,
                    cgraph::Relation::Negative,
                ))
            }

            _ => None,
        });

    if let Some((currencies, relation)) = currencies_data {
        let accepted_currencies_info = "Accepted Currencies";
        let accepted_currencies_id = builder
            .make_in_aggregator(currencies, Some(accepted_currencies_info), None::<()>)
            .map_err(KgraphError::GraphConstructionError)?;

        agg_nodes.push((accepted_currencies_id, relation, cgraph::Strength::Strong));
    }

    let mut amount_nodes = Vec::with_capacity(2);

    if let Some(min_amt) = pm_types.minimum_amount {
        let num_val = NumValue {
            number: min_amt,
            refinement: Some(NumValueRefinement::GreaterThanEqual),
        };

        let min_amt_info = "Minimum Amount";
        let min_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(num_val).into(),
            Some(min_amt_info),
            None::<()>,
        );

        amount_nodes.push(min_amt_id);
    }

    if let Some(max_amt) = pm_types.maximum_amount {
        let num_val = NumValue {
            number: max_amt,
            refinement: Some(NumValueRefinement::LessThanEqual),
        };

        let max_amt_info = "Maximum Amount";
        let max_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(num_val).into(),
            Some(max_amt_info),
            None::<()>,
        );

        amount_nodes.push(max_amt_id);
    }

    if !amount_nodes.is_empty() {
        let zero_num_val = NumValue {
            number: MinorUnit::zero(),
            refinement: None,
        };

        let zero_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(zero_num_val).into(),
            Some("zero_amount"),
            None::<()>,
        );

        let or_node_neighbor_id = if amount_nodes.len() == 1 {
            amount_nodes
                .first()
                .copied()
                .ok_or(KgraphError::IndexingError)?
        } else {
            let nodes = amount_nodes
                .iter()
                .copied()
                .map(|node_id| {
                    (
                        node_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    )
                })
                .collect::<Vec<_>>();

            builder
                .make_all_aggregator(
                    &nodes,
                    Some("amount_constraint_aggregator"),
                    None::<()>,
                    None,
                )
                .map_err(KgraphError::GraphConstructionError)?
        };

        let any_aggregator = builder
            .make_any_aggregator(
                &[
                    (
                        zero_amt_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                    (
                        or_node_neighbor_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                ],
                Some("zero_plus_limits_amount_aggregator"),
                None::<()>,
                None,
            )
            .map_err(KgraphError::GraphConstructionError)?;

        agg_nodes.push((
            any_aggregator,
            cgraph::Relation::Positive,
            cgraph::Strength::Strong,
        ));
    }

    let pmt_all_aggregator_info = "All Aggregator for PaymentMethodType";
    builder
        .make_all_aggregator(&agg_nodes, Some(pmt_all_aggregator_info), None::<()>, None)
        .map_err(KgraphError::GraphConstructionError)
}

#[cfg(feature = "v1")]
fn compile_request_pm_types(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    pm_types: RequestPaymentMethodTypes,
    pm: api_enums::PaymentMethod,
) -> Result<cgraph::NodeId, KgraphError> {
    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();

    let pmt_info = "PaymentMethodType";
    let pmt_id = builder.make_value_node(
        (pm_types.payment_method_type, pm)
            .into_dir_value()
            .map(Into::into)?,
        Some(pmt_info),
        None::<()>,
    );
    agg_nodes.push((
        pmt_id,
        cgraph::Relation::Positive,
        match pm_types.payment_method_type {
            api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => {
                cgraph::Strength::Weak
            }

            _ => cgraph::Strength::Strong,
        },
    ));

    if let Some(card_networks) = pm_types.card_networks {
        if !card_networks.is_empty() {
            let dir_vals: Vec<dir::DirValue> = card_networks
                .into_iter()
                .map(IntoDirValue::into_dir_value)
                .collect::<Result<_, _>>()?;

            let card_network_info = "Card Networks";
            let card_network_id = builder
                .make_in_aggregator(dir_vals, Some(card_network_info), None::<()>)
                .map_err(KgraphError::GraphConstructionError)?;

            agg_nodes.push((
                card_network_id,
                cgraph::Relation::Positive,
                cgraph::Strength::Weak,
            ));
        }
    }

    let currencies_data = pm_types
        .accepted_currencies
        .and_then(|accepted_currencies| match accepted_currencies {
            admin_api::AcceptedCurrencies::EnableOnly(curr) if !curr.is_empty() => Some((
                curr.into_iter()
                    .map(IntoDirValue::into_dir_value)
                    .collect::<Result<_, _>>()
                    .ok()?,
                cgraph::Relation::Positive,
            )),

            admin_api::AcceptedCurrencies::DisableOnly(curr) if !curr.is_empty() => Some((
                curr.into_iter()
                    .map(IntoDirValue::into_dir_value)
                    .collect::<Result<_, _>>()
                    .ok()?,
                cgraph::Relation::Negative,
            )),

            _ => None,
        });

    if let Some((currencies, relation)) = currencies_data {
        let accepted_currencies_info = "Accepted Currencies";
        let accepted_currencies_id = builder
            .make_in_aggregator(currencies, Some(accepted_currencies_info), None::<()>)
            .map_err(KgraphError::GraphConstructionError)?;

        agg_nodes.push((accepted_currencies_id, relation, cgraph::Strength::Strong));
    }

    let mut amount_nodes = Vec::with_capacity(2);

    if let Some(min_amt) = pm_types.minimum_amount {
        let num_val = NumValue {
            number: min_amt,
            refinement: Some(NumValueRefinement::GreaterThanEqual),
        };

        let min_amt_info = "Minimum Amount";
        let min_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(num_val).into(),
            Some(min_amt_info),
            None::<()>,
        );

        amount_nodes.push(min_amt_id);
    }

    if let Some(max_amt) = pm_types.maximum_amount {
        let num_val = NumValue {
            number: max_amt,
            refinement: Some(NumValueRefinement::LessThanEqual),
        };

        let max_amt_info = "Maximum Amount";
        let max_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(num_val).into(),
            Some(max_amt_info),
            None::<()>,
        );

        amount_nodes.push(max_amt_id);
    }

    if !amount_nodes.is_empty() {
        let zero_num_val = NumValue {
            number: MinorUnit::zero(),
            refinement: None,
        };

        let zero_amt_id = builder.make_value_node(
            dir::DirValue::PaymentAmount(zero_num_val).into(),
            Some("zero_amount"),
            None::<()>,
        );

        let or_node_neighbor_id = if amount_nodes.len() == 1 {
            amount_nodes
                .first()
                .copied()
                .ok_or(KgraphError::IndexingError)?
        } else {
            let nodes = amount_nodes
                .iter()
                .copied()
                .map(|node_id| {
                    (
                        node_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    )
                })
                .collect::<Vec<_>>();

            builder
                .make_all_aggregator(
                    &nodes,
                    Some("amount_constraint_aggregator"),
                    None::<()>,
                    None,
                )
                .map_err(KgraphError::GraphConstructionError)?
        };

        let any_aggregator = builder
            .make_any_aggregator(
                &[
                    (
                        zero_amt_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                    (
                        or_node_neighbor_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                ],
                Some("zero_plus_limits_amount_aggregator"),
                None::<()>,
                None,
            )
            .map_err(KgraphError::GraphConstructionError)?;

        agg_nodes.push((
            any_aggregator,
            cgraph::Relation::Positive,
            cgraph::Strength::Strong,
        ));
    }

    let pmt_all_aggregator_info = "All Aggregator for PaymentMethodType";
    builder
        .make_all_aggregator(&agg_nodes, Some(pmt_all_aggregator_info), None::<()>, None)
        .map_err(KgraphError::GraphConstructionError)
}

#[cfg(feature = "v2")]
fn compile_payment_method_enabled(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    enabled: common_types::payment_methods::PaymentMethodsEnabled,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let agg_id = if !enabled
        .payment_method_subtypes
        .as_ref()
        .map(|v| v.is_empty())
        .unwrap_or(true)
    {
        let pm_info = "PaymentMethod";
        let pm_id = builder.make_value_node(
            enabled
                .payment_method_type
                .into_dir_value()
                .map(Into::into)?,
            Some(pm_info),
            None::<()>,
        );

        let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();

        if let Some(pm_types) = enabled.payment_method_subtypes {
            for pm_type in pm_types {
                let node_id =
                    compile_request_pm_types(builder, pm_type, enabled.payment_method_type)?;
                agg_nodes.push((
                    node_id,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Strong,
                ));
            }
        }

        let any_aggregator_info = "Any aggregation for PaymentMethodsType";
        let pm_type_agg_id = builder
            .make_any_aggregator(&agg_nodes, Some(any_aggregator_info), None::<()>, None)
            .map_err(KgraphError::GraphConstructionError)?;

        let all_aggregator_info = "All aggregation for PaymentMethod";
        let enabled_pm_agg_id = builder
            .make_all_aggregator(
                &[
                    (pm_id, cgraph::Relation::Positive, cgraph::Strength::Strong),
                    (
                        pm_type_agg_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                ],
                Some(all_aggregator_info),
                None::<()>,
                None,
            )
            .map_err(KgraphError::GraphConstructionError)?;

        Some(enabled_pm_agg_id)
    } else {
        None
    };

    Ok(agg_id)
}

#[cfg(feature = "v1")]
fn compile_payment_method_enabled(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    enabled: admin_api::PaymentMethodsEnabled,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let agg_id = if !enabled
        .payment_method_types
        .as_ref()
        .map(|v| v.is_empty())
        .unwrap_or(true)
    {
        let pm_info = "PaymentMethod";
        let pm_id = builder.make_value_node(
            enabled.payment_method.into_dir_value().map(Into::into)?,
            Some(pm_info),
            None::<()>,
        );

        let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();

        if let Some(pm_types) = enabled.payment_method_types {
            for pm_type in pm_types {
                let node_id = compile_request_pm_types(builder, pm_type, enabled.payment_method)?;
                agg_nodes.push((
                    node_id,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Strong,
                ));
            }
        }

        let any_aggregator_info = "Any aggregation for PaymentMethodsType";
        let pm_type_agg_id = builder
            .make_any_aggregator(&agg_nodes, Some(any_aggregator_info), None::<()>, None)
            .map_err(KgraphError::GraphConstructionError)?;

        let all_aggregator_info = "All aggregation for PaymentMethod";
        let enabled_pm_agg_id = builder
            .make_all_aggregator(
                &[
                    (pm_id, cgraph::Relation::Positive, cgraph::Strength::Strong),
                    (
                        pm_type_agg_id,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Strong,
                    ),
                ],
                Some(all_aggregator_info),
                None::<()>,
                None,
            )
            .map_err(KgraphError::GraphConstructionError)?;

        Some(enabled_pm_agg_id)
    } else {
        None
    };

    Ok(agg_id)
}

macro_rules! collect_global_variants {
    ($parent_enum:ident) => {
        &mut dir::enums::$parent_enum::iter()
            .map(dir::DirValue::$parent_enum)
            .collect::<Vec<_>>()
    };
}

// #[cfg(feature = "v1")]
fn global_vec_pmt(
    enabled_pmt: Vec<dir::DirValue>,
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
) -> Vec<cgraph::NodeId> {
    let mut global_vector: Vec<dir::DirValue> = Vec::new();

    global_vector.append(collect_global_variants!(PayLaterType));
    global_vector.append(collect_global_variants!(WalletType));
    global_vector.append(collect_global_variants!(BankRedirectType));
    global_vector.append(collect_global_variants!(BankDebitType));
    global_vector.append(collect_global_variants!(CryptoType));
    global_vector.append(collect_global_variants!(RewardType));
    global_vector.append(collect_global_variants!(RealTimePaymentType));
    global_vector.append(collect_global_variants!(UpiType));
    global_vector.append(collect_global_variants!(VoucherType));
    global_vector.append(collect_global_variants!(GiftCardType));
    global_vector.append(collect_global_variants!(BankTransferType));
    global_vector.append(collect_global_variants!(CardRedirectType));
    global_vector.append(collect_global_variants!(OpenBankingType));
    global_vector.append(collect_global_variants!(MobilePaymentType));
    global_vector.push(dir::DirValue::PaymentMethod(
        dir::enums::PaymentMethod::Card,
    ));

    let global_vector = global_vector
        .into_iter()
        .filter(|global_value| !enabled_pmt.contains(global_value))
        .collect::<Vec<_>>();

    global_vector
        .into_iter()
        .map(|dir_v| {
            builder.make_value_node(
                cgraph::NodeValue::Value(dir_v),
                Some("Payment Method Type"),
                None::<()>,
            )
        })
        .collect::<Vec<_>>()
}

fn compile_graph_for_countries_and_currencies(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    config: &kgraph_types::CurrencyCountryFlowFilter,
    payment_method_type_node: cgraph::NodeId,
) -> Result<cgraph::NodeId, KgraphError> {
    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();
    agg_nodes.push((
        payment_method_type_node,
        cgraph::Relation::Positive,
        cgraph::Strength::Normal,
    ));
    if let Some(country) = config.country.clone() {
        let node_country = country
            .into_iter()
            .map(|country| dir::DirValue::BillingCountry(api_enums::Country::from_alpha2(country)))
            .collect();
        let country_agg = builder
            .make_in_aggregator(node_country, Some("Configs for Country"), None::<()>)
            .map_err(KgraphError::GraphConstructionError)?;
        agg_nodes.push((
            country_agg,
            cgraph::Relation::Positive,
            cgraph::Strength::Weak,
        ))
    }

    if let Some(currency) = config.currency.clone() {
        let node_currency = currency
            .into_iter()
            .map(IntoDirValue::into_dir_value)
            .collect::<Result<Vec<_>, _>>()?;
        let currency_agg = builder
            .make_in_aggregator(node_currency, Some("Configs for Currency"), None::<()>)
            .map_err(KgraphError::GraphConstructionError)?;
        agg_nodes.push((
            currency_agg,
            cgraph::Relation::Positive,
            cgraph::Strength::Normal,
        ))
    }
    if let Some(capture_method) = config
        .not_available_flows
        .and_then(|naf| naf.capture_method)
    {
        let make_capture_node = builder.make_value_node(
            cgraph::NodeValue::Value(dir::DirValue::CaptureMethod(capture_method)),
            Some("Configs for CaptureMethod"),
            None::<()>,
        );
        agg_nodes.push((
            make_capture_node,
            cgraph::Relation::Negative,
            cgraph::Strength::Normal,
        ))
    }

    builder
        .make_all_aggregator(
            &agg_nodes,
            Some("Country & Currency Configs With Payment Method Type"),
            None::<()>,
            None,
        )
        .map_err(KgraphError::GraphConstructionError)
}

// #[cfg(feature = "v1")]
fn compile_config_graph(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    config: &kgraph_types::CountryCurrencyFilter,
    connector: api_enums::RoutableConnectors,
) -> Result<cgraph::NodeId, KgraphError> {
    let mut agg_node_id: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();
    let mut pmt_enabled: Vec<dir::DirValue> = Vec::new();
    if let Some(pmt) = config
        .connector_configs
        .get(&connector)
        .or(config.default_configs.as_ref())
        .map(|inner| inner.0.clone())
    {
        for pm_filter_key in pmt {
            match pm_filter_key {
                (kgraph_types::PaymentMethodFilterKey::PaymentMethodType(pm), filter) => {
                    let dir_val_pm = get_dir_value_payment_method(pm)?;

                    let pm_node = if pm == api_enums::PaymentMethodType::Credit
                        || pm == api_enums::PaymentMethodType::Debit
                    {
                        pmt_enabled
                            .push(dir::DirValue::PaymentMethod(api_enums::PaymentMethod::Card));
                        builder.make_value_node(
                            cgraph::NodeValue::Value(dir::DirValue::PaymentMethod(
                                dir::enums::PaymentMethod::Card,
                            )),
                            Some("PaymentMethod"),
                            None::<()>,
                        )
                    } else {
                        pmt_enabled.push(dir_val_pm.clone());
                        builder.make_value_node(
                            cgraph::NodeValue::Value(dir_val_pm),
                            Some("PaymentMethodType"),
                            None::<()>,
                        )
                    };

                    let node_config =
                        compile_graph_for_countries_and_currencies(builder, &filter, pm_node)?;

                    agg_node_id.push((
                        node_config,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Normal,
                    ));
                }
                (kgraph_types::PaymentMethodFilterKey::CardNetwork(cn), filter) => {
                    let dir_val_cn = cn.clone().into_dir_value()?;
                    pmt_enabled.push(dir_val_cn);
                    let cn_node = builder.make_value_node(
                        cn.clone().into_dir_value().map(Into::into)?,
                        Some("CardNetwork"),
                        None::<()>,
                    );
                    let node_config =
                        compile_graph_for_countries_and_currencies(builder, &filter, cn_node)?;

                    agg_node_id.push((
                        node_config,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Normal,
                    ));
                }
            }
        }
    }
    let global_vector_pmt: Vec<cgraph::NodeId> = global_vec_pmt(pmt_enabled, builder);
    let any_agg_pmt: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = global_vector_pmt
        .into_iter()
        .map(|node| (node, cgraph::Relation::Positive, cgraph::Strength::Normal))
        .collect::<Vec<_>>();
    let any_agg_node = builder
        .make_any_aggregator(
            &any_agg_pmt,
            Some("Any Aggregator For Payment Method Types"),
            None::<()>,
            None,
        )
        .map_err(KgraphError::GraphConstructionError)?;

    agg_node_id.push((
        any_agg_node,
        cgraph::Relation::Positive,
        cgraph::Strength::Normal,
    ));

    builder
        .make_any_aggregator(&agg_node_id, Some("Configs"), None::<()>, None)
        .map_err(KgraphError::GraphConstructionError)
}

#[cfg(feature = "v2")]
fn compile_merchant_connector_graph(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,


// Implementation: impl api::RefundExecute for for Silverflow
// File: crates/hyperswitch_connectors/src/connectors/silverflow.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Silverflow


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

pub struct CybersourceTransactionResponse


// File: crates/scheduler/src/configs/defaults.rs
// Module: scheduler

impl Default for super::settings::SchedulerSettings {
    fn default() -> Self {
        Self {
            stream: "SCHEDULER_STREAM".into(),
            producer: super::settings::ProducerSettings::default(),
            consumer: super::settings::ConsumerSettings::default(),
            graceful_shutdown_interval: 60000,
            loop_interval: 5000,
            server: super::settings::Server::default(),
        }
    }
}

impl Default for super::settings::ProducerSettings {
    fn default() -> Self {
        Self {
            upper_fetch_limit: 0,
            lower_fetch_limit: 1800,
            lock_key: "PRODUCER_LOCKING_KEY".into(),
            lock_ttl: 160,
            batch_size: 200,
        }
    }
}

impl Default for super::settings::ConsumerSettings {
    fn default() -> Self {
        Self {
            disabled: false,
            consumer_group: "SCHEDULER_GROUP".into(),
        }
    }
}

impl Default for super::settings::Server {
    fn default() -> Self {
        Self {
            port: 8080,
            workers: num_cpus::get_physical(),
            host: "localhost".into(),
        }
    }
}


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

pub fn new(
        app_ip: Option<std::net::IpAddr>,
        psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,
        force_3ds_challenge: bool,
        message_version: SemanticVersion,
    ) -> Self


// Function: update_dispute_evidence
// File: crates/router/src/core/disputes/transformers.rs
// Module: router

pub fn update_dispute_evidence(
    dispute_evidence: DisputeEvidence,
    evidence_type: api::EvidenceType,
    file_id: String,
) -> DisputeEvidence


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

impl api::RefundSync for for Facilitapay


// Struct: FlowResponse
// File: crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FlowResponse


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

impl api::PaymentSync for for Stax


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

pub struct DeletePaymentMethodFromVault


// File: crates/common_utils/src/id_type/global_id.rs
// Module: common_utils
// Public functions: 2
// Public structs: 1

pub(super) mod customer;
pub(super) mod payment;
pub(super) mod payment_methods;
pub(super) mod refunds;
pub(super) mod token;

use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types};
use error_stack::ResultExt;
use thiserror::Error;

use crate::{
    consts::{CELL_IDENTIFIER_LENGTH, MAX_GLOBAL_ID_LENGTH, MIN_GLOBAL_ID_LENGTH},
    errors, generate_time_ordered_id,
    id_type::{AlphaNumericId, AlphaNumericIdError, LengthId, LengthIdError},
};

#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize)]
/// A global id that can be used to identify any entity
/// This id will have information about the entity and cell in a distributed system architecture
pub(crate) struct GlobalId(LengthId<MAX_GLOBAL_ID_LENGTH, MIN_GLOBAL_ID_LENGTH>);

#[derive(Clone, Copy)]
/// Entities that can be identified by a global id
pub(crate) enum GlobalEntity {
    Customer,
    Payment,
    Attempt,
    PaymentMethod,
    Refund,
    PaymentMethodSession,
    Token,
}

impl GlobalEntity {
    fn prefix(self) -> &'static str {
        match self {
            Self::Customer => "cus",
            Self::Payment => "pay",
            Self::PaymentMethod => "pm",
            Self::Attempt => "att",
            Self::Refund => "ref",
            Self::PaymentMethodSession => "pms",
            Self::Token => "tok",
        }
    }
}

/// Cell identifier for an instance / deployment of application
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct CellId(LengthId<CELL_IDENTIFIER_LENGTH, CELL_IDENTIFIER_LENGTH>);

#[derive(Debug, Error, PartialEq, Eq)]
pub enum CellIdError {
    #[error("cell id error: {0}")]
    InvalidCellLength(LengthIdError),

    #[error("{0}")]
    InvalidCellIdFormat(AlphaNumericIdError),
}

impl From<LengthIdError> for CellIdError {
    fn from(error: LengthIdError) -> Self {
        Self::InvalidCellLength(error)
    }
}

impl From<AlphaNumericIdError> for CellIdError {
    fn from(error: AlphaNumericIdError) -> Self {
        Self::InvalidCellIdFormat(error)
    }
}

impl CellId {
    /// Create a new cell id from a string
    fn from_str(cell_id_string: impl AsRef<str>) -> Result<Self, CellIdError> {
        let trimmed_input_string = cell_id_string.as_ref().trim().to_string();
        let alphanumeric_id = AlphaNumericId::from(trimmed_input_string.into())?;
        let length_id = LengthId::from_alphanumeric_id(alphanumeric_id)?;
        Ok(Self(length_id))
    }

    /// Create a new cell id from a string
    pub fn from_string(
        input_string: impl AsRef<str>,
    ) -> error_stack::Result<Self, errors::ValidationError> {
        Self::from_str(input_string).change_context(
            errors::ValidationError::IncorrectValueProvided {
                field_name: "cell_id",
            },
        )
    }

    /// Get the string representation of the cell id
    fn get_string_repr(&self) -> &str {
        &self.0 .0 .0
    }
}

impl<'de> serde::Deserialize<'de> for CellId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized_string = String::deserialize(deserializer)?;
        Self::from_str(deserialized_string.as_str()).map_err(serde::de::Error::custom)
    }
}

/// Error generated from violation of constraints for MerchantReferenceId
#[derive(Debug, Error, PartialEq, Eq)]
pub(crate) enum GlobalIdError {
    /// The format for the global id is invalid
    #[error("The id format is invalid, expected format is {{cell_id:5}}_{{entity_prefix:3}}_{{uuid:32}}_{{random:24}}")]
    InvalidIdFormat,

    /// LengthIdError and AlphanumericIdError
    #[error("{0}")]
    LengthIdError(#[from] LengthIdError),

    /// CellIdError because of invalid cell id format
    #[error("{0}")]
    CellIdError(#[from] CellIdError),
}

impl GlobalId {
    /// Create a new global id from entity and cell information
    /// The entity prefix is used to identify the entity, `cus` for customers, `pay`` for payments etc.
    pub fn generate(cell_id: &CellId, entity: GlobalEntity) -> Self {
        let prefix = format!("{}_{}", cell_id.get_string_repr(), entity.prefix());
        let id = generate_time_ordered_id(&prefix);
        let alphanumeric_id = AlphaNumericId::new_unchecked(id);
        Self(LengthId::new_unchecked(alphanumeric_id))
    }

    pub(crate) fn from_string(
        input_string: std::borrow::Cow<'static, str>,
    ) -> Result<Self, GlobalIdError> {
        let length_id = LengthId::from(input_string)?;
        let input_string = &length_id.0 .0;
        let (cell_id, _remaining) = input_string
            .split_once("_")
            .ok_or(GlobalIdError::InvalidIdFormat)?;

        CellId::from_str(cell_id)?;

        Ok(Self(length_id))
    }

    pub(crate) fn get_string_repr(&self) -> &str {
        &self.0 .0 .0
    }
}

impl<DB> ToSql<sql_types::Text, DB> for GlobalId
where
    DB: Backend,
    String: ToSql<sql_types::Text, DB>,
{
    fn to_sql<'b>(
        &'b self,
        out: &mut diesel::serialize::Output<'b, '_, DB>,
    ) -> diesel::serialize::Result {
        self.0 .0 .0.to_sql(out)
    }
}

impl<DB> FromSql<sql_types::Text, DB> for GlobalId
where
    DB: Backend,
    String: FromSql<sql_types::Text, DB>,
{
    fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
        let string_val = String::from_sql(value)?;
        let alphanumeric_id = AlphaNumericId::from(string_val.into())?;
        let length_id = LengthId::from_alphanumeric_id(alphanumeric_id)?;
        Ok(Self(length_id))
    }
}

/// Deserialize the global id from string
/// The format should match {cell_id:5}_{entity_prefix:3}_{time_ordered_id:32}_{.*:24}
impl<'de> serde::Deserialize<'de> for GlobalId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized_string = String::deserialize(deserializer)?;
        Self::from_string(deserialized_string.into()).map_err(serde::de::Error::custom)
    }
}

#[cfg(test)]
mod global_id_tests {
    #![allow(clippy::unwrap_used)]
    use super::*;

    #[test]
    fn test_cell_id_from_str() {
        let cell_id_string = "12345";
        let cell_id = CellId::from_str(cell_id_string).unwrap();
        assert_eq!(cell_id.get_string_repr(), cell_id_string);
    }

    #[test]
    fn test_global_id_generate() {
        let cell_id_string = "12345";
        let entity = GlobalEntity::Customer;
        let cell_id = CellId::from_str(cell_id_string).unwrap();
        let global_id = GlobalId::generate(&cell_id, entity);

        // Generate a regex for globalid
        // Eg - 12abc_cus_abcdefghijklmnopqrstuvwxyz1234567890
        let regex = regex::Regex::new(r"[a-z0-9]{5}_cus_[a-z0-9]{32}").unwrap();

        assert!(regex.is_match(&global_id.0 .0 .0));
    }

    #[test]
    fn test_global_id_from_string() {
        let input_string = "12345_cus_abcdefghijklmnopqrstuvwxyz1234567890";
        let global_id = GlobalId::from_string(input_string.into()).unwrap();
        assert_eq!(global_id.0 .0 .0, input_string);
    }

    #[test]
    fn test_global_id_deser() {
        let input_string_for_serde_json_conversion =
            r#""12345_cus_abcdefghijklmnopqrstuvwxyz1234567890""#;

        let input_string = "12345_cus_abcdefghijklmnopqrstuvwxyz1234567890";
        let global_id =
            serde_json::from_str::<GlobalId>(input_string_for_serde_json_conversion).unwrap();
        assert_eq!(global_id.0 .0 .0, input_string);
    }

    #[test]
    fn test_global_id_deser_error() {
        let input_string_for_serde_json_conversion =
            r#""123_45_cus_abcdefghijklmnopqrstuvwxyz1234567890""#;

        let global_id = serde_json::from_str::<GlobalId>(input_string_for_serde_json_conversion);
        assert!(global_id.is_err());

        let expected_error_message = format!(
            "cell id error: the minimum required length for this field is {CELL_IDENTIFIER_LENGTH}"
        );

        let error_message = global_id.unwrap_err().to_string();
        assert_eq!(error_message, expected_error_message);
    }
}


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

pub struct NordeaPaymentsResponseWrapper


// File: crates/common_utils/src/types/authentication.rs
// Module: common_utils
// Public functions: 1

use crate::id_type;

/// Enum for different levels of authentication
#[derive(
    Clone,
    Debug,
    Hash,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
)]
pub enum AuthInfo {
    /// OrgLevel: Authentication at the organization level
    OrgLevel {
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
    },
    /// MerchantLevel: Authentication at the merchant level
    MerchantLevel {
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
        /// merchant_ids: Vec<MerchantId>
        merchant_ids: Vec<id_type::MerchantId>,
    },
    /// ProfileLevel: Authentication at the profile level
    ProfileLevel {
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
        /// merchant_id: MerchantId
        merchant_id: id_type::MerchantId,
        /// profile_ids: Vec<ProfileId>
        profile_ids: Vec<id_type::ProfileId>,
    },
}

/// Enum for different resource types supported in client secret
#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ResourceId {
    /// Global Payment ID (Not exposed in api_models version of enum)
    Payment(id_type::GlobalPaymentId),
    /// Global Customer ID
    Customer(id_type::GlobalCustomerId),
    /// Global Payment Methods Session ID
    PaymentMethodSession(id_type::GlobalPaymentMethodSessionId),
}

#[cfg(feature = "v2")]
impl ResourceId {
    /// Get string representation of enclosed ID type
    pub fn to_str(&self) -> &str {
        match self {
            Self::Payment(id) => id.get_string_repr(),
            Self::Customer(id) => id.get_string_repr(),
            Self::PaymentMethodSession(id) => id.get_string_repr(),
        }
    }
}


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

pub struct RoleInfoWithParents


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

pub fn insert_merchant_configs(
    db: &dyn StorageInterface,
    merchant_id: &id_type::MerchantId,
) -> RouterResult<()>


// Implementation: impl DummyConnectorNextAction
// File: crates/hyperswitch_connectors/src/connectors/dummyconnector/transformers.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl DummyConnectorNextAction


// Struct: WisePayoutCreateRequest
// File: crates/hyperswitch_connectors/src/connectors/wise/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WisePayoutCreateRequest


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

impl api::MandateSetup for for Tokenio


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

impl api::PaymentAuthorize for for Forte


// Struct: MandateUpdateMems
// File: crates/diesel_models/src/kv.rs
// Module: diesel_models
// Implementations: 0

pub struct MandateUpdateMems


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

impl api::ConnectorCustomer for for Authorizedotnet


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

pub fn perform_cgraph_filtering(
    state: &SessionState,
    key_store: &domain::MerchantKeyStore,
    chosen: Vec<routing_types::RoutableConnectorChoice>,
    backend_input: dsl_inputs::BackendInput,
    eligible_connectors: Option<&Vec<api_enums::RoutableConnectors>>,
    profile_id: &common_utils::id_type::ProfileId,
    transaction_type: &api_enums::TransactionType,
) -> RoutingResult<Vec<routing_types::RoutableConnectorChoice>>


// Function: payment_link_retrieve
// File: crates/router/src/routes/payment_link.rs
// Module: router

pub fn payment_link_retrieve(
    state: web::Data<AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<String>,
    json_payload: web::Query<api_models::payments::RetrievePaymentLinkRequest>,
) -> impl Responder


// Struct: Edge
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Implementations: 0

pub struct Edge


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

pub struct IssuerInformation


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

use api_models::analytics::{payments::PaymentDimensions, Granularity, TimeRange};
use common_utils::errors::ReportSwitchExt;
use diesel_models::enums::{AttemptStatus, AuthenticationType, Currency, RoutingApproach};
use error_stack::ResultExt;
use time::PrimitiveDateTime;

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

pub trait PaymentFilterAnalytics: LoadRow<PaymentFilterRow> {}

pub async fn get_payment_filter_for_dimension<T>(
    dimension: PaymentDimensions,
    auth: &AuthInfo,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<PaymentFilterRow>>
where
    T: AnalyticsDataSource + PaymentFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);

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

    auth.set_filter_clause(&mut query_builder).switch()?;

    query_builder.set_distinct();

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

#[derive(Debug, serde::Serialize, Eq, PartialEq, serde::Deserialize)]
pub struct PaymentFilterRow {
    pub currency: Option<DBEnumWrapper<Currency>>,
    pub status: Option<DBEnumWrapper<AttemptStatus>>,
    pub connector: Option<String>,
    pub authentication_type: Option<DBEnumWrapper<AuthenticationType>>,
    pub payment_method: Option<String>,
    pub payment_method_type: Option<String>,
    pub client_source: Option<String>,
    pub client_version: Option<String>,
    pub profile_id: Option<String>,
    pub card_network: Option<String>,
    pub merchant_id: Option<String>,
    pub card_last_4: Option<String>,
    pub card_issuer: Option<String>,
    pub error_reason: Option<String>,
    pub first_attempt: Option<bool>,
    pub routing_approach: Option<DBEnumWrapper<RoutingApproach>>,
    pub signature_network: Option<String>,
    pub is_issuer_regulated: Option<bool>,
    pub is_debit_routed: Option<bool>,
}


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

pub fn get_merchant_details_as_secret(
        &self,
    ) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError>


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

pub fn set_ip_address_if_required(
    request: &mut SetMetaDataRequest,
    headers: &HeaderMap,
) -> UserResult<()>


// Struct: AccessTokenAuthentication
// File: crates/hyperswitch_domain_models/src/router_flow_types/access_token_auth.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct AccessTokenAuthentication


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

pub struct NetceteraErrorDetails


// Implementation: impl api::RefundExecute for for Globepay
// File: crates/hyperswitch_connectors/src/connectors/globepay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Globepay


// Struct: AuthEventMetricsBucketIdentifier
// File: crates/api_models/src/analytics/auth_events.rs
// Module: api_models
// Implementations: 3
// Traits: Hash, PartialEq

pub struct AuthEventMetricsBucketIdentifier


// Struct: EmvThreedsData
// File: crates/hyperswitch_connectors/src/connectors/redsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct EmvThreedsData


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

pub fn list_all_key_stores(
        conn: &PgPooledConn,
        from: u32,
        limit: u32,
    ) -> StorageResult<Vec<Self>>


// Implementation: impl ReverseLookup
// File: crates/diesel_models/src/query/reverse_lookup.rs
// Module: diesel_models
// Methods: 1 total (0 public)

impl ReverseLookup


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

impl api::PaymentAuthorize for for Gigadat


// File: crates/router/src/core/routing/transformers.rs
// Module: router

use api_models::routing::{
    DynamicRoutingAlgorithm, MerchantRoutingAlgorithm, RoutingAlgorithmKind,
    RoutingAlgorithmWrapper, RoutingDictionaryRecord,
};
#[cfg(feature = "v1")]
use api_models::{
    open_router::{OpenRouterDecideGatewayRequest, PaymentInfo, RankingAlgorithm},
    routing::RoutableConnectorChoice,
};
use common_utils::ext_traits::ValueExt;
use diesel_models::{
    enums as storage_enums,
    routing_algorithm::{RoutingAlgorithm, RoutingProfileMetadata},
};
#[cfg(feature = "v1")]
use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt;
use masking::{PeekInterface, Secret};

use crate::{
    core::{errors, routing},
    types::transformers::{ForeignFrom, ForeignInto, ForeignTryFrom},
};

impl ForeignFrom<RoutingProfileMetadata> for RoutingDictionaryRecord {
    fn foreign_from(value: RoutingProfileMetadata) -> Self {
        Self {
            id: value.algorithm_id,

            profile_id: value.profile_id,
            name: value.name,
            kind: value.kind.foreign_into(),
            description: value.description.unwrap_or_default(),
            created_at: value.created_at.assume_utc().unix_timestamp(),
            modified_at: value.modified_at.assume_utc().unix_timestamp(),
            algorithm_for: Some(value.algorithm_for),
            decision_engine_routing_id: None,
        }
    }
}

impl ForeignFrom<RoutingAlgorithm> for RoutingDictionaryRecord {
    fn foreign_from(value: RoutingAlgorithm) -> Self {
        Self {
            id: value.algorithm_id,

            profile_id: value.profile_id,
            name: value.name,
            kind: value.kind.foreign_into(),
            description: value.description.unwrap_or_default(),
            created_at: value.created_at.assume_utc().unix_timestamp(),
            modified_at: value.modified_at.assume_utc().unix_timestamp(),
            algorithm_for: Some(value.algorithm_for),
            decision_engine_routing_id: value.decision_engine_routing_id,
        }
    }
}

impl ForeignTryFrom<RoutingAlgorithm> for MerchantRoutingAlgorithm {
    type Error = error_stack::Report<errors::ParsingError>;

    fn foreign_try_from(value: RoutingAlgorithm) -> Result<Self, Self::Error> {
        let algorithm: RoutingAlgorithmWrapper = match value.kind {
            diesel_models::enums::RoutingAlgorithmKind::Dynamic => value
                .algorithm_data
                .parse_value::<DynamicRoutingAlgorithm>("RoutingAlgorithmDynamic")
                .map(RoutingAlgorithmWrapper::Dynamic)?,
            _ => value
                .algorithm_data
                .parse_value::<api_models::routing::StaticRoutingAlgorithm>("RoutingAlgorithm")
                .map(RoutingAlgorithmWrapper::Static)?,
        };

        Ok(Self {
            id: value.algorithm_id,
            name: value.name,
            profile_id: value.profile_id,
            description: value.description.unwrap_or_default(),
            algorithm,
            created_at: value.created_at.assume_utc().unix_timestamp(),
            modified_at: value.modified_at.assume_utc().unix_timestamp(),
            algorithm_for: value.algorithm_for,
        })
    }
}

impl ForeignFrom<storage_enums::RoutingAlgorithmKind> for RoutingAlgorithmKind {
    fn foreign_from(value: storage_enums::RoutingAlgorithmKind) -> Self {
        match value {
            storage_enums::RoutingAlgorithmKind::Single => Self::Single,
            storage_enums::RoutingAlgorithmKind::Priority => Self::Priority,
            storage_enums::RoutingAlgorithmKind::VolumeSplit => Self::VolumeSplit,
            storage_enums::RoutingAlgorithmKind::Advanced => Self::Advanced,
            storage_enums::RoutingAlgorithmKind::Dynamic => Self::Dynamic,
            storage_enums::RoutingAlgorithmKind::ThreeDsDecisionRule => Self::ThreeDsDecisionRule,
        }
    }
}

impl ForeignFrom<RoutingAlgorithmKind> for storage_enums::RoutingAlgorithmKind {
    fn foreign_from(value: RoutingAlgorithmKind) -> Self {
        match value {
            RoutingAlgorithmKind::Single => Self::Single,
            RoutingAlgorithmKind::Priority => Self::Priority,
            RoutingAlgorithmKind::VolumeSplit => Self::VolumeSplit,
            RoutingAlgorithmKind::Advanced => Self::Advanced,
            RoutingAlgorithmKind::Dynamic => Self::Dynamic,
            RoutingAlgorithmKind::ThreeDsDecisionRule => Self::ThreeDsDecisionRule,
        }
    }
}

impl From<&routing::TransactionData<'_>> for storage_enums::TransactionType {
    fn from(value: &routing::TransactionData<'_>) -> Self {
        match value {
            routing::TransactionData::Payment(_) => Self::Payment,
            #[cfg(feature = "payouts")]
            routing::TransactionData::Payout(_) => Self::Payout,
        }
    }
}

#[cfg(feature = "v1")]
pub trait OpenRouterDecideGatewayRequestExt {
    fn construct_sr_request(
        attempt: &PaymentAttempt,
        eligible_gateway_list: Vec<RoutableConnectorChoice>,
        ranking_algorithm: Option<RankingAlgorithm>,
        is_elimination_enabled: bool,
    ) -> Self
    where
        Self: Sized;

    fn construct_debit_request(
        attempt: &PaymentAttempt,
        metadata: Option<String>,
        card_isin: Option<Secret<String>>,
        ranking_algorithm: Option<RankingAlgorithm>,
    ) -> Self
    where
        Self: Sized;
}

#[cfg(feature = "v1")]
impl OpenRouterDecideGatewayRequestExt for OpenRouterDecideGatewayRequest {
    fn construct_sr_request(
        attempt: &PaymentAttempt,
        eligible_gateway_list: Vec<RoutableConnectorChoice>,
        ranking_algorithm: Option<RankingAlgorithm>,
        is_elimination_enabled: bool,
    ) -> Self {
        Self {
            payment_info: PaymentInfo {
                payment_id: attempt.payment_id.clone(),
                amount: attempt.net_amount.get_order_amount(),
                currency: attempt.currency.unwrap_or(storage_enums::Currency::USD),
                payment_type: "ORDER_PAYMENT".to_string(),
                payment_method_type: "UPI".into(), // TODO: once open-router makes this field string, we can send from attempt
                payment_method: attempt.payment_method.unwrap_or_default(),
                metadata: None,
                card_isin: None,
            },
            merchant_id: attempt.profile_id.clone(),
            eligible_gateway_list: Some(
                eligible_gateway_list
                    .into_iter()
                    .map(|connector| connector.to_string())
                    .collect(),
            ),
            ranking_algorithm,
            elimination_enabled: Some(is_elimination_enabled),
        }
    }

    fn construct_debit_request(
        attempt: &PaymentAttempt,
        metadata: Option<String>,
        card_isin: Option<Secret<String>>,
        ranking_algorithm: Option<RankingAlgorithm>,
    ) -> Self {
        Self {
            payment_info: PaymentInfo {
                payment_id: attempt.payment_id.clone(),
                amount: attempt.net_amount.get_total_amount(),
                currency: attempt.currency.unwrap_or(storage_enums::Currency::USD),
                payment_type: "ORDER_PAYMENT".to_string(),
                card_isin: card_isin.map(|value| value.peek().clone()),
                metadata,
                payment_method_type: "UPI".into(), // TODO: once open-router makes this field string, we can send from attempt
                payment_method: attempt.payment_method.unwrap_or_default(),
            },
            merchant_id: attempt.profile_id.clone(),
            // eligible gateway list is not used in debit routing
            eligible_gateway_list: None,
            ranking_algorithm,
            elimination_enabled: None,
        }
    }
}


// Struct: NmiPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/nmi/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NmiPaymentsRequest


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

impl api::Refund for for Elavon


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

pub struct SmartRetriedAmount


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

// Public submodules:
pub mod transformers;


// Struct: GocardlessErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GocardlessErrorResponse


// Function: is_transaction_event
// File: crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs
// Module: hyperswitch_connectors

pub fn is_transaction_event(event: &Shift4WebhookEvent) -> bool


// Struct: ConnectorApiIntegrationPayload
// File: crates/connector_configs/src/common_config.rs
// Module: connector_configs
// Implementations: 0

pub struct ConnectorApiIntegrationPayload


// File: crates/openapi/src/routes/merchant_account.rs
// Module: openapi
// Public functions: 10

#[cfg(feature = "v1")]
/// Merchant Account - Create
///
/// Create a new account for a *merchant* and the *merchant* could be a seller or retailer or client who likes to receive and send payments.
#[utoipa::path(
    post,
    path = "/accounts",
    request_body(
        content = MerchantAccountCreate,
        examples(
            (
                "Create a merchant account with minimal fields" = (
                    value = json!({"merchant_id": "merchant_abc"})
                )
            ),
            (
                "Create a merchant account with webhook url" = (
                    value = json!({
                        "merchant_id": "merchant_abc",
                        "webhook_details" : {
                            "webhook_url": "https://webhook.site/a5c54f75-1f7e-4545-b781-af525b7e37a0"
                        }
                    })
                )
            ),
            (
                "Create a merchant account with return url" = (
                    value = json!({"merchant_id": "merchant_abc",
                "return_url": "https://example.com"})
                )
            )
        )

    ),
    responses(
        (status = 200, description = "Merchant Account Created", body = MerchantAccountResponse),
        (status = 400, description = "Invalid data")
    ),
    tag = "Merchant Account",
    operation_id = "Create a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn merchant_account_create() {}

#[cfg(feature = "v2")]
/// Merchant Account - Create
///
/// Create a new account for a *merchant* and the *merchant* could be a seller or retailer or client who likes to receive and send payments.
///
/// Before creating the merchant account, it is mandatory to create an organization.
#[utoipa::path(
    post,
    path = "/v2/merchant-accounts",
    params(
      (
        "X-Organization-Id" = String, Header,
        description = "Organization ID for which the merchant account has to be created.",
        example = json!({"X-Organization-Id": "org_abcdefghijklmnop"})
      ),
    ),
    request_body(
        content = MerchantAccountCreate,
        examples(
            (
                "Create a merchant account with minimal fields" = (
                    value = json!({
                        "merchant_name": "Cloth Store",
                    })
                )
            ),
            (
                "Create a merchant account with merchant details" = (
                    value = json!({
                        "merchant_name": "Cloth Store",
                        "merchant_details": {
                                "primary_contact_person": "John Doe",
                                "primary_email": "example@company.com"
                        }
                    })
                )
            ),
            (
                "Create a merchant account with metadata" = (
                    value = json!({
                        "merchant_name": "Cloth Store",
                        "metadata": {
                                "key_1": "John Doe",
                                "key_2": "Trends"
                        }
                    })
                )
            ),

        )

    ),
    responses(
        (status = 200, description = "Merchant Account Created", body = MerchantAccountResponse),
        (status = 400, description = "Invalid data")
    ),
    tag = "Merchant Account",
    operation_id = "Create a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn merchant_account_create() {}

#[cfg(feature = "v1")]
/// Merchant Account - Retrieve
///
/// Retrieve a *merchant* account details.
#[utoipa::path(
    get,
    path = "/accounts/{account_id}",
    params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "Merchant Account Retrieved", body = MerchantAccountResponse),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Retrieve a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn retrieve_merchant_account() {}

#[cfg(feature = "v2")]
/// Merchant Account - Retrieve
///
/// Retrieve a *merchant* account details.
#[utoipa::path(
    get,
    path = "/v2/merchant-accounts/{id}",
    params (("id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "Merchant Account Retrieved", body = MerchantAccountResponse),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Retrieve a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn merchant_account_retrieve() {}

#[cfg(feature = "v1")]
/// Merchant Account - Update
///
/// Updates details of an existing merchant account. Helpful in updating merchant details such as email, contact details, or other configuration details like webhook, routing algorithm etc
#[utoipa::path(
    post,
    path = "/accounts/{account_id}",
    request_body (
        content = MerchantAccountUpdate,
        examples(
            (
            "Update merchant name" = (
                value = json!({
                    "merchant_id": "merchant_abc",
                    "merchant_name": "merchant_name"
                })
            )
            ),
            ("Update webhook url" = (
                    value = json!({
                        "merchant_id": "merchant_abc",
                        "webhook_details": {
                            "webhook_url": "https://webhook.site/a5c54f75-1f7e-4545-b781-af525b7e37a0"
                        }
                    })
                )
            ),
            ("Update return url" = (
                value = json!({
                    "merchant_id": "merchant_abc",
                    "return_url": "https://example.com"
                })
            )))),
    params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "Merchant Account Updated", body = MerchantAccountResponse),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Update a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn update_merchant_account() {}

#[cfg(feature = "v2")]
/// Merchant Account - Update
///
/// Updates details of an existing merchant account. Helpful in updating merchant details such as email, contact details, or other configuration details like webhook, routing algorithm etc
#[utoipa::path(
    put,
    path = "/v2/merchant-accounts/{id}",
    request_body (
        content = MerchantAccountUpdate,
        examples(
            (
            "Update merchant name" = (
                value = json!({
                    "merchant_id": "merchant_abc",
                    "merchant_name": "merchant_name"
                })
            )
            ),
            ("Update Merchant Details" = (
                    value = json!({
                        "merchant_details": {
                                "primary_contact_person": "John Doe",
                                "primary_email": "example@company.com"
                        }
                    })
                )
            ),
            )),
    params (("id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "Merchant Account Updated", body = MerchantAccountResponse),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Update a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn merchant_account_update() {}

#[cfg(feature = "v1")]
/// Merchant Account - Delete
///
/// Delete a *merchant* account
#[utoipa::path(
    delete,
    path = "/accounts/{account_id}",
    params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "Merchant Account Deleted", body = MerchantAccountDeleteResponse),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Delete a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn delete_merchant_account() {}

#[cfg(feature = "v1")]
/// Merchant Account - KV Status
///
/// Toggle KV mode for the Merchant Account
#[utoipa::path(
    post,
    path = "/accounts/{account_id}/kv",
    request_body (
        content = ToggleKVRequest,
        examples (
            ("Enable KV for Merchant" = (
                value = json!({
                "kv_enabled": "true"
                })
        )),
        ("Disable KV for Merchant" = (
                value = json!({
                "kv_enabled": "false"
                })
        )))
    ),
    params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
    responses(
        (status = 200, description = "KV mode is enabled/disabled for Merchant Account", body = ToggleKVResponse),
        (status = 400, description = "Invalid data"),
        (status = 404, description = "Merchant account not found")
    ),
    tag = "Merchant Account",
    operation_id = "Enable/Disable KV for a Merchant Account",
    security(("admin_api_key" = []))
)]
pub async fn merchant_account_kv_status() {}

/// Merchant Connector - List
///
/// List Merchant Connector Details for the merchant
#[utoipa::path(
    get,
    path = "/accounts/{account_id}/profile/connectors",
    params(
        ("account_id" = String, Path, description = "The unique identifier for the merchant account"),
    ),
    responses(
        (status = 200, description = "Merchant Connector list retrieved successfully", body = Vec<MerchantConnectorResponse>),
        (status = 404, description = "Merchant Connector does not exist in records"),
        (status = 401, description = "Unauthorized request")
    ),
    tag = "Merchant Connector Account",
    operation_id = "List all Merchant Connectors for The given Profile",
    security(("admin_api_key" = []))
)]
pub async fn payment_connector_list_profile() {}

#[cfg(feature = "v2")]
/// Merchant Account - Profile List
///
/// List profiles for an Merchant
#[utoipa::path(
    get,
    path = "/v2/merchant-accounts/{id}/profiles",
    params (("id" = String, Path, description = "The unique identifier for the Merchant")),
    responses(
        (status = 200, description = "profile list retrieved successfully", body = Vec<ProfileResponse>),
        (status = 400, description = "Invalid data")
    ),
    tag = "Merchant Account",
    operation_id = "List Profiles",
    security(("admin_api_key" = []))
)]
pub async fn profiles_list() {}