mod host_functions;
mod objects;
use {
    crate::{
        handle::{self, Handle},
        interp::{host_functions::host_make_object, objects::OBJECTS},
    },
    alloc::{string::String, vec::Vec},
    hashbrown::HashMap,
    log::trace,
    spin::{Lazy, Mutex},
    wasmi::{Caller, Error, Func, Instance, Linker, Module, Store, TypedFunc},
    xml::XMLElement,
};
// Seperate use statement
use alloc::vec;

#[derive(Debug)]

pub struct WasmContext {
    pub proc_id:  Option<u64>,
    pub instance: Instance,
    pub store:    Store<HostState>,
}

pub fn wasm() -> Result<(), wasmi::Error> {
    use wasmi::{Config, Engine};
    let mut conf = Config::default();
    conf.wasm_bulk_memory(true);
    // conf.,
    let engine = Engine::new(&conf);
    // trace!("Engine constructed");

    // let wasm = include_bytes!("../../wasm_syscall_test.wasm");
    let wasm = include_bytes!("../../../test.wasm");

    // trace!("Loading WASM binary");
    let module = Module::new(&engine, &wasm[..]).unwrap();
    // trace!("Constructing wasm module");
    let hs = HostState { handles: vec![] };
    let mut store = Store::new(&engine, hs);
    // trace!("constructing host store");

    let read_mem_addr = Func::wrap(
        &mut store,
        |caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
    );

    let mut linker = <Linker<HostState>>::new(&engine);

    linker.define(
        "host",
        "read_mem_addr",
        Func::wrap(
            &mut store,
            |caller: Caller<'_, HostState>, param: i32| -> i32 {
                read_memory_address(caller, param)
            },
        ),
    )?;

    linker.define(
        "host",
        "register_idt_handler",
        Func::wrap(&mut store, host_functions::host_register_idt_handler),
    )?;

    linker.define(
        "host",
        "read_object_attribute",
        Func::wrap(&mut store, host_read_object_attribute),
    )?;

    linker.define(
        "host",
        "create_object",
        Func::wrap(&mut store, host_make_object),
    )?;

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

    let version = instance.get_global(&store, "VERSION");

    // trace!("Version: {:?}", version);
    let hello = instance.get_typed_func::<(), i64>(&store, "start")?;

    let ret = hello.call(&mut store, ())?;
    trace!("Called start got return of {:?}", ret);

    Ok(())
}

#[derive(Clone, Debug)]
pub struct HostState {
    handles: Vec<Handle>,
}

pub fn read_memory_address(caller: Caller<'_, HostState>, address: i32) -> i32 {
    trace!("Address: {}", address);
    // let obj = host_make_object(caller, 16, 23);
    0
}

pub fn host_read_object_attribute(
    caller: Caller<'_, HostState>,
    handle: i64,
    address_start: i32,
    length_of_string: i32,
) -> (i32, i32) {
    {
        let binding = OBJECTS;
        let mut olock = binding.lock();

        // olock.get(&handle);
    }

    let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
    let mem_array = mem.data(&caller);
    let mut name = String::new();
    for i in address_start..(address_start + length_of_string) {
        let ch = mem_array[i as usize] as char;
        name.push(ch);
    }

    (0, 0)
}

pub fn build_wasm_context(bytes: Vec<u8>) -> Result<WasmContext, wasmi::Error> {
    use wasmi::{Config, Engine};
    let mut conf = Config::default();
    conf.wasm_bulk_memory(true);
    // conf.,
    let engine = Engine::new(&conf);
    // trace!("Engine constructed");

    // let wasm = include_bytes!("../../wasm_syscall_test.wasm");
    let wasm = include_bytes!("../../../test.wasm");

    // trace!("Loading WASM binary");
    let module = Module::new(&engine, &wasm[..]).unwrap();
    // trace!("Constructing wasm module");
    let hs = HostState { handles: vec![] };
    let mut store = Store::new(&engine, hs);
    // trace!("constructing host store");

    let read_mem_addr = Func::wrap(
        &mut store,
        |caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
    );

    let mut linker = <Linker<HostState>>::new(&engine);
    linker.define(
        "host",
        "read_mem_addr",
        Func::wrap(
            &mut store,
            |caller: Caller<'_, HostState>, param: i32| -> i32 {
                read_memory_address(caller, param)
            },
        ),
    )?;

    linker.define(
        "host",
        "read_object_attribute",
        Func::wrap(&mut store, host_read_object_attribute),
    )?;

    linker.define(
        "host",
        "create_object",
        Func::wrap(&mut store, host_make_object),
    )?;

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

    let wc = WasmContext {
        instance,
        store,
        proc_id: None,
    };

    Ok(wc)
}

pub type HostFunctionIDT = HashMap<usize, WCFunction>;
pub struct WCFunction {
    wc: WasmContext,
    function: TypedFunc<(), ()>,
}

pub static HFIDT: Lazy<Mutex<HostFunctionIDT>> = Lazy::new(|| {
    let mut hfidt = HashMap::new();

    Mutex::new(hfidt)
});