use core::mem::MaybeUninit;

use alloc::vec::Vec;
use libk_mm::{
    address::{AsPhysicalAddress, PhysicalAddress},
    table::MapAttributes,
    OnDemandPage, PageBox, PageProvider, VirtualPage, L3_PAGE_SIZE,
};
use yggdrasil_abi::error::Error;

/// Shared memory VFS object
pub struct SharedMemory {
    pages: Vec<PageBox<MaybeUninit<[u8; 4096]>>>,
}

impl SharedMemory {
    /// Creates a new buffer of shared memory
    pub fn new(size: usize) -> Result<SharedMemory, Error> {
        let page_count = size.div_ceil(0x1000);

        let pages = (0..page_count)
            .map(|_| PageBox::new_uninit())
            .collect::<Result<_, _>>()?;

        Ok(Self { pages })
    }
}

impl PageProvider for SharedMemory {
    fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
        unreachable!()
    }

    fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
        let index = (offset / L3_PAGE_SIZE as u64) as usize;
        self.pages
            .get(index)
            .map(|bx| unsafe { bx.as_physical_address() })
            .ok_or(Error::InvalidMemoryOperation)
            .map(VirtualPage::Immediate)
    }

    fn release_page(
        &self,
        _offset: u64,
        _phys: PhysicalAddress,
        _dirty: bool,
    ) -> Result<(), Error> {
        Ok(())
    }

    fn clone_page(
        &self,
        _offset: u64,
        _src_phys: PhysicalAddress,
        _src_attrs: MapAttributes,
    ) -> Result<PhysicalAddress, Error> {
        todo!()
    }
}
