// File: crates/storage_impl/src/mock_db.rs

use std::sync::Arc;

use common_utils::{errors::CustomResult, types::keymanager::KeyManagerState};
use diesel_models as store;
use error_stack::ResultExt;
use futures::lock::{Mutex, MutexGuard};
use hyperswitch_domain_models::{
    behaviour::{Conversion, ReverseConversion},
    merchant_key_store::MerchantKeyStore,
    payments::{payment_attempt::PaymentAttempt, PaymentIntent},
};
use redis_interface::RedisSettings;

use crate::{errors::StorageError, redis::RedisStore};

pub mod payment_attempt;
pub mod payment_intent;
#[cfg(feature = "payouts")]
pub mod payout_attempt;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod redis_conn;
#[cfg(not(feature = "payouts"))]
use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};

#[derive(Clone)]
pub struct MockDb {
    pub addresses: Arc<Mutex<Vec<store::Address>>>,
    pub configs: Arc<Mutex<Vec<store::Config>>>,
    pub merchant_accounts: Arc<Mutex<Vec<store::MerchantAccount>>>,
    pub merchant_connector_accounts: Arc<Mutex<Vec<store::MerchantConnectorAccount>>>,
    pub payment_attempts: Arc<Mutex<Vec<PaymentAttempt>>>,
    pub payment_intents: Arc<Mutex<Vec<PaymentIntent>>>,
    pub payment_methods: Arc<Mutex<Vec<store::PaymentMethod>>>,
    pub customers: Arc<Mutex<Vec<store::Customer>>>,
    pub refunds: Arc<Mutex<Vec<store::Refund>>>,
    pub processes: Arc<Mutex<Vec<store::ProcessTracker>>>,
    pub redis: Arc<RedisStore>,
    pub api_keys: Arc<Mutex<Vec<store::ApiKey>>>,
    pub ephemeral_keys: Arc<Mutex<Vec<store::EphemeralKey>>>,
    pub cards_info: Arc<Mutex<Vec<store::CardInfo>>>,
    pub events: Arc<Mutex<Vec<store::Event>>>,
    pub disputes: Arc<Mutex<Vec<store::Dispute>>>,
    pub lockers: Arc<Mutex<Vec<store::LockerMockUp>>>,
    pub mandates: Arc<Mutex<Vec<store::Mandate>>>,
    pub captures: Arc<Mutex<Vec<store::capture::Capture>>>,
    pub merchant_key_store: Arc<Mutex<Vec<store::merchant_key_store::MerchantKeyStore>>>,
    #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
    pub tokenizations: Arc<Mutex<Vec<store::tokenization::Tokenization>>>,
    pub business_profiles: Arc<Mutex<Vec<store::business_profile::Profile>>>,
    pub reverse_lookups: Arc<Mutex<Vec<store::ReverseLookup>>>,
    pub payment_link: Arc<Mutex<Vec<store::payment_link::PaymentLink>>>,
    pub organizations: Arc<Mutex<Vec<store::organization::Organization>>>,
    pub users: Arc<Mutex<Vec<store::user::User>>>,
    pub user_roles: Arc<Mutex<Vec<store::user_role::UserRole>>>,
    pub authorizations: Arc<Mutex<Vec<store::authorization::Authorization>>>,
    pub dashboard_metadata: Arc<Mutex<Vec<store::user::dashboard_metadata::DashboardMetadata>>>,
    #[cfg(feature = "payouts")]
    pub payout_attempt: Arc<Mutex<Vec<store::payout_attempt::PayoutAttempt>>>,
    #[cfg(feature = "payouts")]
    pub payouts: Arc<Mutex<Vec<store::payouts::Payouts>>>,
    pub authentications: Arc<Mutex<Vec<store::authentication::Authentication>>>,
    pub roles: Arc<Mutex<Vec<store::role::Role>>>,
    pub user_key_store: Arc<Mutex<Vec<store::user_key_store::UserKeyStore>>>,
    pub user_authentication_methods:
        Arc<Mutex<Vec<store::user_authentication_method::UserAuthenticationMethod>>>,
    pub themes: Arc<Mutex<Vec<store::user::theme::Theme>>>,
    pub hyperswitch_ai_interactions:
        Arc<Mutex<Vec<store::hyperswitch_ai_interaction::HyperswitchAiInteraction>>>,
    pub key_manager_state: Option<KeyManagerState>,
}

impl MockDb {
    pub fn get_keymanager_state(&self) -> Result<&KeyManagerState, StorageError> {
        self.key_manager_state
            .as_ref()
            .ok_or(StorageError::DecryptionError)
    }
    pub async fn new(
        redis: &RedisSettings,
        key_manager_state: KeyManagerState,
    ) -> error_stack::Result<Self, StorageError> {
        Ok(Self {
            addresses: Default::default(),
            configs: Default::default(),
            merchant_accounts: Default::default(),
            merchant_connector_accounts: Default::default(),
            payment_attempts: Default::default(),
            payment_intents: Default::default(),
            payment_methods: Default::default(),
            customers: Default::default(),
            refunds: Default::default(),
            processes: Default::default(),
            redis: Arc::new(
                RedisStore::new(redis)
                    .await
                    .change_context(StorageError::InitializationError)?,
            ),
            api_keys: Default::default(),
            ephemeral_keys: Default::default(),
            cards_info: Default::default(),
            events: Default::default(),
            disputes: Default::default(),
            lockers: Default::default(),
            mandates: Default::default(),
            captures: Default::default(),
            merchant_key_store: Default::default(),
            #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
            tokenizations: Default::default(),
            business_profiles: Default::default(),
            reverse_lookups: Default::default(),
            payment_link: Default::default(),
            organizations: Default::default(),
            users: Default::default(),
            user_roles: Default::default(),
            authorizations: Default::default(),
            dashboard_metadata: Default::default(),
            #[cfg(feature = "payouts")]
            payout_attempt: Default::default(),
            #[cfg(feature = "payouts")]
            payouts: Default::default(),
            authentications: Default::default(),
            roles: Default::default(),
            user_key_store: Default::default(),
            user_authentication_methods: Default::default(),
            themes: Default::default(),
            hyperswitch_ai_interactions: Default::default(),
            key_manager_state: Some(key_manager_state),
        })
    }

