//! Minimal `wasm-pack` library for generation of an IPFS CID (v0 and v1) from a given file
//! Adapted from [this `rust-ipfs` example](https://github.com/rs-ipfs/rust-ipfs/blob/master/unixfs/examples/add.rs)
//! 
//! # Example:
//! Minimal node app is located in `./node-app`
//! To run, simply `cd` into that directory and run `npm start`
//! Node App adapted from [this `wasm-pack` template](https://github.com/rustwasm/create-wasm-app)

use cid::Cid;
use ipfs_unixfs::file::adder::FileAdder;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub fn get_cid(bytes: Vec<u8>) -> String {

    let mut stats = Stats::default();
    let mut adder = FileAdder::default();

    let mut total  = 0;
    while total < bytes.len() {
        let (_, consumed) = adder.push(&bytes[total..]);
        total += consumed;
    }

    let blocks = adder.finish();

    stats.process(blocks);
    
    let cids = stats.get_json_cids();

    cids
}

#[derive(Default)]
struct Stats {
    last: Option<Cid>,
}


impl Stats {
    fn process<I: Iterator<Item = (Cid, Vec<u8>)>>(&mut self, new_blocks: I) {
        for (cid, _) in new_blocks {
            self.last = Some(cid);
        }
    }

    fn get_json_cids(&self) -> String {
        let cidv0 = self.last.as_ref().unwrap();
        let cidv1 = Cid::new_v1(cid::Codec::DagProtobuf, cidv0.hash().to_owned());

        String::from(format!("{{\"CIDv0\":\"{}\",\"CIDv1\":\"{}\"}}",cidv0,cidv1))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    pub fn test_cid_wasm(){
        // Known test case for simple string "abcdefg\n" as a Vec<u8> -- tool that can help: https://onlineunicodetools.com/convert-unicode-to-utf8  -- note that u8 is ecoded in decimal!!!
        let content = vec![97, 98, 99, 100, 101, 102, 103, 10];
        let cidv0 = "QmYhMRHZAceoM8L21yqBcJjk1TXasZzHw4g1qzTSHBLq1c";
        let cidv1 = "bafybeiez4kcddcze2tyxsrxzp3lbtx6jyue3mhbg4uo2t2mmdfywwp3sxm";

        let expected = String::from(format!("{{\"CIDv0\":\"{}\",\"CIDv1\":\"{}\"}}",cidv0,cidv1));

        assert_eq!(expected, get_cid(content));    
    }
}

