#pragma once

#include <concepts>
#include <cstdint>
#include <type_traits>

namespace renderive {

enum class Event_Type : std::uint8_t {
    Resize,
    Show,
    Hide,
    Leave,
    Pointer_Move,
    Pointer_Press,
    Pointer_Release,
    Wheel,
    Key_Press,
    Key_Release
};

struct Event {
    explicit Event(Event_Type value) : type(value) {}
    virtual ~Event() = default;

    void accept() const noexcept { accepted_ = true; }
    [[nodiscard]] bool is_accepted() const noexcept { return accepted_; }

    Event_Type type;

private:
    mutable bool accepted_{};
};

template <class T>
concept Event_Object = std::derived_from<std::remove_cvref_t<T>, Event>;

template <class T>
concept Event_Point = std::default_initializable<T> && requires(T value) {
    value.x;
    value.y;
};

template <class T>
concept Event_Size = std::default_initializable<T> && requires(T value) {
    value.width;
    value.height;
};

enum class Mouse_Button : std::uint8_t { None, Left, Right, Middle };
using Mouse_Button_Mask = std::uint8_t;

enum class Keyboard_Modifier : std::uint8_t {
    None = 0,
    Ctrl = 1 << 0,
    Shift = 1 << 1,
    Alt = 1 << 2,
    Meta = 1 << 3
};

constexpr Keyboard_Modifier operator|(Keyboard_Modifier left,
                                      Keyboard_Modifier right) noexcept {
    return static_cast<Keyboard_Modifier>(static_cast<std::uint8_t>(left) |
                                          static_cast<std::uint8_t>(right));
}

template <Event_Point Point>
struct Basic_Pointer_Event : Event {
    explicit Basic_Pointer_Event(Event_Type value = Event_Type::Pointer_Move)
        : Event(value) {}

    Point position;
    Point global_position;
    Mouse_Button button = Mouse_Button::None;
    Mouse_Button_Mask buttons{};
    Keyboard_Modifier modifiers = Keyboard_Modifier::None;
};

template <Event_Point Point>
struct Basic_Wheel_Event : Basic_Pointer_Event<Point> {
    Basic_Wheel_Event() : Basic_Pointer_Event<Point>(Event_Type::Wheel) {}

    double angle_delta_x{};
    double angle_delta_y{};
    double pixel_delta_x{};
    double pixel_delta_y{};
};

template <Event_Size Size>
struct Basic_Resize_Event : Event {
    Basic_Resize_Event() : Event(Event_Type::Resize) {}

    Size old_size;
    Size new_size;
};

enum class Key : std::uint16_t {
    Unknown,
    Escape,
    Enter,
    Space,
    Delete,
    Backspace,
    Left,
    Right,
    Up,
    Down
};

struct Key_Event : Event {
    explicit Key_Event(Event_Type value) : Event(value) {}

    Key key = Key::Unknown;
    std::uint32_t native_key{};
    Keyboard_Modifier modifiers = Keyboard_Modifier::None;
    bool auto_repeat{};
};

} // namespace renderive
