use crate::storage::Error;
use async_trait::async_trait;
use pbbson::Model;

#[async_trait]
pub trait ConfigStore<B: ToString>: Sync + Send {
    async fn create(&self, bucket: B, model: Model) -> Result<Model, Error>;
    async fn delete(&self, bucket: B, id: &str, by_account_id: Option<String>) -> Result<(), Error>;
    async fn find(&self, bucket: B, id: &str) -> Result<Model, Error>;
    async fn find_many(&self, bucket: B, options: FindOptions) -> Result<Vec<Model>, Error>;
    async fn update(&self, bucket: B, model: Model) -> Result<Model, Error>;
}

#[derive(Clone, Debug, Default)]
pub struct FindOptions {
    pub filter: Model,
    pub ordering: Option<Model>,
    pub pagination: (Option<u32>, Option<u32>),
    pub projection: Option<Model>,
}

impl FindOptions {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_filter(&self, filter: Model) -> Self {
        Self {
            filter,
            ordering: self.ordering.clone(),
            pagination: self.pagination,
            projection: self.projection.clone(),
        }
    }

    pub fn with_ordering(&self, ordering: Option<Model>) -> Self {
        Self {
            filter: self.filter.clone(),
            ordering,
            pagination: self.pagination,
            projection: self.projection.clone(),
        }
    }

    pub fn with_pagination(&self, offset: Option<u32>, limit: Option<u32>) -> Self {
        Self {
            filter: self.filter.clone(),
            ordering: self.ordering.clone(),
            pagination: (offset, limit),
            projection: self.projection.clone(),
        }
    }

    pub fn with_projection(&self, projection: Option<Model>) -> Self {
        Self {
            filter: self.filter.clone(),
            ordering: self.ordering.clone(),
            pagination: self.pagination,
            projection,
        }
    }
}
