use {
    alloc::{collections::VecDeque, rc::Rc, slice, vec::Vec},
    hbvm::validate::validate,
};

use {crate::host::TrapHandler, hbvm::vm::Vm};

pub struct Scheduler<'a> {
    data: VecDeque<Vm<'a, TrapHandler>>,
    pub tick_callback: Option<fn() -> u64>,
    pub last_timer_count: u64,
    pub tick_limit: u64,
}

// NOTE: This is a very simple schduler and it sucks and should be replaced with a better one
// Written By Yours Truly: Munir



impl Scheduler<'_> {
    pub fn new() -> Self {
        Self {
            data: VecDeque::new(),
            tick_callback: None,
            last_timer_count: 0,
            tick_limit: 64,
        }
    }
    pub fn new_process(&mut self, program: Vec<u8>) {
        let prog = program.clone();
        let prog_arc = Rc::new(prog);

        let binding = Rc::try_unwrap(prog_arc).ok().unwrap();

        #[allow(clippy::redundant_else)]
        if let Err(e) = validate(&program.as_slice()) {
            log::error!("Program validation error: {e:?}");
        } else {
            log::info!("valid program");
            unsafe {
                let slice = slice::from_raw_parts(binding.as_ptr(), binding.len());
                let mut vm = Vm::new_unchecked(&*slice, TrapHandler);
                vm.memory.insert_test_page();
                self.data.push_front(vm);
            }
        }
    }

    pub fn scheduler_run(&mut self) -> Option<u32> {
        loop {
            let mut prog = self.data.pop_front().unwrap();
            prog.run().unwrap();
            self.data.push_back(prog);
            if self.tick_callback.is_some() {
                let ret = self.tick_callback.unwrap()();
                if (ret - self.last_timer_count) >= self.tick_limit {
                    
                    return Some(0);

                }
            }
            break;
        }
        Some(1)
    }
}