/*
 * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/OwnPtr.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibGfx/Point.h>
#include <LibIPC/Forward.h>
#include <LibWeb/Export.h>
#include <LibWeb/HTML/SelectedFile.h>
#include <LibWeb/PixelUnits.h>
#include <LibWeb/UIEvents/KeyCode.h>
#include <LibWeb/UIEvents/MouseButton.h>

namespace Web {

struct BrowserInputData {
    virtual ~BrowserInputData() = default;
};

struct WEB_API KeyEvent {
    enum class Type : u8 {
        KeyDown,
        KeyUp,
    };

    KeyEvent clone_without_browser_data() const;

    Type type;
    UIEvents::KeyCode key { UIEvents::KeyCode::Key_Invalid };
    UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
    u32 code_point { 0 };
    bool repeat { false };

    OwnPtr<BrowserInputData> browser_data;
};

struct WEB_API MouseEvent {
    enum class Type : u8 {
        MouseDown,
        MouseUp,
        MouseMove,
        MouseLeave,
        MouseWheel,
    };

    MouseEvent clone_without_browser_data() const;

    Type type;
    Web::DevicePixelPoint position;
    Web::DevicePixelPoint screen_position;
    UIEvents::MouseButton button { UIEvents::MouseButton::None };
    UIEvents::MouseButton buttons { UIEvents::MouseButton::None };
    UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
    double wheel_delta_x { 0 };
    double wheel_delta_y { 0 };
    int click_count { 0 };

    OwnPtr<BrowserInputData> browser_data;
    bool async_scroll_performed_default_action { false };
};

struct WEB_API DragEvent {
    enum class Type : u8 {
        DragStart,
        DragMove,
        DragEnd,
        Drop,
    };

    DragEvent clone_without_browser_data() const;

    Type type;
    Web::DevicePixelPoint position;
    Web::DevicePixelPoint screen_position;
    UIEvents::MouseButton button { UIEvents::MouseButton::None };
    UIEvents::MouseButton buttons { UIEvents::MouseButton::None };
    UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
    Vector<HTML::SelectedFile> files;

    OwnPtr<BrowserInputData> browser_data;
};

struct WEB_API PinchEvent {
    Web::DevicePixelPoint position;
    double scale_delta;
};

using InputEvent = Variant<KeyEvent, MouseEvent, DragEvent, PinchEvent>;

struct QueuedInputEvent {
    u64 page_id { 0 };
    InputEvent event;
    size_t coalesced_event_count { 0 };
};

}

namespace IPC {

template<>
WEB_API ErrorOr<void> encode(Encoder&, Web::KeyEvent const&);

template<>
WEB_API ErrorOr<Web::KeyEvent> decode(Decoder&);

template<>
WEB_API ErrorOr<void> encode(Encoder&, Web::MouseEvent const&);

template<>
WEB_API ErrorOr<Web::MouseEvent> decode(Decoder&);

template<>
WEB_API ErrorOr<void> encode(Encoder&, Web::DragEvent const&);

template<>
WEB_API ErrorOr<Web::DragEvent> decode(Decoder&);

template<>
WEB_API ErrorOr<void> encode(Encoder&, Web::PinchEvent const&);

template<>
WEB_API ErrorOr<Web::PinchEvent> decode(Decoder&);

}