    /// Returns an option of the resource if it exists
    pub async fn find_resource<D, R>(
        &self,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
    ) -> CustomResult<Option<R>, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        let resource = resources.iter().find(filter_fn).cloned();
        match resource {
            Some(res) => Ok(Some(
                res.convert(
                    self.get_keymanager_state()
                        .attach_printable("Missing KeyManagerState")?,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)?,
            )),
            None => Ok(None),
        }
    }

    /// Throws errors when the requested resource is not found
    pub async fn get_resource<D, R>(
        &self,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
        error_message: String,
    ) -> CustomResult<R, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        match self.find_resource(key_store, resources, filter_fn).await? {
            Some(res) => Ok(res),
            None => Err(StorageError::ValueNotFound(error_message).into()),
        }
    }

    pub async fn get_resources<D, R>(
        &self,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
        error_message: String,
    ) -> CustomResult<Vec<R>, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        let resources: Vec<_> = resources.iter().filter(filter_fn).cloned().collect();
        if resources.is_empty() {
            Err(StorageError::ValueNotFound(error_message).into())
        } else {
            let pm_futures = resources
                .into_iter()
                .map(|pm| async {
                    pm.convert(
                        self.get_keymanager_state()
                            .attach_printable("Missing KeyManagerState")?,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)
                })
                .collect::<Vec<_>>();

            let domain_resources = futures::future::try_join_all(pm_futures).await?;

            Ok(domain_resources)
        }
    }

    pub async fn update_resource<D, R>(
        &self,
        key_store: &MerchantKeyStore,
        mut resources: MutexGuard<'_, Vec<D>>,
        resource_updated: D,
        filter_fn: impl Fn(&&mut D) -> bool,
        error_message: String,
    ) -> CustomResult<R, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        if let Some(pm) = resources.iter_mut().find(filter_fn) {
            *pm = resource_updated.clone();
            let result = resource_updated
                .convert(
                    self.get_keymanager_state()
                        .attach_printable("Missing KeyManagerState")?,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)?;
            Ok(result)
        } else {
            Err(StorageError::ValueNotFound(error_message).into())
        }
    }

    pub fn master_key(&self) -> &[u8] {
        &[
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
            25, 26, 27, 28, 29, 30, 31, 32,
        ]
    }
}

#[cfg(not(feature = "payouts"))]
impl PayoutsInterface for MockDb {}

#[cfg(not(feature = "payouts"))]
impl PayoutAttemptInterface for MockDb {}


// File: crates/storage_impl/src/callback_mapper.rs

use diesel_models::callback_mapper::CallbackMapper as DieselCallbackMapper;
use hyperswitch_domain_models::callback_mapper::CallbackMapper;

use crate::DataModelExt;

impl DataModelExt for CallbackMapper {
    type StorageModel = DieselCallbackMapper;

    fn to_storage_model(self) -> Self::StorageModel {
        DieselCallbackMapper {
            id: self.id,
            type_: self.callback_mapper_id_type,
            data: self.data,
            created_at: self.created_at,
            last_modified_at: self.last_modified_at,
        }
    }

    fn from_storage_model(storage_model: Self::StorageModel) -> Self {
        Self {
            id: storage_model.id,
            callback_mapper_id_type: storage_model.type_,
            data: storage_model.data,
            created_at: storage_model.created_at,
            last_modified_at: storage_model.last_modified_at,
        }
    }
}


// File: crates/storage_impl/src/lookup.rs

use common_utils::errors::CustomResult;
use diesel_models::{
    enums as storage_enums, kv,
    reverse_lookup::{
        ReverseLookup as DieselReverseLookup, ReverseLookupNew as DieselReverseLookupNew,
    },
};
use error_stack::ResultExt;
use redis_interface::SetnxReply;

use crate::{
    diesel_error_to_data_error,
    errors::{self, RedisErrorExt},
    kv_router_store::KVRouterStore,
    redis::kv_store::{decide_storage_scheme, kv_wrapper, KvOperation, Op, PartitionKey},
    utils::{self, try_redis_get_else_try_database_get},
    DatabaseStore, RouterStore,
};

