use std::path::Path;

use derive_more::Debug;

use crate::utils::{DbInfo, Persist};

#[derive(Debug, Clone)]
pub struct Database {
    #[debug(skip)]
    pub db: super::Db,
    pub db_info: Persist<DbInfo>,
    pub path: String,
}

impl Database {
    #[tracing::instrument(skip(self), name = "Database::close", fields(path = self.path))]
    pub fn close(&self) {
        self.db_info.save();
    }
}

impl Database {
    #[tracing::instrument(name = "Database::new")]
    pub fn new<P>(path: P, cache_capacity: usize) -> Self
    where
        P: AsRef<Path> + std::fmt::Debug,
    {
        use std::sync::Arc;

        use parking_lot::ReentrantMutex;
        use sled::Config;

        let path = path.as_ref();
        let sled_path = path.join("sled");

        let db = Config::new()
            .path(sled_path)
            .cache_capacity_bytes(cache_capacity)
            .open()
            .expect("cannot open persist db");

        let db_info = Persist::<DbInfo>::open(path.join("db.info"));
        let db = Arc::new(ReentrantMutex::new(db));

        Self {
            db,
            db_info,
            path: path.to_string_lossy().to_string(),
        }
    }

    pub fn open_tree(&self, name: &str) -> super::Tree {
        Box::new(self.db.lock().open_tree(name).expect("cannot open tree"))
    }
}
