//! Database property access functionality.
use crate::binding::{leveldb_free, leveldb_property_value};
use std::ffi::{CStr, CString, NulError};

/// Predefined LevelDB property names for convenient access.
pub mod property_name {
    /// Get the number of files at a specific level.
    ///
    /// This property name serves as a prefix and must be concatenated with
    /// the desired level number to form the complete property name. (e.g., "leveldb.num-files-at-level0").
    pub const NUM_FILES_AT_LEVEL: &str = "leveldb.num-files-at-level";

    /// Returns a multi-line string that describes statistics about the internal operation of the LevelDB instance.
    pub const STATS: &str = "leveldb.stats";

    /// Returns a multi-line string that describes all of the sstables that make up the LevelDB instance contents.
    pub const SSTABLES: &str = "leveldb.sstables";

    /// Returns the approximate number of bytes of memory in use by the LevelDB instance.
    pub const APPROXIMATE_MEMORY_USAGE: &str = "leveldb.approximate-memory-usage";
}

/// Trait for accessing LevelDB properties.
pub trait Property {
    /// Get a property value by name.
    ///
    /// Returns Ok(Some(String)) if the property exists, Ok(None) if the property name is unknown.
    ///
    /// For common statistical properties like number of files at various levels, overall stats, sstables
    /// information, or memory usage, it is recommended to use more convenient methods provided by the
    /// `Statistics` trait instead.
    fn get_property(&self, name: &str) -> Result<Option<String>, NulError>;
}

impl Property for super::Database {
    fn get_property(&self, name: &str) -> Result<Option<String>, NulError> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let result = leveldb_property_value(self.database.ptr, c_name.as_ptr());
            if result.is_null() {
                Ok(None)
            } else {
                let c_str = CStr::from_ptr(result);
                let property = c_str.to_string_lossy().into_owned();
                leveldb_free(result as *mut libc::c_void);
                Ok(Some(property))
            }
        }
    }
}