#[async_trait::async_trait]
pub trait ReverseLookupInterface {
    async fn insert_reverse_lookup(
        &self,
        _new: DieselReverseLookupNew,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError>;
    async fn get_lookup_by_lookup_id(
        &self,
        _id: &str,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError>;
}

#[async_trait::async_trait]
impl<T: DatabaseStore> ReverseLookupInterface for RouterStore<T> {
    async fn insert_reverse_lookup(
        &self,
        new: DieselReverseLookupNew,
        _storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError> {
        let conn = self
            .get_master_pool()
            .get()
            .await
            .change_context(errors::StorageError::DatabaseConnectionError)?;
        new.insert(&conn).await.map_err(|er| {
            let new_err = diesel_error_to_data_error(*er.current_context());
            er.change_context(new_err)
        })
    }

    async fn get_lookup_by_lookup_id(
        &self,
        id: &str,
        _storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError> {
        let conn = utils::pg_connection_read(self).await?;
        DieselReverseLookup::find_by_lookup_id(id, &conn)
            .await
            .map_err(|er| {
                let new_err = diesel_error_to_data_error(*er.current_context());
                er.change_context(new_err)
            })
    }
}

#[async_trait::async_trait]
impl<T: DatabaseStore> ReverseLookupInterface for KVRouterStore<T> {
    async fn insert_reverse_lookup(
        &self,
        new: DieselReverseLookupNew,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError> {
        let storage_scheme = Box::pin(decide_storage_scheme::<_, DieselReverseLookup>(
            self,
            storage_scheme,
            Op::Insert,
        ))
        .await;
        match storage_scheme {
            storage_enums::MerchantStorageScheme::PostgresOnly => {
                self.router_store
                    .insert_reverse_lookup(new, storage_scheme)
                    .await
            }
            storage_enums::MerchantStorageScheme::RedisKv => {
                let created_rev_lookup = DieselReverseLookup {
                    lookup_id: new.lookup_id.clone(),
                    sk_id: new.sk_id.clone(),
                    pk_id: new.pk_id.clone(),
                    source: new.source.clone(),
                    updated_by: storage_scheme.to_string(),
                };
                let redis_entry = kv::TypedSql {
                    op: kv::DBOperation::Insert {
                        insertable: Box::new(kv::Insertable::ReverseLookUp(new)),
                    },
                };

                match Box::pin(kv_wrapper::<DieselReverseLookup, _, _>(
                    self,
                    KvOperation::SetNx(&created_rev_lookup, redis_entry),
                    PartitionKey::CombinationKey {
                        combination: &format!("reverse_lookup_{}", &created_rev_lookup.lookup_id),
                    },
                ))
                .await
                .map_err(|err| err.to_redis_failed_response(&created_rev_lookup.lookup_id))?
                .try_into_setnx()
                {
                    Ok(SetnxReply::KeySet) => Ok(created_rev_lookup),
                    Ok(SetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
                        entity: "reverse_lookup",
                        key: Some(created_rev_lookup.lookup_id.clone()),
                    }
                    .into()),
                    Err(er) => Err(er).change_context(errors::StorageError::KVError),
                }
            }
        }
    }

    async fn get_lookup_by_lookup_id(
        &self,
        id: &str,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<DieselReverseLookup, errors::StorageError> {
        let database_call = || async {
            self.router_store
                .get_lookup_by_lookup_id(id, storage_scheme)
                .await
        };
        let storage_scheme = Box::pin(decide_storage_scheme::<_, DieselReverseLookup>(
            self,
            storage_scheme,
            Op::Find,
        ))
        .await;
        match storage_scheme {
            storage_enums::MerchantStorageScheme::PostgresOnly => database_call().await,
            storage_enums::MerchantStorageScheme::RedisKv => {
                let redis_fut = async {
                    Box::pin(kv_wrapper(
                        self,
                        KvOperation::<DieselReverseLookup>::Get,
                        PartitionKey::CombinationKey {
                            combination: &format!("reverse_lookup_{id}"),
                        },
                    ))
                    .await?
                    .try_into_get()
                };

                Box::pin(try_redis_get_else_try_database_get(
                    redis_fut,
                    database_call,
                ))
                .await
            }
        }
    }
}


// File: crates/storage_impl/src/merchant_account.rs

#[cfg(feature = "olap")]
use std::collections::HashMap;

use common_utils::ext_traits::AsyncExt;
use diesel_models::merchant_account as storage;
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    behaviour::{Conversion, ReverseConversion},
    master_key::MasterKeyInterface,
    merchant_account::{self as domain, MerchantAccountInterface},
    merchant_key_store::{MerchantKeyStore, MerchantKeyStoreInterface},
};
use masking::PeekInterface;
use router_env::{instrument, tracing};

#[cfg(feature = "accounts_cache")]
use crate::redis::{
    cache,
    cache::{CacheKind, ACCOUNTS_CACHE},
};
#[cfg(feature = "accounts_cache")]
use crate::RedisConnInterface;
use crate::{
    kv_router_store,
    store::MerchantAccountUpdateInternal,
    utils::{pg_accounts_connection_read, pg_accounts_connection_write},
    CustomResult, DatabaseStore, MockDb, RouterStore, StorageError,
};

#[async_trait::async_trait]
impl<T: DatabaseStore> MerchantAccountInterface for kv_router_store::KVRouterStore<T> {
    type Error = StorageError;
    #[instrument(skip_all)]
    async fn insert_merchant(
        &self,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        self.router_store
            .insert_merchant(merchant_account, merchant_key_store)
            .await
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        self.router_store
            .find_merchant_account_by_merchant_id(merchant_id, merchant_key_store)
            .await
    }

    #[instrument(skip_all)]
    async fn update_merchant(
        &self,
        this: domain::MerchantAccount,
        merchant_account: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        self.router_store
            .update_merchant(this, merchant_account, merchant_key_store)
            .await
    }

    #[instrument(skip_all)]
    async fn update_specific_fields_in_merchant(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        self.router_store
            .update_specific_fields_in_merchant(merchant_id, merchant_account, merchant_key_store)
            .await
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_publishable_key(
        &self,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, MerchantKeyStore), StorageError> {
        self.router_store
            .find_merchant_account_by_publishable_key(publishable_key)
            .await
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        self.router_store
            .list_merchant_accounts_by_organization_id(organization_id)
            .await
    }

    #[instrument(skip_all)]
    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, StorageError> {
        self.router_store
            .delete_merchant_account_by_merchant_id(merchant_id)
            .await
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_multiple_merchant_accounts(
        &self,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        self.router_store
            .list_multiple_merchant_accounts(merchant_ids)
            .await
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_and_org_ids(
        &self,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        StorageError,
    > {
        self.router_store
            .list_merchant_and_org_ids(limit, offset)
            .await
    }

    async fn update_all_merchant_account(
        &self,
        merchant_account: domain::MerchantAccountUpdate,
    ) -> CustomResult<usize, StorageError> {
        self.router_store
            .update_all_merchant_account(merchant_account)
            .await
    }
}

#[async_trait::async_trait]
impl<T: DatabaseStore> MerchantAccountInterface for RouterStore<T> {
    type Error = StorageError;
    #[instrument(skip_all)]
    async fn insert_merchant(
        &self,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let conn = pg_accounts_connection_write(self).await?;
        merchant_account
            .construct_new()
            .await
            .change_context(StorageError::EncryptionError)?
            .insert(&conn)
            .await
            .map_err(|error| report!(StorageError::from(error)))?
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let fetch_func = || async {
            let conn = pg_accounts_connection_read(self).await?;
            storage::MerchantAccount::find_by_merchant_id(&conn, merchant_id)
                .await
                .map_err(|error| report!(StorageError::from(error)))
        };
        let state = self
            .get_keymanager_state()
            .attach_printable("Missing KeyManagerState")?;

        #[cfg(not(feature = "accounts_cache"))]
        {
            fetch_func()
                .await?
                .convert(
                    state,
                    merchant_key_store.key.get_inner(),
                    merchant_id.to_owned().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)
        }

        #[cfg(feature = "accounts_cache")]
        {
            cache::get_or_populate_in_memory(
                self,
                merchant_id.get_string_repr(),
                fetch_func,
                &ACCOUNTS_CACHE,
            )
            .await?
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
        }
    }

    #[instrument(skip_all)]
    async fn update_merchant(
        &self,
        this: domain::MerchantAccount,
        merchant_account: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let conn = pg_accounts_connection_write(self).await?;

        let updated_merchant_account = Conversion::convert(this)
            .await
            .change_context(StorageError::EncryptionError)?
            .update(&conn, merchant_account.into())
            .await
            .map_err(|error| report!(StorageError::from(error)))?;

        #[cfg(feature = "accounts_cache")]
        {
            publish_and_redact_merchant_account_cache(self, &updated_merchant_account).await?;
        }
        updated_merchant_account
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn update_specific_fields_in_merchant(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let conn = pg_accounts_connection_write(self).await?;
        let updated_merchant_account = storage::MerchantAccount::update_with_specific_fields(
            &conn,
            merchant_id,
            merchant_account.into(),
        )
        .await
        .map_err(|error| report!(StorageError::from(error)))?;

        #[cfg(feature = "accounts_cache")]
        {
            publish_and_redact_merchant_account_cache(self, &updated_merchant_account).await?;
        }
        updated_merchant_account
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_publishable_key(
        &self,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, MerchantKeyStore), StorageError> {
        let fetch_by_pub_key_func = || async {
            let conn = pg_accounts_connection_read(self).await?;

            storage::MerchantAccount::find_by_publishable_key(&conn, publishable_key)
                .await
                .map_err(|error| report!(StorageError::from(error)))
        };

        let merchant_account;
        #[cfg(not(feature = "accounts_cache"))]
        {
            merchant_account = fetch_by_pub_key_func().await?;
        }

        #[cfg(feature = "accounts_cache")]
        {
            merchant_account = cache::get_or_populate_in_memory(
                self,
                publishable_key,
                fetch_by_pub_key_func,
                &ACCOUNTS_CACHE,
            )
            .await?;
        }
        let key_store = self
            .get_merchant_key_store_by_merchant_id(
                merchant_account.get_id(),
                &self.master_key().peek().to_vec().into(),
            )
            .await?;
        let domain_merchant_account = merchant_account
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)?;
        Ok((domain_merchant_account, key_store))
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        use futures::future::try_join_all;
        let conn = pg_accounts_connection_read(self).await?;

        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_by_organization_id(&conn, organization_id)
                .await
                .map_err(|error| report!(StorageError::from(error)))?;

        let db_master_key = self.master_key().peek().to_vec().into();
        let merchant_key_stores =
            try_join_all(encrypted_merchant_accounts.iter().map(|merchant_account| {
                self.get_merchant_key_store_by_merchant_id(
                    merchant_account.get_id(),
                    &db_master_key,
                )
            }))
            .await?;

        let merchant_accounts = try_join_all(
            encrypted_merchant_accounts
                .into_iter()
                .zip(merchant_key_stores.iter())
                .map(|(merchant_account, key_store)| async {
                    merchant_account
                        .convert(
                            self.get_keymanager_state()
                                .attach_printable("Missing KeyManagerState")?,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(StorageError::DecryptionError)
                }),
        )
        .await?;

        Ok(merchant_accounts)
    }

    #[instrument(skip_all)]
    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, StorageError> {
        let conn = pg_accounts_connection_write(self).await?;

        let is_deleted_func = || async {
            storage::MerchantAccount::delete_by_merchant_id(&conn, merchant_id)
                .await
                .map_err(|error| report!(StorageError::from(error)))
        };

        let is_deleted;

        #[cfg(not(feature = "accounts_cache"))]
        {
            is_deleted = is_deleted_func().await?;
        }

        #[cfg(feature = "accounts_cache")]
        {
            let merchant_account =
                storage::MerchantAccount::find_by_merchant_id(&conn, merchant_id)
                    .await
                    .map_err(|error| report!(StorageError::from(error)))?;

            is_deleted = is_deleted_func().await?;

            publish_and_redact_merchant_account_cache(self, &merchant_account).await?;
        }

        Ok(is_deleted)
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_multiple_merchant_accounts(
        &self,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        let conn = pg_accounts_connection_read(self).await?;

        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_multiple_merchant_accounts(&conn, merchant_ids)
                .await
                .map_err(|error| report!(StorageError::from(error)))?;

        let db_master_key = self.master_key().peek().to_vec().into();

        let merchant_key_stores = self
            .list_multiple_key_stores(
                encrypted_merchant_accounts
                    .iter()
                    .map(|merchant_account| merchant_account.get_id())
                    .cloned()
                    .collect(),
                &db_master_key,
            )
            .await?;

        let key_stores_by_id: HashMap<_, _> = merchant_key_stores
            .iter()
            .map(|key_store| (key_store.merchant_id.to_owned(), key_store))
            .collect();

        let merchant_accounts =
            futures::future::try_join_all(encrypted_merchant_accounts.into_iter().map(
                |merchant_account| async {
                    let key_store = key_stores_by_id.get(merchant_account.get_id()).ok_or(
                        StorageError::ValueNotFound(format!(
                            "merchant_key_store with merchant_id = {:?}",
                            merchant_account.get_id()
                        )),
                    )?;
                    merchant_account
                        .convert(
                            self.get_keymanager_state()
                                .attach_printable("Missing KeyManagerState")?,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(StorageError::DecryptionError)
                },
            ))
            .await?;

        Ok(merchant_accounts)
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_and_org_ids(
        &self,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        StorageError,
    > {
        let conn = pg_accounts_connection_read(self).await?;
        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_all_merchant_accounts(&conn, limit, offset)
                .await
                .map_err(|error| report!(StorageError::from(error)))?;

        let merchant_and_org_ids = encrypted_merchant_accounts
            .into_iter()
            .map(|merchant_account| {
                let merchant_id = merchant_account.get_id().clone();
                let org_id = merchant_account.organization_id;
                (merchant_id, org_id)
            })
            .collect();
        Ok(merchant_and_org_ids)
    }

    async fn update_all_merchant_account(
        &self,
        merchant_account: domain::MerchantAccountUpdate,
    ) -> CustomResult<usize, StorageError> {
        let conn = pg_accounts_connection_read(self).await?;

        let db_func = || async {
            storage::MerchantAccount::update_all_merchant_accounts(
                &conn,
                MerchantAccountUpdateInternal::from(merchant_account),
            )
            .await
            .map_err(|error| report!(StorageError::from(error)))
        };

        let total;
        #[cfg(not(feature = "accounts_cache"))]
        {
            let ma = db_func().await?;
            total = ma.len();
        }

        #[cfg(feature = "accounts_cache")]
        {
            let ma = db_func().await?;
            publish_and_redact_all_merchant_account_cache(self, &ma).await?;
            total = ma.len();
        }

        Ok(total)
    }
}

#[async_trait::async_trait]
impl MerchantAccountInterface for MockDb {
    type Error = StorageError;
    #[allow(clippy::panic)]
    async fn insert_merchant(
        &self,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        let account = Conversion::convert(merchant_account)
            .await
            .change_context(StorageError::EncryptionError)?;
        accounts.push(account.clone());

        account
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    #[allow(clippy::panic)]
    async fn find_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        accounts
            .iter()
            .find(|account| account.get_id() == merchant_id)
            .cloned()
            .ok_or(StorageError::ValueNotFound(format!(
                "Merchant ID: {merchant_id:?} not found",
            )))?
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    async fn update_merchant(
        &self,
        merchant_account: domain::MerchantAccount,
        merchant_account_update: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let merchant_id = merchant_account.get_id().to_owned();
        let mut accounts = self.merchant_accounts.lock().await;
        accounts
            .iter_mut()
            .find(|account| account.get_id() == merchant_account.get_id())
            .async_map(|account| async {
                let update = MerchantAccountUpdateInternal::from(merchant_account_update)
                    .apply_changeset(
                        Conversion::convert(merchant_account)
                            .await
                            .change_context(StorageError::EncryptionError)?,
                    );
                *account = update.clone();
                update
                    .convert(
                        self.get_keymanager_state()
                            .attach_printable("Missing KeyManagerState")?,
                        merchant_key_store.key.get_inner(),
                        merchant_key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)
            })
            .await
            .transpose()?
            .ok_or(
                StorageError::ValueNotFound(format!("Merchant ID: {merchant_id:?} not found",))
                    .into(),
            )
    }

    async fn update_specific_fields_in_merchant(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account_update: domain::MerchantAccountUpdate,
        merchant_key_store: &MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        accounts
            .iter_mut()
            .find(|account| account.get_id() == merchant_id)
            .async_map(|account| async {
                let update = MerchantAccountUpdateInternal::from(merchant_account_update)
                    .apply_changeset(account.clone());
                *account = update.clone();
                update
                    .convert(
                        self.get_keymanager_state()
                            .attach_printable("Missing KeyManagerState")?,
                        merchant_key_store.key.get_inner(),
                        merchant_key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)
            })
            .await
            .transpose()?
            .ok_or(
                StorageError::ValueNotFound(format!("Merchant ID: {merchant_id:?} not found",))
                    .into(),
            )
    }

    async fn find_merchant_account_by_publishable_key(
        &self,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, MerchantKeyStore), StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        let account = accounts
            .iter()
            .find(|account| {
                account
                    .publishable_key
                    .as_ref()
                    .is_some_and(|key| key == publishable_key)
            })
            .ok_or(StorageError::ValueNotFound(format!(
                "Publishable Key: {publishable_key} not found",
            )))?;
        let key_store = self
            .get_merchant_key_store_by_merchant_id(
                account.get_id(),
                &self.get_master_key().to_vec().into(),
            )
            .await?;
        let merchant_account = account
            .clone()
            .convert(
                self.get_keymanager_state()
                    .attach_printable("Missing KeyManagerState")?,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)?;
        Ok((merchant_account, key_store))
    }

    async fn update_all_merchant_account(
        &self,
        merchant_account_update: domain::MerchantAccountUpdate,
    ) -> CustomResult<usize, StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        Ok(accounts.iter_mut().fold(0, |acc, account| {
            let update = MerchantAccountUpdateInternal::from(merchant_account_update.clone())
                .apply_changeset(account.clone());
            *account = update;
            acc + 1
        }))
    }

    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        accounts.retain(|x| x.get_id() != merchant_id);
        Ok(true)
    }

    #[cfg(feature = "olap")]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        let futures = accounts
            .iter()
            .filter(|account| account.organization_id == *organization_id)
            .map(|account| async {
                let key_store = self
                    .get_merchant_key_store_by_merchant_id(
                        account.get_id(),
                        &self.get_master_key().to_vec().into(),
                    )
                    .await;
                match key_store {
                    Ok(key) => account
                        .clone()
                        .convert(
                            self.get_keymanager_state()
                                .attach_printable("Missing KeyManagerState")?,
                            key.key.get_inner(),
                            key.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(StorageError::DecryptionError),
                    Err(err) => Err(err),
                }
            });
        futures::future::join_all(futures)
            .await
            .into_iter()
            .collect()
    }

    #[cfg(feature = "olap")]
    async fn list_multiple_merchant_accounts(
        &self,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        let futures = accounts
            .iter()
            .filter(|account| merchant_ids.contains(account.get_id()))
            .map(|account| async {
                let key_store = self
                    .get_merchant_key_store_by_merchant_id(
                        account.get_id(),
                        &self.get_master_key().to_vec().into(),
                    )
                    .await;
                match key_store {
                    Ok(key) => account
                        .clone()
                        .convert(
                            self.get_keymanager_state()
                                .attach_printable("Missing KeyManagerState")?,
                            key.key.get_inner(),
                            key.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(StorageError::DecryptionError),
                    Err(err) => Err(err),
                }
            });
        futures::future::join_all(futures)
            .await
            .into_iter()
            .collect()
    }

    #[cfg(feature = "olap")]
    async fn list_merchant_and_org_ids(
        &self,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        StorageError,
    > {
        let accounts = self.merchant_accounts.lock().await;
        let limit = limit.try_into().unwrap_or(accounts.len());
        let offset = offset.unwrap_or(0).try_into().unwrap_or(0);

        let merchant_and_org_ids = accounts
            .iter()
            .skip(offset)
            .take(limit)
            .map(|account| (account.get_id().clone(), account.organization_id.clone()))
            .collect::<Vec<_>>();

        Ok(merchant_and_org_ids)
    }
}

#[cfg(feature = "accounts_cache")]
async fn publish_and_redact_merchant_account_cache(
    store: &(dyn RedisConnInterface + Send + Sync),
    merchant_account: &storage::MerchantAccount,
) -> CustomResult<(), StorageError> {
    let publishable_key = merchant_account
        .publishable_key
        .as_ref()
        .map(|publishable_key| CacheKind::Accounts(publishable_key.into()));

    #[cfg(feature = "v1")]
    let cgraph_key = merchant_account.default_profile.as_ref().map(|profile_id| {
        CacheKind::CGraph(
            format!(
                "cgraph_{}_{}",
                merchant_account.get_id().get_string_repr(),
                profile_id.get_string_repr(),
            )
            .into(),
        )
    });

    // TODO: we will not have default profile in v2
    #[cfg(feature = "v2")]
    let cgraph_key = None;

    let mut cache_keys = vec![CacheKind::Accounts(
        merchant_account.get_id().get_string_repr().into(),
    )];

    cache_keys.extend(publishable_key.into_iter());
    cache_keys.extend(cgraph_key.into_iter());

    cache::redact_from_redis_and_publish(store, cache_keys).await?;
    Ok(())
}

#[cfg(feature = "accounts_cache")]
async fn publish_and_redact_all_merchant_account_cache(
    cache: &(dyn RedisConnInterface + Send + Sync),
    merchant_accounts: &[storage::MerchantAccount],
) -> CustomResult<(), StorageError> {
    let merchant_ids = merchant_accounts
        .iter()
        .map(|merchant_account| merchant_account.get_id().get_string_repr().to_string());
    let publishable_keys = merchant_accounts
        .iter()
        .filter_map(|m| m.publishable_key.clone());

    let cache_keys: Vec<CacheKind<'_>> = merchant_ids
        .chain(publishable_keys)
        .map(|s| CacheKind::Accounts(s.into()))
        .collect();

    cache::redact_from_redis_and_publish(cache, cache_keys).await?;
    Ok(())
}


// File: crates/storage_impl/src/payouts.rs

pub mod payout_attempt;
#[allow(clippy::module_inception)]
pub mod payouts;

use diesel_models::{payout_attempt::PayoutAttempt, payouts::Payouts};

use crate::redis::kv_store::KvStorePartition;

impl KvStorePartition for Payouts {}
impl KvStorePartition for PayoutAttempt {}


// File: crates/storage_impl/src/database.rs

pub mod store;


// File: crates/storage_impl/src/cards_info.rs

pub use diesel_models::{CardInfo, UpdateCardInfo};
use error_stack::report;
use hyperswitch_domain_models::cards_info::CardsInfoInterface;
use router_env::{instrument, tracing};

use crate::{
    errors::StorageError,
    kv_router_store::KVRouterStore,
    redis::kv_store::KvStorePartition,
    utils::{pg_connection_read, pg_connection_write},
    CustomResult, DatabaseStore, MockDb, RouterStore,
};

impl KvStorePartition for CardInfo {}

#[async_trait::async_trait]
impl<T: DatabaseStore> CardsInfoInterface for RouterStore<T> {
    type Error = StorageError;
    #[instrument(skip_all)]
    async fn get_card_info(&self, card_iin: &str) -> CustomResult<Option<CardInfo>, StorageError> {
        let conn = pg_connection_read(self).await?;
        CardInfo::find_by_iin(&conn, card_iin)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
    #[instrument(skip_all)]
    async fn add_card_info(&self, data: CardInfo) -> CustomResult<CardInfo, StorageError> {
        let conn = pg_connection_write(self).await?;
        data.insert(&conn)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
    #[instrument(skip_all)]
    async fn update_card_info(
        &self,
        card_iin: String,
        data: UpdateCardInfo,
    ) -> CustomResult<CardInfo, StorageError> {
        let conn = pg_connection_write(self).await?;
        CardInfo::update(&conn, card_iin, data)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
}

#[async_trait::async_trait]
impl<T: DatabaseStore> CardsInfoInterface for KVRouterStore<T> {
    type Error = StorageError;
    #[instrument(skip_all)]
    async fn get_card_info(&self, card_iin: &str) -> CustomResult<Option<CardInfo>, StorageError> {
        let conn = pg_connection_read(self).await?;
        CardInfo::find_by_iin(&conn, card_iin)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
    #[instrument(skip_all)]
    async fn add_card_info(&self, data: CardInfo) -> CustomResult<CardInfo, StorageError> {
        let conn = pg_connection_write(self).await?;
        data.insert(&conn)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
    #[instrument(skip_all)]
    async fn update_card_info(
        &self,
        card_iin: String,
        data: UpdateCardInfo,
    ) -> CustomResult<CardInfo, StorageError> {
        let conn = pg_connection_write(self).await?;
        CardInfo::update(&conn, card_iin, data)
            .await
            .map_err(|error| report!(StorageError::from(error)))
    }
}

#[async_trait::async_trait]
impl CardsInfoInterface for MockDb {
    type Error = StorageError;
    #[instrument(skip_all)]
    async fn get_card_info(&self, card_iin: &str) -> CustomResult<Option<CardInfo>, StorageError> {
        Ok(self
            .cards_info
            .lock()
            .await
            .iter()
            .find(|ci| ci.card_iin == card_iin)
            .cloned())
    }

    async fn add_card_info(&self, _data: CardInfo) -> CustomResult<CardInfo, StorageError> {
        Err(StorageError::MockDbError)?
    }

    async fn update_card_info(
        &self,
        _card_iin: String,
        _data: UpdateCardInfo,
    ) -> CustomResult<CardInfo, StorageError> {
        Err(StorageError::MockDbError)?
    }
}


// File: crates/storage_impl/src/payment_method.rs

pub use diesel_models::payment_method::PaymentMethod;

use crate::redis::kv_store::KvStorePartition;

impl KvStorePartition for PaymentMethod {}

use common_enums::enums::MerchantStorageScheme;
use common_utils::{errors::CustomResult, id_type};
#[cfg(feature = "v1")]
use diesel_models::kv;
use diesel_models::payment_method::{PaymentMethodUpdate, PaymentMethodUpdateInternal};
use error_stack::ResultExt;
#[cfg(feature = "v1")]
use hyperswitch_domain_models::behaviour::ReverseConversion;
use hyperswitch_domain_models::{
    behaviour::Conversion,
    merchant_key_store::MerchantKeyStore,
    payment_methods::{PaymentMethod as DomainPaymentMethod, PaymentMethodInterface},
};
use router_env::{instrument, tracing};

use super::MockDb;
use crate::{
    diesel_error_to_data_error, errors,
    kv_router_store::{FindResourceBy, KVRouterStore},
    utils::{pg_connection_read, pg_connection_write},
    DatabaseStore, RouterStore,
};
#[cfg(feature = "v1")]
use crate::{
    kv_router_store::{FilterResourceParams, InsertResourceParams, UpdateResourceParams},
    redis::kv_store::{Op, PartitionKey},
};

#[async_trait::async_trait]
impl<T: DatabaseStore> PaymentMethodInterface for KVRouterStore<T> {
    type Error = errors::StorageError;
    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resource_by_id(
            key_store,
            storage_scheme,
            PaymentMethod::find_by_payment_method_id(&conn, payment_method_id),
            FindResourceBy::LookupId(format!("payment_method_{payment_method_id}")),
        )
        .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &id_type::GlobalPaymentMethodId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resource_by_id(
            key_store,
            storage_scheme,
            PaymentMethod::find_by_id(&conn, payment_method_id),
            FindResourceBy::LookupId(format!(
                "payment_method_{}",
                payment_method_id.get_string_repr()
            )),
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_locker_id(
        &self,
        key_store: &MerchantKeyStore,
        locker_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resource_by_id(
            key_store,
            storage_scheme,
            PaymentMethod::find_by_locker_id(&conn, locker_id),
            FindResourceBy::LookupId(format!("payment_method_locker_{locker_id}")),
        )
        .await
    }

    // not supported in kv
    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn get_payment_method_count_by_customer_id_merchant_id_status(
        &self,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        self.router_store
            .get_payment_method_count_by_customer_id_merchant_id_status(
                customer_id,
                merchant_id,
                status,
            )
            .await
    }

    #[instrument(skip_all)]
    async fn get_payment_method_count_by_merchant_id_status(
        &self,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        self.router_store
            .get_payment_method_count_by_merchant_id_status(merchant_id, status)
            .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn insert_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        self.router_store
            .insert_payment_method(key_store, payment_method, storage_scheme)
            .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn insert_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_write(self).await?;
        let mut payment_method_new = payment_method
            .construct_new()
            .await
            .change_context(errors::StorageError::DecryptionError)?;
        payment_method_new.update_storage_scheme(storage_scheme);

        let key = PartitionKey::MerchantIdCustomerId {
            merchant_id: &payment_method_new.merchant_id.clone(),
            customer_id: &payment_method_new.customer_id.clone(),
        };
        let identifier = format!("payment_method_id_{}", payment_method_new.get_id());
        let lookup_id1 = format!("payment_method_{}", payment_method_new.get_id());
        let mut reverse_lookups = vec![lookup_id1];
        if let Some(locker_id) = &payment_method_new.locker_id {
            reverse_lookups.push(format!("payment_method_locker_{locker_id}"))
        }
        let payment_method = (&payment_method_new.clone()).into();
        self.insert_resource(
            key_store,
            storage_scheme,
            payment_method_new.clone().insert(&conn),
            payment_method,
            InsertResourceParams {
                insertable: kv::Insertable::PaymentMethod(Box::new(payment_method_new.clone())),
                reverse_lookups,
                key,
                identifier,
                resource_type: "payment_method",
            },
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn update_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        payment_method_update: PaymentMethodUpdate,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method = Conversion::convert(payment_method)
            .await
            .change_context(errors::StorageError::DecryptionError)?;

        let merchant_id = payment_method.merchant_id.clone();
        let customer_id = payment_method.customer_id.clone();
        let key = PartitionKey::MerchantIdCustomerId {
            merchant_id: &merchant_id,
            customer_id: &customer_id,
        };
        let conn = pg_connection_write(self).await?;
        let field = format!("payment_method_id_{}", payment_method.get_id().clone());
        let p_update: PaymentMethodUpdateInternal =
            payment_method_update.convert_to_payment_method_update(storage_scheme);
        let updated_payment_method = p_update.clone().apply_changeset(payment_method.clone());
        self.update_resource(
            key_store,
            storage_scheme,
            payment_method
                .clone()
                .update_with_payment_method_id(&conn, p_update.clone()),
            updated_payment_method,
            UpdateResourceParams {
                updateable: kv::Updateable::PaymentMethodUpdate(Box::new(
                    kv::PaymentMethodUpdateMems {
                        orig: payment_method.clone(),
                        update_data: p_update.clone(),
                    },
                )),
                operation: Op::Update(
                    key.clone(),
                    &field,
                    payment_method.clone().updated_by.as_deref(),
                ),
            },
        )
        .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn update_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        payment_method_update: PaymentMethodUpdate,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        self.router_store
            .update_payment_method(
                key_store,
                payment_method,
                payment_method_update,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_customer_id_merchant_id_list(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        self.router_store
            .find_payment_method_by_customer_id_merchant_id_list(
                key_store,
                customer_id,
                merchant_id,
                limit,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_list_by_global_customer_id(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::GlobalCustomerId,
        limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        self.router_store
            .find_payment_method_list_by_global_customer_id(key_store, customer_id, limit)
            .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.filter_resources(
            key_store,
            storage_scheme,
            PaymentMethod::find_by_customer_id_merchant_id_status(
                &conn,
                customer_id,
                merchant_id,
                status,
                limit,
            ),
            |pm| pm.status == status,
            FilterResourceParams {
                key: PartitionKey::MerchantIdCustomerId {
                    merchant_id,
                    customer_id,
                },
                pattern: "payment_method_id_*",
                limit,
            },
        )
        .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_global_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::GlobalCustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        self.router_store
            .find_payment_method_by_global_customer_id_merchant_id_status(
                key_store,
                customer_id,
                merchant_id,
                status,
                limit,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v1")]
    async fn delete_payment_method_by_merchant_id_payment_method_id(
        &self,
        key_store: &MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        payment_method_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        self.router_store
            .delete_payment_method_by_merchant_id_payment_method_id(
                key_store,
                merchant_id,
                payment_method_id,
            )
            .await
    }

    // Soft delete, Check if KV stuff is needed here
    #[cfg(feature = "v2")]
    async fn delete_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        self.router_store
            .delete_payment_method(key_store, payment_method)
            .await
    }

    // Check if KV stuff is needed here
    #[cfg(feature = "v2")]
    async fn find_payment_method_by_fingerprint_id(
        &self,
        key_store: &MerchantKeyStore,
        fingerprint_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        self.router_store
            .find_payment_method_by_fingerprint_id(key_store, fingerprint_id)
            .await
    }
}

#[async_trait::async_trait]
impl<T: DatabaseStore> PaymentMethodInterface for RouterStore<T> {
    type Error = errors::StorageError;
    #[instrument(skip_all)]
    #[cfg(feature = "v1")]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.call_database(
            key_store,
            PaymentMethod::find_by_payment_method_id(&conn, payment_method_id),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &id_type::GlobalPaymentMethodId,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.call_database(
            key_store,
            PaymentMethod::find_by_id(&conn, payment_method_id),
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_locker_id(
        &self,
        key_store: &MerchantKeyStore,
        locker_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.call_database(
            key_store,
            PaymentMethod::find_by_locker_id(&conn, locker_id),
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn get_payment_method_count_by_customer_id_merchant_id_status(
        &self,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        PaymentMethod::get_count_by_customer_id_merchant_id_status(
            &conn,
            customer_id,
            merchant_id,
            status,
        )
        .await
        .map_err(|error| {
            let new_err = diesel_error_to_data_error(*error.current_context());
            error.change_context(new_err)
        })
    }

    #[instrument(skip_all)]
    async fn get_payment_method_count_by_merchant_id_status(
        &self,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        PaymentMethod::get_count_by_merchant_id_status(&conn, merchant_id, status)
            .await
            .map_err(|error| {
                let new_err = diesel_error_to_data_error(*error.current_context());
                error.change_context(new_err)
            })
    }

    #[instrument(skip_all)]
    async fn insert_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method_new = payment_method
            .construct_new()
            .await
            .change_context(errors::StorageError::DecryptionError)?;

        let conn = pg_connection_write(self).await?;
        self.call_database(key_store, payment_method_new.insert(&conn))
            .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn update_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        payment_method_update: PaymentMethodUpdate,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method = Conversion::convert(payment_method)
            .await
            .change_context(errors::StorageError::DecryptionError)?;

        let conn = pg_connection_write(self).await?;
        self.call_database(
            key_store,
            payment_method.update_with_payment_method_id(&conn, payment_method_update.into()),
        )
        .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn update_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        payment_method_update: PaymentMethodUpdate,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method = Conversion::convert(payment_method)
            .await
            .change_context(errors::StorageError::DecryptionError)?;
        let conn = pg_connection_write(self).await?;
        self.call_database(
            key_store,
            payment_method.update_with_id(&conn, payment_method_update.into()),
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_customer_id_merchant_id_list(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resources(
            key_store,
            PaymentMethod::find_by_customer_id_merchant_id(&conn, customer_id, merchant_id, limit),
        )
        .await
    }

    // Need to fix this once we move to payment method for customer
    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn find_payment_method_list_by_global_customer_id(
        &self,
        key_store: &MerchantKeyStore,
        id: &id_type::GlobalCustomerId,
        limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resources(
            key_store,
            PaymentMethod::find_by_global_customer_id(&conn, id, limit),
        )
        .await
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resources(
            key_store,
            PaymentMethod::find_by_customer_id_merchant_id_status(
                &conn,
                customer_id,
                merchant_id,
                status,
                limit,
            ),
        )
        .await
    }

    #[cfg(feature = "v2")]
    #[instrument(skip_all)]
    async fn find_payment_method_by_global_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::GlobalCustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.find_resources(
            key_store,
            PaymentMethod::find_by_global_customer_id_merchant_id_status(
                &conn,
                customer_id,
                merchant_id,
                status,
                limit,
            ),
        )
        .await
    }

    #[cfg(feature = "v1")]
    async fn delete_payment_method_by_merchant_id_payment_method_id(
        &self,
        key_store: &MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        payment_method_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_write(self).await?;
        self.call_database(
            key_store,
            PaymentMethod::delete_by_merchant_id_payment_method_id(
                &conn,
                merchant_id,
                payment_method_id,
            ),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn delete_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method = Conversion::convert(payment_method)
            .await
            .change_context(errors::StorageError::DecryptionError)?;
        let conn = pg_connection_write(self).await?;
        let payment_method_update = PaymentMethodUpdate::StatusUpdate {
            status: Some(common_enums::PaymentMethodStatus::Inactive),
            last_modified_by: None,
        };
        self.call_database(
            key_store,
            payment_method.update_with_id(&conn, payment_method_update.into()),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_by_fingerprint_id(
        &self,
        key_store: &MerchantKeyStore,
        fingerprint_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let conn = pg_connection_read(self).await?;
        self.call_database(
            key_store,
            PaymentMethod::find_by_fingerprint_id(&conn, fingerprint_id),
        )
        .await
    }
}

#[async_trait::async_trait]
impl PaymentMethodInterface for MockDb {
    type Error = errors::StorageError;
    #[cfg(feature = "v1")]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resource::<PaymentMethod, _>(
            key_store,
            payment_methods,
            |pm| pm.get_id() == payment_method_id,
            "cannot find payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method_id: &id_type::GlobalPaymentMethodId,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resource::<PaymentMethod, _>(
            key_store,
            payment_methods,
            |pm| pm.get_id() == payment_method_id,
            "cannot find payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v1")]
    async fn find_payment_method_by_locker_id(
        &self,
        key_store: &MerchantKeyStore,
        locker_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resource::<PaymentMethod, _>(
            key_store,
            payment_methods,
            |pm| pm.locker_id == Some(locker_id.to_string()),
            "cannot find payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v1")]
    async fn get_payment_method_count_by_customer_id_merchant_id_status(
        &self,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        let count = payment_methods
            .iter()
            .filter(|pm| {
                pm.customer_id == *customer_id
                    && pm.merchant_id == *merchant_id
                    && pm.status == status
            })
            .count();
        i64::try_from(count).change_context(errors::StorageError::MockDbError)
    }

    async fn get_payment_method_count_by_merchant_id_status(
        &self,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        let count = payment_methods
            .iter()
            .filter(|pm| pm.merchant_id == *merchant_id && pm.status == status)
            .count();
        i64::try_from(count).change_context(errors::StorageError::MockDbError)
    }

    async fn insert_payment_method(
        &self,
        _key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let mut payment_methods = self.payment_methods.lock().await;

        let pm = Conversion::convert(payment_method.clone())
            .await
            .change_context(errors::StorageError::DecryptionError)?;

        payment_methods.push(pm);
        Ok(payment_method)
    }

    #[cfg(feature = "v1")]
    async fn find_payment_method_by_customer_id_merchant_id_list(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        _limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resources(
            key_store,
            payment_methods,
            |pm| pm.customer_id == *customer_id && pm.merchant_id == *merchant_id,
            "cannot find payment method".to_string(),
        )
        .await
    }

    // Need to fix this once we complete v2 payment method
    #[cfg(feature = "v2")]
    async fn find_payment_method_list_by_global_customer_id(
        &self,
        _key_store: &MerchantKeyStore,
        _id: &id_type::GlobalCustomerId,
        _limit: Option<i64>,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        todo!()
    }

    #[cfg(feature = "v1")]
    async fn find_payment_method_by_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        _limit: Option<i64>,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resources(
            key_store,
            payment_methods,
            |pm| {
                pm.customer_id == *customer_id
                    && pm.merchant_id == *merchant_id
                    && pm.status == status
            },
            "cannot find payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_by_global_customer_id_merchant_id_status(
        &self,
        key_store: &MerchantKeyStore,
        customer_id: &id_type::GlobalCustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        _limit: Option<i64>,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<DomainPaymentMethod>, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        let find_pm_by = |pm: &&PaymentMethod| {
            pm.customer_id == *customer_id && pm.merchant_id == *merchant_id && pm.status == status
        };
        let error_message = "cannot find payment method".to_string();
        self.get_resources(key_store, payment_methods, find_pm_by, error_message)
            .await
    }

    #[cfg(feature = "v1")]
    async fn delete_payment_method_by_merchant_id_payment_method_id(
        &self,
        key_store: &MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        payment_method_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let mut payment_methods = self.payment_methods.lock().await;
        match payment_methods
            .iter()
            .position(|pm| pm.merchant_id == *merchant_id && pm.get_id() == payment_method_id)
        {
            Some(index) => {
                let deleted_payment_method = payment_methods.remove(index);
                Ok(deleted_payment_method
                    .convert(
                        self.get_keymanager_state()
                            .attach_printable("Missing KeyManagerState")?,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(errors::StorageError::DecryptionError)?)
            }
            None => Err(errors::StorageError::ValueNotFound(
                "cannot find payment method to delete".to_string(),
            )
            .into()),
        }
    }

    async fn update_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
        payment_method_update: PaymentMethodUpdate,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method_updated = PaymentMethodUpdateInternal::from(payment_method_update)
            .apply_changeset(
                Conversion::convert(payment_method.clone())
                    .await
                    .change_context(errors::StorageError::EncryptionError)?,
            );
        self.update_resource::<PaymentMethod, _>(
            key_store,
            self.payment_methods.lock().await,
            payment_method_updated,
            |pm| pm.get_id() == payment_method.get_id(),
            "cannot update payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn delete_payment_method(
        &self,
        key_store: &MerchantKeyStore,
        payment_method: DomainPaymentMethod,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_method_update = PaymentMethodUpdate::StatusUpdate {
            status: Some(common_enums::PaymentMethodStatus::Inactive),
            last_modified_by: None,
        };
        let payment_method_updated = PaymentMethodUpdateInternal::from(payment_method_update)
            .apply_changeset(
                Conversion::convert(payment_method.clone())
                    .await
                    .change_context(errors::StorageError::EncryptionError)?,
            );
        self.update_resource::<PaymentMethod, _>(
            key_store,
            self.payment_methods.lock().await,
            payment_method_updated,
            |pm| pm.get_id() == payment_method.get_id(),
            "cannot find payment method".to_string(),
        )
        .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_by_fingerprint_id(
        &self,
        key_store: &MerchantKeyStore,
        fingerprint_id: &str,
    ) -> CustomResult<DomainPaymentMethod, errors::StorageError> {
        let payment_methods = self.payment_methods.lock().await;
        self.get_resource::<PaymentMethod, _>(
            key_store,
            payment_methods,
            |pm| pm.locker_fingerprint_id == Some(fingerprint_id.to_string()),
            "cannot find payment method".to_string(),
        )
        .await
    }
}