/// Transcript is a wrapper around Merlin Transcripts to provide some structure for
/// more complex protocol-driven applications as seen in Tapir
#[derive(Clone)]
pub struct Transcript {
    mtranscript: merlin::Transcript,
    transcript: String,
}

impl Transcript {
    pub fn new_transcript(label: &'static str) -> Transcript {
        Transcript {
            mtranscript: merlin::Transcript::new(label.as_ref()),
            transcript: String::new(),
        }
    }

    pub fn add_to_transcript(&mut self, label: &'static str, b: &[u8]) {
        let op = format!("{} ({}) {};", label, b.len(), hex::encode(b));
        self.transcript = format!("{}\n{}", self.transcript, op);
        self.mtranscript.append_message(label.as_ref(), b);
    }

    pub fn output_transcript_to_audit(&self) -> String {
        self.transcript.clone()
    }

    pub fn new_protocol(&mut self, label: &str) {
        let op = format!("---- new-protocol: {} ----", label);
        self.transcript = format!("{}\n{}", self.transcript, op);
        self.mtranscript.append_message("protocol".as_ref(), label.as_ref());
    }

    pub fn commit_to_transcript(&mut self, label: &'static str) -> [u8; 64] {
        let mut result = [0u8; 64];
        self.mtranscript.challenge_bytes(label.as_ref(), result.as_mut_slice());
        self.transcript = format!("{}\nextract {}: {}", self.transcript, label, hex::encode(result));
        result
    }
}

#[cfg(test)]
mod tests {
    use crate::primitives::transcript::Transcript;

    #[test]
    fn test_transcript() {
        let mut t = Transcript::new_transcript("label");
        t.add_to_transcript("action", "test data".as_bytes());
        if t.output_transcript_to_audit() != t.output_transcript_to_audit() {
            panic!("Multiple Audit Calls should not impact underlying Transcript")
        }

        println!("{}", t.output_transcript_to_audit());
        println!("{:?}", t.commit_to_transcript("first commit"));
        println!("{}", t.output_transcript_to_audit());
        println!("{:?}", t.commit_to_transcript("second commit"));
        t.add_to_transcript("action", "test data".as_bytes());

        // Test vector from golang Tapir tests...
        let test_vector: [u8; 64] = [
            239, 5, 86, 166, 139, 70, 247, 187, 137, 37, 36, 183, 53, 51, 114, 115, 24, 103, 110, 65, 82, 190, 88, 106, 4, 114, 91, 194, 90, 114, 107, 19, 3, 33, 103, 187, 122, 54, 156, 213, 203, 40,
            132, 26, 203, 130, 117, 55, 161, 245, 30, 102, 127, 151, 233, 148, 116, 212, 235, 186, 46, 59, 1, 8,
        ];
        assert_eq!(test_vector, t.commit_to_transcript("third commit"))
    }
}
