use crate::tally::TallyList;
use crate::utilstring::to_hex;
use std::fmt;

/**
 * Hash used in a merkle proof. If it's a leaf node, its a vote reference,
 * otherwise a node hash.
 *
 * The node hash of a leaf node can be derived from its vote reference.
 */
pub type ProofHash = [u8; 32];

/// A node in the tally merkle tree as represented in a merkle proof,
/// consisting of the node hash and tally.
pub type ProofNode = (ProofHash, Option<TallyList>);
/// Two siblings nodes in a merkle tree proof. If a sibling is None, that means
/// you should be able to derive it from the "above" branches.
pub type ProofBranch = (Option<ProofNode>, Option<ProofNode>);

/// Merkle Tally Proof
#[derive(Debug, Default)]
pub struct Proof {
    /// Pairs of sibling nodes in a merkle tally leading up to a merkle root
    /// hash, allowing for verifying that a set of nodes belong in a tree.
    pub branches: Vec<ProofBranch>,
}

impl fmt::Display for Proof {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Proof {{")?;

        for (left, right) in &self.branches {
            let l = if let Some((hash, _tally)) = left {
                to_hex(hash.as_slice()).unwrap()
            } else {
                "None".to_string()
            };
            let r = if let Some((hash, _tally)) = right {
                to_hex(hash.as_slice()).unwrap()
            } else {
                "None".to_string()
            };
            writeln!(f, "  ({}, {}) ", l, r)?;
        }
        write!(f, "}}")
    }
}
