use std::io::{stdout, Write};
use std::thread;
use std::time::Duration;

use anyhow::Result;
use wasmtime::*;

fn main() -> Result<()> {
    // Modules can be compiled through either the text or binary format
    // let engine = Engine::default();
    let mut config = Config::default();
    config.consume_fuel(true);
    config.epoch_interruption(true);
    config.static_memory_maximum_size(1_000_000_u64);
    config.dynamic_memory_guard_size(0_u64);
    let engine = Engine::new(&config).unwrap();

    let add_wasm_bytes = std::fs::read("add.wasm").expect("Read wasm failed");
    let module = Module::new(&engine, add_wasm_bytes)?;

    let linker = Linker::new(&engine);
    let mut store = Store::new(&engine, 4);
    store.set_epoch_deadline(10);
    store.epoch_deadline_trap();
    // store.epoch_deadline_callback(|a /*store -> data*/| {
    //     println!("!epoch_deadline_callback! -- {}", a);
    //     //Ok(1)
    //     Err(anyhow::anyhow!("error"))
    // });

    thread::spawn(move || {
        for _ in 0.. {
            thread::sleep(Duration::from_millis(100));
            print!(":");
            stdout().flush().ok();
            engine.increment_epoch();
        }
    });

    let instance = linker.instantiate(&mut store, &module)?;

    let hello = instance.get_typed_func::<(i32, i32), i32>(&mut store, "add")?;
    // let hello2 = instance.get_typed_func::<(&str, i32), i32, _>(&mut store, "add")?;

    store.add_fuel(1000_000_000_u64).ok();

    println!("1 + 2 = {:?}", hello.call(&mut store, (1, 2))?);
    println!("Fuel consumed: {:?}", store.fuel_consumed());
    println!("2 + 3 = {:?}", hello.call(&mut store, (2, 3))?);
    println!("Fuel consumed: {:?}", store.fuel_consumed());

    for i in 0..100000000 {
        if i % 10000 == 0 {
            print!(".");
            stdout().flush().ok();
        }
        hello.call(&mut store, (1, 2))?;
    }

    Ok(())
}

