use super::{create_checkout_session, sync_account, sync_plan};
use crate::payments::{Error, PaymentProcessor};
use crate::storage::config_store::ConfigStore;
use async_trait::async_trait;
use pbbson::Model;
use std::sync::Arc;
use stripe::Client;

pub struct StripePaymentProcessor<B: Clone + Send + Sync + ToString + 'static> {
    #[allow(unused)]
    pub client: Client,

    #[allow(unused)]
    pub config_store: Arc<dyn ConfigStore<B>>,
}

impl<B: Clone + Send + Sync + ToString> StripePaymentProcessor<B> {
    pub fn new(_app_name: &str, access_token: &str, config_store: Arc<dyn ConfigStore<B>>) -> Self {
        let client = Client::new(access_token);
        Self { client, config_store }
    }
}

#[async_trait]
impl<B: Clone + Send + Sync + ToString> PaymentProcessor<B> for StripePaymentProcessor<B> {
    async fn create_checkout_session(
        &self,
        account: Model,
        plan: Model,
        plan_metadata_field: &str,
        client_reference_id: Option<String>,
        success_url: Option<String>,
        cancel_url: Option<String>,
    ) -> Result<Model, Error> {
        log::trace!("create_checkout_session()");
        create_checkout_session::create(
            self,
            account,
            plan,
            plan_metadata_field,
            client_reference_id,
            success_url,
            cancel_url,
        )
        .await
    }

    async fn sync_account(&self, account: Model, accounts_bucket: B) -> Result<Model, Error> {
        log::trace!("sync_account()");
        sync_account::sync(self, &account, accounts_bucket).await
    }

    async fn sync_plan(
        &self,
        plan: Model,
        plan_metadata_field: &str,
        services_bucket: B,
        plans_bucket: B,
    ) -> Result<Model, Error> {
        log::trace!("sync_plan()");
        sync_plan::sync(self, &plan, plan_metadata_field, services_bucket, plans_bucket).await
    }
}
