use crate::Error;
use futures::Stream;
use nostr_rs_types::types::{Event, Filter};

/// Trait to store/query events
#[async_trait::async_trait]
pub trait Storage: Send + Sync {
    /// Result iterators
    type Cursor<'a>: Stream<Item = Result<Event, Error>> + Unpin + Send
    where
        Self: 'a;

    /// Returns true if the storage is flushing data to disk
    fn is_flushing(&self) -> bool {
        false
    }

    /// Stores a new event into the database. This action will also creates all
    /// the needed indexes to find this event later by reference, author, kind or tag.
    async fn store(&self, event: &Event) -> Result<bool, Error>;

    /// Flags the current event as initiated locally. This useful to retrieve
    /// events using `get_local_events`.
    async fn set_local_event(&self, event: &Event) -> Result<(), Error>;

    /// Returns an event by its ID
    async fn get_event<T: AsRef<[u8]> + Send + Sync>(&self, id: T) -> Result<Option<Event>, Error>;

    /// Get events from the database with a given filter
    ///
    /// The first step is to use one available index to get a list of event-IDs,
    /// then call `load_and_filter_events` that will load the events from the
    /// `Events` namespace and will filter them by the given parameters.
    async fn get_by_filter(&self, query: Filter) -> Result<Self::Cursor<'_>, Error>;

    /// Return a vector of all local events
    async fn get_local_events(&self, limit: Option<usize>) -> Result<Self::Cursor<'_>, Error>;

    /// Stores an event, similar to store(Event), but keeps track of this event in a
    /// local index. This is useful to keep track of the events that are created by
    /// this node, to be broadcasted to new nodes in the future
    async fn store_local_event(&self, event: &Event) -> Result<bool, Error> {
        let ret = self.store(event).await?;
        self.set_local_event(event).await?;
        Ok(ret)
    }
}
