use super::{batch::WriteBatch, error::StorageError, iterator::PrefixIterator};

/// The storage engine trait.
///
/// All access to durable state goes through this interface.
/// Implementations include `InMemoryBackend` (for testing) and
/// `FjallBackend` (for production).
///
/// Keys and values are opaque byte slices — typed serialization
/// is handled by higher modules.
pub trait StorageEngine: Send + Sync {
    /// Read a single key. Returns `None` if the key does not exist.
    ///
    /// # Errors
    ///
    /// Returns `StorageError` on I/O failure or corruption.
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, StorageError>;

    /// Write a single key-value pair.
    ///
    /// # Errors
    ///
    /// Returns `StorageError` on I/O failure or if the engine is closed.
    fn put(&self, key: &[u8], value: &[u8]) -> Result<(), StorageError>;

    /// Delete a key. No-op if the key does not exist.
    ///
    /// # Errors
    ///
    /// Returns `StorageError` on I/O failure or if the engine is closed.
    fn delete(&self, key: &[u8]) -> Result<(), StorageError>;

    /// Scan all keys with the given prefix, in lexicographic order.
    ///
    /// Returns a boxed iterator that yields `(key, value)` pairs.
    fn scan_prefix(&self, prefix: &[u8]) -> PrefixIterator<'_>;

    /// Write a batch of operations atomically.
    ///
    /// Either all operations are applied or none are.
    ///
    /// # Durability
    ///
    /// Atomicity is **not** durability. A successful return guarantees the batch
    /// commits all-or-nothing, but the bytes may still sit in an in-process
    /// memtable / OS page cache and be lost on power loss. Callers that need the
    /// batch to survive a crash MUST pair it with [`flush`](Self::flush) (which
    /// `fsync`s to stable storage) — for the multi-keyspace backend that barrier
    /// is `FjallStorage::flush_all` (a single `persist(SyncAll)` covering every
    /// keyspace). Until that barrier returns, treat the batch as committed-not-yet-durable.
    ///
    /// # Errors
    ///
    /// Returns `StorageError` on I/O failure.
    fn write_batch(&self, batch: WriteBatch) -> Result<(), StorageError>;

    /// Force all buffered data to stable storage.
    ///
    /// # Errors
    ///
    /// Returns `StorageError` on I/O failure.
    fn flush(&self) -> Result<(), StorageError>;
}
