//! Events fired and types used during keyboard input.

use winit::{
    event::{ElementState, KeyEvent},
    keyboard::{KeyCode, NativeKeyCode, PhysicalKey},
};

/// Fired when a key is pressed.
#[derive(Clone, Debug, PartialEq)]
pub struct KeyPress {
    pub key: Key,
    pub state: KeyState,
}

impl KeyPress {
    /// Initializes [`self`].
    #[inline]
    pub const fn new(key: Key, state: KeyState) -> Self {
        Self { key, state }
    }
}

impl TryFrom<&KeyEvent> for KeyPress {
    type Error = KeyPressConversionError;

    fn try_from(other: &KeyEvent) -> Result<Self, Self::Error> {
        match other.physical_key {
            PhysicalKey::Code(code) => {
                let key = Into::into(code);
                let state = Into::into(other.state);

                let this = KeyPress::new(key, state);

                Ok(this)
            },
            PhysicalKey::Unidentified(code) => {
                let err = KeyPressConversionError::NativeScanCode(code);

                Err(err)
            },
        }
    }
}

/// Errors which can occur during [`KeyEvent`] -> [`KeyPress`] conversion.
pub enum KeyPressConversionError {
    NativeScanCode(NativeKeyCode),
}

/// What state a [`KeyPress`] is under.
#[derive(Clone, Debug, PartialEq)]
pub enum KeyState {
    Pressed,
    Released,
}

impl KeyState {
    /// Whether [`self`] is [`KeyState::Pressed`] or not.
    pub fn is_pressed(&self) -> bool {
        self == &KeyState::Pressed
    }
}

impl From<ElementState> for KeyState {
    fn from(other: ElementState) -> Self {
        match other {
            ElementState::Pressed => KeyState::Pressed,
            ElementState::Released => KeyState::Released,
        }
    }
}

/// Fired when a key is pressed.
///
/// List of keys isn't final.
#[derive(Clone, Default, Debug, PartialEq)]
pub enum Key {
    #[default]
    Unknown,

    Escape,
    Tab,
    ShiftLeft,
    ShiftRight,
    ControlLeft,
    ControlRight,
    Space,
    Q,
    W,
    E,
    R,
    T,
    Y,
    U,
    I,
    O,
    P,
    A,
    S,
    D,
    F,
    G,
    H,
    J,
    K,
    L,
    Z,
    X,
    C,
    V,
    B,
    N,
    M,
}

impl From<KeyCode> for Key {
    fn from(code: KeyCode) -> Self {
        match code {
            KeyCode::Escape => Self::Escape,
            KeyCode::Tab => Self::Tab,
            KeyCode::ShiftLeft => Self::ShiftLeft,
            KeyCode::ShiftRight => Self::ShiftRight,
            KeyCode::ControlLeft => Self::ControlLeft,
            KeyCode::ControlRight => Self::ControlRight,
            KeyCode::Space => Self::Space,
            KeyCode::KeyQ => Key::Q,
            KeyCode::KeyW => Key::W,
            KeyCode::KeyE => Key::E,
            KeyCode::KeyR => Key::R,
            KeyCode::KeyT => Key::T,
            KeyCode::KeyY => Key::Y,
            KeyCode::KeyU => Key::U,
            KeyCode::KeyI => Key::I,
            KeyCode::KeyO => Key::O,
            KeyCode::KeyP => Key::P,
            KeyCode::KeyA => Key::A,
            KeyCode::KeyS => Key::S,
            KeyCode::KeyD => Key::D,
            KeyCode::KeyF => Key::F,
            KeyCode::KeyG => Key::G,
            KeyCode::KeyH => Key::H,
            KeyCode::KeyJ => Key::J,
            KeyCode::KeyK => Key::K,
            KeyCode::KeyL => Key::L,
            KeyCode::KeyZ => Key::Z,
            KeyCode::KeyX => Key::X,
            KeyCode::KeyC => Key::C,
            KeyCode::KeyV => Key::V,
            KeyCode::KeyB => Key::B,
            KeyCode::KeyN => Key::N,
            KeyCode::KeyM => Key::M,
            _ => Key::Unknown,
        }
    }
}
