//! Font management and data structures

use core::mem::size_of;

use bytemuck::{Pod, Zeroable};
use yggdrasil_abi::error::Error;

use crate::AlignedTo;

static CONSOLE_FONT: &AlignedTo<u32, [u8]> = &AlignedTo {
    align: [],
    bytes: *include_bytes!("font.psfu"),
};

#[repr(C)]
#[derive(Pod, Zeroable, Clone, Copy)]
struct PsfHeader {
    magic: u32,
    version: u32,
    header_size: u32,
    flags: u32,
    num_glyph: u32,
    bytes_per_glyph: u32,
    height: u32,
    width: u32,
}

/// Represents a PSF-format font object
#[derive(Clone, Copy)]
pub struct PcScreenFont<'a> {
    header: &'a PsfHeader,
    glyph_data: &'a [u8],
}

impl Default for PcScreenFont<'static> {
    fn default() -> Self {
        Self::from_bytes(&CONSOLE_FONT.bytes).unwrap()
    }
}

impl<'a> PcScreenFont<'a> {
    /// Constructs an instance of [PcScreenFont] from its byte representation
    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
        let header: &PsfHeader = bytemuck::from_bytes(&bytes[..size_of::<PsfHeader>()]);
        let glyph_data = &bytes[header.header_size as usize..];

        Ok(Self { header, glyph_data })
    }

    /// Returns the character width of the font
    #[inline]
    pub const fn width(&self) -> u32 {
        self.header.width
    }

    /// Returns the character height of the font
    #[inline]
    pub const fn height(&self) -> u32 {
        self.header.height
    }

    /// Returns the count of glyphs present in the font
    #[allow(clippy::len_without_is_empty)]
    #[inline]
    pub const fn len(&self) -> u32 {
        self.header.num_glyph
    }

    /// Returns the data slice of a single glyph within the font
    #[inline]
    pub fn raw_glyph_data(&self, index: u32) -> &[u8] {
        &self.glyph_data[(index * self.header.bytes_per_glyph) as usize..]
    }
}
