//! # Database
//!
//! It supports `SqlLite` and `RocksDB`.
//!
//! ## `RocksDB`
//!
//! `SqlLite` is used by default.
//!
//! ## `SqlLite`
//!
//! To use `SqlLite`, you need to compile with the `sqlite_storage` feature and with `--no-default-features` flag.

use std::collections::HashSet;

use thiserror::Error;

use crate::block::types::block::Block;
use crate::peer::PeerId;
use crate::utilities::crypto::Certificate;
use crate::utilities::merkle::MerkleTree;

#[cfg(feature = "rocksdb_storage")]
pub(crate) mod rocksdb;

#[cfg(feature = "sqlite_storage")]
pub(crate) mod sqlite;

pub(crate) type Result<T> = std::result::Result<T, DatabaseError>;

#[derive(Error, Debug)]
pub(crate) enum DatabaseError {
    //Pessimistically assume that most database errors are fatal and unrecoverable.
    #[error("Database failure: {0}")]
    DatabaseFailure(#[from] anyhow::Error),
}

pub(crate) trait EphemeraDatabase: Send {
    /// Returns block by its id. Block ids are generated by Ephemera
    fn get_block_by_hash(&self, block_hash: &str) -> Result<Option<Block>>;

    /// Returns last committed/finalised block.
    fn get_last_block(&self) -> Result<Option<Block>>;

    /// Returns block by its height
    fn get_block_by_height(&self, height: u64) -> Result<Option<Block>>;

    /// Returns block certificates.
    ///
    /// Certificates were created as part of broadcast protocol and signed by peers who participated.
    fn get_block_certificates(&self, block_hash: &str) -> Result<Option<Vec<Certificate>>>;

    /// Returns peers who participated in block broadcast.
    fn get_block_broadcast_group(&self, block_hash: &str) -> Result<Option<Vec<PeerId>>>;

    /// Stores block and its signatures
    fn store_block(
        &mut self,
        block: &Block,
        certificates: HashSet<Certificate>,
        members: HashSet<PeerId>,
    ) -> Result<()>;

    /// Returns block merkle tree
    fn get_block_merkle_tree(&self, block_hash: &str) -> Result<Option<MerkleTree>>;
}
