use {
    crate::holeybytes::{kernel_services::block_read, Vm},
    alloc::alloc::{alloc_zeroed, dealloc},
    core::alloc::Layout,
    log::{debug, info},
};

pub enum MemoryServiceError {
    InvalidMemoryFormat,
}
#[derive(Debug)]
pub enum MemoryQuotaType {
    NoQuota = 0,
    SoftQuota = 1,
    HardQuota = 2,
    KillQuota = 3,
}

fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
    let ptr = unsafe { alloc_zeroed(Layout::new::<[u8; 4096]>()) };
    info!("Block address: {:?}", ptr);
    vm.registers[1] = hbvm::value::Value(ptr as u64);
    vm.registers[2] = hbvm::value::Value(4096);
    Ok(())
}

pub fn memory_msg_handler(
    vm: &mut Vm,
    mem_addr: u64,
    length: usize,
) -> Result<(), MemoryServiceError> {
    let msg_vec = block_read(mem_addr, length);
    let msg_type = msg_vec[0];
    match msg_type {
        0 => {
            let page_count = msg_vec[1];
            let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
            let mptr: u64 = u64::from_le_bytes(mptr_raw);

            log::debug!("Allocating {} pages @ {:x}", page_count, mptr);

            let ptr = unsafe {
                alloc_zeroed(Layout::from_size_align_unchecked(
                    page_count as usize * 4096,
                    1,
                ))
            };

            vm.registers[1] = hbvm::value::Value(ptr as u64);
            log::debug!("Kernel ptr: {:x}", ptr as u64);
        }

        1 => {
            let page_count = msg_vec[1];

            let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
            let mptr: u64 = u64::from_le_bytes(mptr_raw);
            log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
            unsafe {
                dealloc(
                    mptr as *mut u8,
                    Layout::from_size_align_unchecked(page_count as usize * 4096, 1),
                )
            }
        }
        2 => {
            use MemoryQuotaType::*;
            let quota_type = match msg_vec[0] {
                0 => NoQuota,
                1 => SoftQuota,
                2 => HardQuota,
                3 => KillQuota,
                _ => NoQuota,
            };
            let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
            let hid: u64 = u64::from_le_bytes(hid_raw);
            let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
            let pid: u64 = u64::from_le_bytes(pid_raw);
            debug!(
                "Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
                hid, pid, quota_type
            )
        }
        3 => {
            let page_count = msg_vec[0];
            log::debug!(" {} pages", page_count);
        }

        _ => {
            log::debug!("Unknown memory service message type: {}", msg_type);
        }
    }

    Ok(())
}