use super::{
    AccountError, ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt,
    Serializable, Word,
};
use crate::{
    accounts::StorageMapDelta,
    crypto::{
        hash::rpo::RpoDigest,
        merkle::{InnerNodeInfo, LeafIndex, Smt, SmtLeaf, SmtProof, SMT_DEPTH},
    },
};
pub const EMPTY_STORAGE_MAP_ROOT: Word = [
    Felt::new(15321474589252129342),
    Felt::new(17373224439259377994),
    Felt::new(15071539326562317628),
    Felt::new(3312677166725950353),
];
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageMap {
    map: Smt,
}
impl StorageMap {
    pub const STORAGE_MAP_TREE_DEPTH: u8 = SMT_DEPTH;
    pub const EMPTY_VALUE: Word = Smt::EMPTY_VALUE;
    pub fn new() -> Self {
        StorageMap { map: Smt::new() }
    }
    pub fn with_entries(
        entries: impl IntoIterator<Item = (RpoDigest, Word)>,
    ) -> Result<Self, AccountError> {
        let mut storage_map = Smt::new();
        for (key, value) in entries {
            storage_map.insert(key, value);
        }
        Ok(StorageMap { map: storage_map })
    }
    pub const fn depth(&self) -> u8 {
        SMT_DEPTH
    }
    pub fn root(&self) -> RpoDigest {
        self.map.root() }
    pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf {
        self.map.get_leaf(key) }
    pub fn get_value(&self, key: &RpoDigest) -> Word {
        self.map.get_value(key) }
    pub fn open(&self, key: &RpoDigest) -> SmtProof {
        self.map.open(key) }
    pub fn leaves(&self) -> impl Iterator<Item = (LeafIndex<SMT_DEPTH>, &SmtLeaf)> {
        self.map.leaves() }
    pub fn entries(&self) -> impl Iterator<Item = &(RpoDigest, Word)> {
        self.map.entries() }
    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
        self.map.inner_nodes() }
    pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word {
        self.map.insert(key, value) }
    pub fn apply_delta(&mut self, delta: &StorageMapDelta) -> Digest {
        for (&key, &value) in delta.leaves().iter() {
            self.insert(key, value);
        }
        self.root()
    }
}
impl Default for StorageMap {
    fn default() -> Self {
        Self::new()
    }
}
impl Serializable for StorageMap {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        self.map.write_into(target)
    }
}
impl Deserializable for StorageMap {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let smt = Smt::read_from(source)?;
        Ok(StorageMap { map: smt })
    }
}
#[cfg(test)]
mod tests {
    use miden_crypto::{hash::rpo::RpoDigest, Felt};
    use super::{Deserializable, Serializable, StorageMap, Word, EMPTY_STORAGE_MAP_ROOT};
    #[test]
    fn account_storage_serialization() {
        let storage_map_default = StorageMap::default();
        let bytes = storage_map_default.to_bytes();
        assert_eq!(storage_map_default, StorageMap::read_from_bytes(&bytes).unwrap());
        let storage_map_leaves_2: [(RpoDigest, Word); 2] = [
            (
                RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
                [Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)],
            ),
            (
                RpoDigest::new([Felt::new(105), Felt::new(106), Felt::new(107), Felt::new(108)]),
                [Felt::new(5_u64), Felt::new(6_u64), Felt::new(7_u64), Felt::new(8_u64)],
            ),
        ];
        let storage_map = StorageMap::with_entries(storage_map_leaves_2).unwrap();
        let bytes = storage_map.to_bytes();
        assert_eq!(storage_map, StorageMap::read_from_bytes(&bytes).unwrap());
    }
    #[test]
    fn test_empty_storage_map_constants() {
        assert_eq!(*StorageMap::default().root(), EMPTY_STORAGE_MAP_ROOT);
    }
}