pub mod fs;
pub mod memory;

use crate::error::StoreError;
use crate::model::{AnnotationSet, Library, LibraryId, Reference, ReferenceId, Snapshot};

/// Abstraction over the storage backend.
///
/// The git-backed filesystem (`FsStore`) is the production implementation.
/// An in-memory implementation (`MemoryStore`) exists for testing.
pub trait Store {
    // ---- References ----

    fn save_reference(&mut self, reference: &Reference) -> Result<(), StoreError>;
    fn load_reference(&self, id: ReferenceId) -> Result<Reference, StoreError>;
    fn delete_reference(&mut self, id: ReferenceId) -> Result<(), StoreError>;
    fn list_reference_ids(&self) -> Result<Vec<ReferenceId>, StoreError>;

    // ---- Libraries ----

    fn save_library(&mut self, library: &Library) -> Result<(), StoreError>;
    fn load_library(&self, id: LibraryId) -> Result<Library, StoreError>;
    fn delete_library(&mut self, id: LibraryId) -> Result<(), StoreError>;
    fn list_library_ids(&self) -> Result<Vec<LibraryId>, StoreError>;

    // ---- Annotations ----

    /// Load the annotation set for a reference. Returns an empty set if none exists.
    fn load_annotations(&self, ref_id: ReferenceId) -> Result<AnnotationSet, StoreError>;
    fn save_annotations(&mut self, set: &AnnotationSet) -> Result<(), StoreError>;
    fn delete_annotations(&mut self, ref_id: ReferenceId) -> Result<(), StoreError>;

    // ---- Snapshots ----

    fn create_snapshot(&mut self, message: &str) -> Result<Snapshot, StoreError>;
    fn list_snapshots(&self) -> Result<Vec<Snapshot>, StoreError>;
    /// Restore to a previous snapshot. Caller must ensure no uncommitted changes exist.
    fn restore_snapshot(&mut self, snapshot_id: &str) -> Result<(), StoreError>;
    fn has_uncommitted_changes(&self) -> Result<bool, StoreError>;
}

// Re-export concrete types for convenience.
pub use fs::FsStore;
pub use memory::MemoryStore;
