use alloc::vec::Vec;

use miden_protocol::Word;
use miden_protocol::crypto::merkle::mmr::{Forest, MmrDelta};
use miden_protocol::crypto::merkle::{MerklePath, SparseMerklePath};

use crate::rpc::errors::RpcConversionError;
use crate::rpc::generated as proto;

// MERKLE PATH
// ================================================================================================

impl From<MerklePath> for proto::primitives::MerklePath {
    fn from(value: MerklePath) -> Self {
        (&value).into()
    }
}

impl From<&MerklePath> for proto::primitives::MerklePath {
    fn from(value: &MerklePath) -> Self {
        let siblings = value.nodes().iter().map(proto::primitives::Digest::from).collect();
        proto::primitives::MerklePath { siblings }
    }
}

impl TryFrom<&proto::primitives::MerklePath> for MerklePath {
    type Error = RpcConversionError;

    fn try_from(merkle_path: &proto::primitives::MerklePath) -> Result<Self, Self::Error> {
        merkle_path.siblings.iter().map(Word::try_from).collect()
    }
}

impl TryFrom<proto::primitives::MerklePath> for MerklePath {
    type Error = RpcConversionError;

    fn try_from(merkle_path: proto::primitives::MerklePath) -> Result<Self, Self::Error> {
        MerklePath::try_from(&merkle_path)
    }
}

// SPARSE MERKLE PATH

// ================================================================================================

impl From<SparseMerklePath> for proto::primitives::SparseMerklePath {
    fn from(value: SparseMerklePath) -> Self {
        let (empty_nodes_mask, siblings) = value.into_parts();

        proto::primitives::SparseMerklePath {
            empty_nodes_mask,

            siblings: siblings.into_iter().map(proto::primitives::Digest::from).collect(),
        }
    }
}

impl TryFrom<proto::primitives::SparseMerklePath> for SparseMerklePath {
    type Error = RpcConversionError;

    fn try_from(merkle_path: proto::primitives::SparseMerklePath) -> Result<Self, Self::Error> {
        Ok(SparseMerklePath::from_parts(
            merkle_path.empty_nodes_mask,
            merkle_path
                .siblings
                .into_iter()
                .map(Word::try_from)
                .collect::<Result<Vec<_>, _>>()?,
        )?)
    }
}

// MMR DELTA
// ================================================================================================

impl TryFrom<MmrDelta> for proto::primitives::MmrDelta {
    type Error = RpcConversionError;

    fn try_from(value: MmrDelta) -> Result<Self, Self::Error> {
        let data = value.data.into_iter().map(proto::primitives::Digest::from).collect();
        Ok(proto::primitives::MmrDelta {
            forest: u64::try_from(value.forest.num_leaves())?,
            data,
        })
    }
}

impl TryFrom<proto::primitives::MmrDelta> for MmrDelta {
    type Error = RpcConversionError;

    fn try_from(value: proto::primitives::MmrDelta) -> Result<Self, Self::Error> {
        let data: Result<Vec<_>, RpcConversionError> =
            value.data.into_iter().map(Word::try_from).collect();

        let num_leaves = usize::try_from(value.forest).map_err(|_| {
            RpcConversionError::InvalidField("MmrDelta forest value exceeds usize".into())
        })?;
        Ok(MmrDelta {
            forest: Forest::new(num_leaves)
                .map_err(|_| RpcConversionError::InvalidField("MmrDelta forest invalid".into()))?,
            data: data?,
        })
    }
}
