#pragma once

#include <array>
#include <cstddef>
#include <string_view>

namespace ta::foundation::input
{
    inline constexpr std::array<const char*, 166> key_names = {
        "Unknown", "LBUTTON", "RBUTTON", "CANCEL", "MBUTTON", "XBUTTON1", "XBUTTON2", "Unknown",
        "BACK", "TAB", "Unknown", "Unknown", "CLEAR", "RETURN", "Unknown", "Unknown",
        "SHIFT", "CONTROL", "MENU", "PAUSE", "CAPITAL", "KANA", "Unknown", "JUNJA",
        "FINAL", "KANJI", "Unknown", "ESCAPE", "CONVERT", "NONCONVERT", "ACCEPT", "MODECHANGE",
        "SPACE", "PRIOR", "NEXT", "END", "HOME", "LEFT", "UP", "RIGHT",
        "DOWN", "SELECT", "PRINT", "EXECUTE", "SNAPSHOT", "INSERT", "DELETE", "HELP",
        "0", "1", "2", "3", "4", "5", "6", "7",
        "8", "9", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown",
        "Unknown", "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", "LWIN", "RWIN", "APPS", "Unknown", "SLEEP",
        "NUMPAD0", "NUMPAD1", "NUMPAD2", "NUMPAD3", "NUMPAD4", "NUMPAD5", "NUMPAD6", "NUMPAD7",
        "NUMPAD8", "NUMPAD9", "MULTIPLY", "ADD", "SEPARATOR", "SUBTRACT", "DECIMAL", "DIVIDE",
        "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
        "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16",
        "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24",
        "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown",
        "NUMLOCK", "SCROLL", "OEM_NEC_EQUAL", "OEM_FJ_MASSHOU", "OEM_FJ_TOUROKU", "OEM_FJ_LOYA", "OEM_FJ_ROYA", "Unknown",
        "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown",
        "LSHIFT", "RSHIFT", "LCONTROL", "RCONTROL", "LMENU", "RMENU"
    };

    [[nodiscard]] constexpr bool is_unknown_name(const char* name) noexcept
    {
        return name == nullptr || std::string_view(name) == "Unknown";
    }

    [[nodiscard]] constexpr bool is_valid_key_index(const int value) noexcept
    {
        return value >= 0 && value < static_cast<int>(key_names.size()) &&
            !is_unknown_name(key_names[static_cast<std::size_t>(value)]);
    }

    [[nodiscard]] inline const char* display_name(const int value, const bool allow_none = true) noexcept
    {
        if (allow_none && value == 0)
            return "NONE";
        if (!is_valid_key_index(value))
            return "UNBOUND";
        return key_names[static_cast<std::size_t>(value)];
    }
}
