use crate::storage::object_store::ObjectStore;
use std::sync::Arc;
use tonic::Status;
use url::Url;

pub async fn new(url: &Url, app_name: &str) -> Result<Arc<dyn ObjectStore>, Status> {
    Ok(match url.scheme() {
        #[cfg(feature = "storage-fs")]
        "file" => {
            let opts = crate::storage::object_store::adapters::fs::Options {
                app_name: Some(app_name.to_string()),
            };
            Arc::new(super::fs::LocalFileSystemObjectStore::new(url, opts).await?)
        }
        #[cfg(feature = "storage-s3")]
        "https" => {
            let opts = crate::storage::object_store::adapters::s3::Options {
                app_name: Some(app_name.to_string()),
            };
            Arc::new(super::s3::S3ObjectStore::new(url, opts).await?)
        }
        #[cfg(feature = "storage-mongodb")]
        "mongodb" | "mongodb+srv" => {
            let opts = crate::storage::object_store::adapters::mongodb::Options {
                app_name: Some(app_name.to_string()),
            };
            Arc::new(super::mongodb::MongoDbObjectStore::new(url, opts).await?)
        }
        _ => {
            let opts = super::service_unavailable::Options {
                app_name: Some(app_name.to_string()),
            };
            Arc::new(
                crate::storage::object_store::adapters::service_unavailable::ServiceUnavailableObjectStore::new(opts),
            )
        }
    })
}

#[cfg(test)]
mod tests {
    const TEST_OBJECT_STORE_URL: &str = "TEST_OBJECT_STORE_URL";

    #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
    async fn can_connect() {
        let object_store_url = match std::env::var(TEST_OBJECT_STORE_URL) {
            Ok(url) => url.parse().unwrap(),
            _ => {
                eprintln!("Skipping test because no {TEST_OBJECT_STORE_URL} is set");
                return;
            }
        };
        let _object_store = super::new(&object_store_url, "object_store-test")
            .await
            .expect("Expected to be able to construct an object store");
    }
}
