//! Source Registry storage for human-readable source metadata.
//!
//! The Source Registry provides a mapping from content-addressed source hashes
//! to human-readable labels and metadata. This enables developers to display
//! meaningful source information in their UIs instead of raw hashes.
//!
//! # Storage Layout
//!
//! | Key Pattern | Value | Purpose |
//! |-------------|-------|---------|
//! | `\x00SREG:{hash_hex}` | Serialized SourceRecord | Primary source metadata |
//! | `\x00SREG_TIER:{tier}:{hash_hex}` | Empty marker | Tier index for listing |
//! | `\x00SREG_LABEL:{label_prefix}:{hash_hex}` | Empty marker | Label index for search |
//!
//! # Example
//!
//! ```ignore
//! use stemedb_storage::{HybridStore, GenericSourceRegistry, SourceRegistry};
//!
//! let kv_store = HybridStore::open("./data")?;
//! let registry = GenericSourceRegistry::new(kv_store);
//!
//! // Register a source
//! let record = SourceRecord::new(
//!     source_hash,
//!     "RFC 7519 - JSON Web Token".to_string(),
//!     Some("https://tools.ietf.org/html/rfc7519".to_string()),
//!     0, // Regulatory tier
//!     timestamp,
//! );
//! registry.register(&record).await?;
//!
//! // Retrieve by hash
//! let retrieved = registry.get(&source_hash).await?;
//!
//! // List by tier
//! let regulatory_sources = registry.list_by_tier(0, 100).await?;
//!
//! // Search by label prefix
//! let rfc_sources = registry.search("RFC", 100).await?;
//! ```

mod generic;

use async_trait::async_trait;
use stemedb_core::types::{SourceRecord, SourceStatus};

use crate::error::Result;

pub use generic::GenericSourceRegistry;

/// Trait for source registry operations.
///
/// Provides CRUD operations for source metadata records, plus indexing
/// for efficient listing by tier and searching by label.
#[async_trait]
pub trait SourceRegistry: Send + Sync {
    /// Register a new source or update an existing one.
    ///
    /// If a source with the same hash already exists, it will be replaced.
    /// Secondary indexes (tier, label) are updated atomically.
    async fn register(&self, record: &SourceRecord) -> Result<()>;

    /// Retrieve a source record by its hash.
    ///
    /// Returns `None` if the source is not registered.
    async fn get(&self, hash: &[u8; 32]) -> Result<Option<SourceRecord>>;

    /// Update the status of a source.
    ///
    /// Returns an error if the source doesn't exist.
    async fn update_status(
        &self,
        hash: &[u8; 32],
        status: SourceStatus,
        timestamp: u64,
    ) -> Result<()>;

    /// Update the tier of a source.
    ///
    /// This also updates the tier index.
    /// Returns an error if the source doesn't exist.
    async fn update_tier(&self, hash: &[u8; 32], tier: u8, timestamp: u64) -> Result<()>;

    /// List sources by tier.
    ///
    /// Returns up to `limit` sources with the specified tier.
    async fn list_by_tier(&self, tier: u8, limit: usize) -> Result<Vec<SourceRecord>>;

    /// Search sources by label prefix (case-insensitive).
    ///
    /// Returns up to `limit` sources whose label starts with the query.
    async fn search(&self, query: &str, limit: usize) -> Result<Vec<SourceRecord>>;

    /// Delete a source record.
    ///
    /// Removes the primary record and all secondary indexes.
    /// Returns true if the source existed, false otherwise.
    async fn delete(&self, hash: &[u8; 32]) -> Result<bool>;

    /// Count all registered sources.
    async fn count(&self) -> Result<usize>;
}
