use serde::{Deserialize, Serialize};
use strum::{EnumCount, FromRepr, VariantArray};
use winit::keyboard::KeyCode as Winit;

/// A keyboard key.
#[derive(
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    FromRepr,
    EnumCount,
    VariantArray,
)]
pub enum Key {
    Backquote = 0,
    Backslash,
    BracketLeft,
    BracketRight,
    Comma,
    Digit0,
    Digit1,
    Digit2,
    Digit3,
    Digit4,
    Digit5,
    Digit6,
    Digit7,
    Digit8,
    Digit9,
    Equal,
    IntlBackslash,
    IntlRo,
    IntlYen,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,
    Minus,
    Period,
    Quote,
    Semicolon,
    Slash,
    AltLeft,
    AltRight,
    Backspace,
    CapsLock,
    ContextMenu,
    ControlLeft,
    ControlRight,
    Enter,
    SuperLeft,
    SuperRight,
    ShiftLeft,
    ShiftRight,
    Space,
    Tab,
    Convert,
    KanaMode,
    Lang1,
    Lang2,
    Lang3,
    Lang4,
    Lang5,
    NonConvert,
    Delete,
    End,
    Help,
    Home,
    Insert,
    PageDown,
    PageUp,
    ArrowDown,
    ArrowLeft,
    ArrowRight,
    ArrowUp,
    NumLock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    NumpadAdd,
    NumpadBackspace,
    NumpadClear,
    NumpadClearEntry,
    NumpadComma,
    NumpadDecimal,
    NumpadDivide,
    NumpadEnter,
    NumpadEqual,
    NumpadHash,
    NumpadMemoryAdd,
    NumpadMemoryClear,
    NumpadMemoryRecall,
    NumpadMemoryStore,
    NumpadMemorySubtract,
    NumpadMultiply,
    NumpadParenLeft,
    NumpadParenRight,
    NumpadStar,
    NumpadSubtract,
    Escape,
    Fn,
    FnLock,
    PrintScreen,
    ScrollLock,
    Pause,
    BrowserBack,
    BrowserFavorites,
    BrowserForward,
    BrowserHome,
    BrowserRefresh,
    BrowserSearch,
    BrowserStop,
    Eject,
    LaunchApp1,
    LaunchApp2,
    LaunchMail,
    MediaPlayPause,
    MediaSelect,
    MediaStop,
    MediaTrackNext,
    MediaTrackPrevious,
    Power,
    Sleep,
    AudioVolumeDown,
    AudioVolumeMute,
    AudioVolumeUp,
    WakeUp,
    Meta,
    Hyper,
    Turbo,
    Abort,
    Resume,
    Suspend,
    Again,
    Copy,
    Cut,
    Find,
    Open,
    Paste,
    Props,
    Select,
    Undo,
    Hiragana,
    Katakana,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    F16,
    F17,
    F18,
    F19,
    F20,
    F21,
    F22,
    F23,
    F24,
    F25,
    F26,
    F27,
    F28,
    F29,
    F30,
    F31,
    F32,
    F33,
    F34,
    F35,
}

impl TryFrom<Winit> for Key {
    type Error = Winit;

