/// Describes a key pressed/released on a keyboard device
// Missing docs: self-explanatory names
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub enum KeyboardKey {
    Char(u8),
    F(u8),
    Enter,
    LShift,
    RShift,
    LControl,
    RControl,
    PageUp,
    PageDown,
    LAlt,
    RAlt,
    CapsLock,
    Escape,
    Backspace,
    Tab,
    Up,
    Down,
    Left,
    Right,
    Home,
    End,
    Insert,
    Delete,
    Unknown,
}

/// Alternative representation for [KeyboardKey]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct KeyboardKeyCode(u16);

/// Descibes a single event produced by a keyboard device
// Missing docs: self-explanatory names
#[allow(missing_docs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug)]
pub enum KeyboardKeyEvent {
    Pressed(KeyboardKey),
    Released(KeyboardKey),
}

impl KeyboardKey {
    /// Converts [KeyboardKey] to its related [KeyboardKeyCode]
    pub const fn code(self) -> KeyboardKeyCode {
        // KeyCode:
        // 0x00..0x80: chars
        // 0x80..0x8C: f1..f12
        // 0x90: Enter
        // 0x91: LShift
        // 0x92: RShift
        // 0x93: LControl
        // 0x94: RControl
        // 0x95: LAlt
        // 0x96: RAlt
        // 0x97: CapsLock
        // 0x98: Escape
        // 0x99: Backspace
        // 0x9A: Tab
        // 0xA0: PageUp
        // 0xA1: PageDown
        // 0xA2: Up
        // 0xA3: Down
        // 0xA4: Left
        // 0xA5: Right
        // 0xA6: Home
        // 0xA7: End
        // 0xA8: Insert
        // 0xA9: Delete
        // 0xFF: Unknown
        KeyboardKeyCode(match self {
            Self::Char(b) => b as u16,
            Self::F(b) => (b - 1) as u16 | 0x80,
            Self::Enter => 0x90,
            Self::LShift => 0x91,
            Self::RShift => 0x92,
            Self::LControl => 0x93,
            Self::RControl => 0x94,
            Self::LAlt => 0x95,
            Self::RAlt => 0x96,
            Self::CapsLock => 0x97,
            Self::Escape => 0x98,
            Self::Backspace => 0x99,
            Self::Tab => 0x9A,
            Self::PageUp => 0xA0,
            Self::PageDown => 0xA1,
            Self::Up => 0xA2,
            Self::Down => 0xA3,
            Self::Left => 0xA4,
            Self::Right => 0xA5,
            Self::Home => 0xA6,
            Self::End => 0xA7,
            Self::Insert => 0xA8,
            Self::Delete => 0xA9,
            Self::Unknown => 0xFF,
        })
    }

    /// Converts a [KeyboardKeyCode] to the [KeyboardKey] it represents. Unknown keycodes are
    /// replaced with [KeyboardKey::Unknown].
    pub const fn from_code(KeyboardKeyCode(code): KeyboardKeyCode) -> Self {
        if code < 0x80 {
            Self::Char(code as u8)
        } else if code < 0x8C {
            Self::F(code as u8 - 0x79)
        } else {
            match code {
                0x90 => Self::Enter,
                0x91 => Self::LShift,
                0x92 => Self::RShift,
                0x93 => Self::LControl,
                0x94 => Self::RControl,
                0x95 => Self::LAlt,
                0x96 => Self::RAlt,
                0x97 => Self::CapsLock,
                0x98 => Self::Escape,
                0x99 => Self::Backspace,
                0x9A => Self::Tab,
                0xA0 => Self::PageUp,
                0xA1 => Self::PageDown,
                0xA2 => Self::Up,
                0xA3 => Self::Down,
                0xA4 => Self::Left,
                0xA5 => Self::Right,
                0xA6 => Self::Home,
                0xA7 => Self::End,
                0xA8 => Self::Insert,
                0xA9 => Self::Delete,
                _ => Self::Unknown,
            }
        }
    }
}

impl KeyboardKeyEvent {
    /// Splits the event into its state and key
    #[inline]
    pub const fn split(self) -> (KeyboardKey, bool) {
        match self {
            Self::Pressed(k) => (k, true),
            Self::Released(k) => (k, false),
        }
    }

    /// Converts a [KeyEvent] to its byte representation
    #[inline]
    pub const fn as_bytes(self) -> [u8; 4] {
        let (key, pressed) = self.split();
        let code = key.code().0.to_ne_bytes();

        [code[0], code[1], pressed as u8, 0]
        // (((pressed as u32) << 16) | (key.code().0 as u32)).to_ne_bytes()
    }

    /// Obtains a [KeyEvent] from its byte representation
    pub const fn from_bytes(bytes: [u8; 4]) -> Self {
        let pressed = bytes[2] != 0;
        let code = KeyboardKeyCode(u16::from_ne_bytes([bytes[0], bytes[1]]));
        let key = KeyboardKey::from_code(code);

        if pressed {
            Self::Pressed(key)
        } else {
            Self::Released(key)
        }
    }
}