    #[inline]
    fn try_from(value: Winit) -> Result<Self, Self::Error> {
        Ok(match value {
            Winit::Backquote => Self::Backquote,
            Winit::Backslash => Self::Backslash,
            Winit::BracketLeft => Self::BracketLeft,
            Winit::BracketRight => Self::BracketRight,
            Winit::Comma => Self::Comma,
            Winit::Digit0 => Self::Digit0,
            Winit::Digit1 => Self::Digit1,
            Winit::Digit2 => Self::Digit2,
            Winit::Digit3 => Self::Digit3,
            Winit::Digit4 => Self::Digit4,
            Winit::Digit5 => Self::Digit5,
            Winit::Digit6 => Self::Digit6,
            Winit::Digit7 => Self::Digit7,
            Winit::Digit8 => Self::Digit8,
            Winit::Digit9 => Self::Digit9,
            Winit::Equal => Self::Equal,
            Winit::IntlBackslash => Self::IntlBackslash,
            Winit::IntlRo => Self::IntlRo,
            Winit::IntlYen => Self::IntlYen,
            Winit::KeyA => Self::A,
            Winit::KeyB => Self::B,
            Winit::KeyC => Self::C,
            Winit::KeyD => Self::D,
            Winit::KeyE => Self::E,
            Winit::KeyF => Self::F,
            Winit::KeyG => Self::G,
            Winit::KeyH => Self::H,
            Winit::KeyI => Self::I,
            Winit::KeyJ => Self::J,
            Winit::KeyK => Self::K,
            Winit::KeyL => Self::L,
            Winit::KeyM => Self::M,
            Winit::KeyN => Self::N,
            Winit::KeyO => Self::O,
            Winit::KeyP => Self::P,
            Winit::KeyQ => Self::Q,
            Winit::KeyR => Self::R,
            Winit::KeyS => Self::S,
            Winit::KeyT => Self::T,
            Winit::KeyU => Self::U,
            Winit::KeyV => Self::V,
            Winit::KeyW => Self::W,
            Winit::KeyX => Self::X,
            Winit::KeyY => Self::Y,
            Winit::KeyZ => Self::Z,
            Winit::Minus => Self::Minus,
            Winit::Period => Self::Period,
            Winit::Quote => Self::Quote,
            Winit::Semicolon => Self::Semicolon,
            Winit::Slash => Self::Slash,
            Winit::AltLeft => Self::AltLeft,
            Winit::AltRight => Self::AltRight,
            Winit::Backspace => Self::Backspace,
            Winit::CapsLock => Self::CapsLock,
            Winit::ContextMenu => Self::ContextMenu,
            Winit::ControlLeft => Self::ControlLeft,
            Winit::ControlRight => Self::ControlRight,
            Winit::Enter => Self::Enter,
            Winit::SuperLeft => Self::SuperLeft,
            Winit::SuperRight => Self::SuperRight,
            Winit::ShiftLeft => Self::ShiftLeft,
            Winit::ShiftRight => Self::ShiftRight,
            Winit::Space => Self::Space,
            Winit::Tab => Self::Tab,
            Winit::Convert => Self::Convert,
            Winit::KanaMode => Self::KanaMode,
            Winit::Lang1 => Self::Lang1,
            Winit::Lang2 => Self::Lang2,
            Winit::Lang3 => Self::Lang3,
            Winit::Lang4 => Self::Lang4,
            Winit::Lang5 => Self::Lang5,
            Winit::NonConvert => Self::NonConvert,
            Winit::Delete => Self::Delete,
            Winit::End => Self::End,
            Winit::Help => Self::Help,
            Winit::Home => Self::Home,
            Winit::Insert => Self::Insert,
            Winit::PageDown => Self::PageDown,
            Winit::PageUp => Self::PageUp,
            Winit::ArrowDown => Self::ArrowDown,
            Winit::ArrowLeft => Self::ArrowLeft,
            Winit::ArrowRight => Self::ArrowRight,
            Winit::ArrowUp => Self::ArrowUp,
            Winit::NumLock => Self::NumLock,
            Winit::Numpad0 => Self::Numpad0,
            Winit::Numpad1 => Self::Numpad1,
            Winit::Numpad2 => Self::Numpad2,
            Winit::Numpad3 => Self::Numpad3,
            Winit::Numpad4 => Self::Numpad4,
            Winit::Numpad5 => Self::Numpad5,
            Winit::Numpad6 => Self::Numpad6,
            Winit::Numpad7 => Self::Numpad7,
            Winit::Numpad8 => Self::Numpad8,
            Winit::Numpad9 => Self::Numpad9,
            Winit::NumpadAdd => Self::NumpadAdd,
            Winit::NumpadBackspace => Self::NumpadBackspace,
            Winit::NumpadClear => Self::NumpadClear,
            Winit::NumpadClearEntry => Self::NumpadClearEntry,
            Winit::NumpadComma => Self::NumpadComma,
            Winit::NumpadDecimal => Self::NumpadDecimal,
            Winit::NumpadDivide => Self::NumpadDivide,
            Winit::NumpadEnter => Self::NumpadEnter,
            Winit::NumpadEqual => Self::NumpadEqual,
            Winit::NumpadHash => Self::NumpadHash,
            Winit::NumpadMemoryAdd => Self::NumpadMemoryAdd,
            Winit::NumpadMemoryClear => Self::NumpadMemoryClear,
            Winit::NumpadMemoryRecall => Self::NumpadMemoryRecall,
            Winit::NumpadMemoryStore => Self::NumpadMemoryStore,
            Winit::NumpadMemorySubtract => Self::NumpadMemorySubtract,
            Winit::NumpadMultiply => Self::NumpadMultiply,
            Winit::NumpadParenLeft => Self::NumpadParenLeft,
            Winit::NumpadParenRight => Self::NumpadParenRight,
            Winit::NumpadStar => Self::NumpadStar,
            Winit::NumpadSubtract => Self::NumpadSubtract,
            Winit::Escape => Self::Escape,
            Winit::Fn => Self::Fn,
            Winit::FnLock => Self::FnLock,
            Winit::PrintScreen => Self::PrintScreen,
            Winit::ScrollLock => Self::ScrollLock,
            Winit::Pause => Self::Pause,
            Winit::BrowserBack => Self::BrowserBack,
            Winit::BrowserFavorites => Self::BrowserFavorites,
            Winit::BrowserForward => Self::BrowserForward,
            Winit::BrowserHome => Self::BrowserHome,
            Winit::BrowserRefresh => Self::BrowserRefresh,
            Winit::BrowserSearch => Self::BrowserSearch,
            Winit::BrowserStop => Self::BrowserStop,
            Winit::Eject => Self::Eject,
            Winit::LaunchApp1 => Self::LaunchApp1,
            Winit::LaunchApp2 => Self::LaunchApp2,
            Winit::LaunchMail => Self::LaunchMail,
            Winit::MediaPlayPause => Self::MediaPlayPause,
            Winit::MediaSelect => Self::MediaSelect,
            Winit::MediaStop => Self::MediaStop,
            Winit::MediaTrackNext => Self::MediaTrackNext,
            Winit::MediaTrackPrevious => Self::MediaTrackPrevious,
            Winit::Power => Self::Power,
            Winit::Sleep => Self::Sleep,
            Winit::AudioVolumeDown => Self::AudioVolumeDown,
            Winit::AudioVolumeMute => Self::AudioVolumeMute,
            Winit::AudioVolumeUp => Self::AudioVolumeUp,
            Winit::WakeUp => Self::WakeUp,
            Winit::Meta => Self::Meta,
            Winit::Hyper => Self::Hyper,
            Winit::Turbo => Self::Turbo,
            Winit::Abort => Self::Abort,
            Winit::Resume => Self::Resume,
            Winit::Suspend => Self::Suspend,
            Winit::Again => Self::Again,
            Winit::Copy => Self::Copy,
            Winit::Cut => Self::Cut,
            Winit::Find => Self::Find,
            Winit::Open => Self::Open,
            Winit::Paste => Self::Paste,
            Winit::Props => Self::Props,
            Winit::Select => Self::Select,
            Winit::Undo => Self::Undo,
            Winit::Hiragana => Self::Hiragana,
            Winit::Katakana => Self::Katakana,
            Winit::F1 => Self::F1,
            Winit::F2 => Self::F2,
            Winit::F3 => Self::F3,
            Winit::F4 => Self::F4,
            Winit::F5 => Self::F5,
            Winit::F6 => Self::F6,
            Winit::F7 => Self::F7,
            Winit::F8 => Self::F8,
            Winit::F9 => Self::F9,
            Winit::F10 => Self::F10,
            Winit::F11 => Self::F11,
            Winit::F12 => Self::F12,
            Winit::F13 => Self::F13,
            Winit::F14 => Self::F14,
            Winit::F15 => Self::F15,
            Winit::F16 => Self::F16,
            Winit::F17 => Self::F17,
            Winit::F18 => Self::F18,
            Winit::F19 => Self::F19,
            Winit::F20 => Self::F20,
            Winit::F21 => Self::F21,
            Winit::F22 => Self::F22,
            Winit::F23 => Self::F23,
            Winit::F24 => Self::F24,
            Winit::F25 => Self::F25,
            Winit::F26 => Self::F26,
            Winit::F27 => Self::F27,
            Winit::F28 => Self::F28,
            Winit::F29 => Self::F29,
            Winit::F30 => Self::F30,
            Winit::F31 => Self::F31,
            Winit::F32 => Self::F32,
            Winit::F33 => Self::F33,
            Winit::F34 => Self::F34,
            Winit::F35 => Self::F35,
            key => return Err(key),
        })
    }
}
