#pragma once

#include "foundation/result.h"

#include <cstddef>
#include <cstdint>
#include <vector>

namespace pp::foundation {

constexpr std::size_t max_event_subscriptions = 65536;

struct Event {
    std::uint32_t type = 0;
    std::uint64_t source_id = 0;
    std::uint64_t frame_id = 0;
    std::uint64_t payload_u64 = 0;
};

using EventCallback = void (*)(const Event& event, void* user_data) noexcept;

struct EventSubscription {
    std::uint64_t id = 0;
    std::uint32_t type = 0;
    EventCallback callback = nullptr;
    void* user_data = nullptr;
};

class EventDispatcher {
public:
    explicit EventDispatcher(std::size_t max_subscriptions = max_event_subscriptions) noexcept;

    [[nodiscard]] std::size_t size() const noexcept;
    [[nodiscard]] bool empty() const noexcept;
    [[nodiscard]] std::size_t max_subscriptions() const noexcept;

    [[nodiscard]] Result<std::uint64_t> subscribe(std::uint32_t type, EventCallback callback, void* user_data);
    [[nodiscard]] Status unsubscribe(std::uint64_t subscription_id) noexcept;
    [[nodiscard]] std::size_t publish(const Event& event) const noexcept;
    void clear() noexcept;

private:
    std::size_t max_subscriptions_ = max_event_subscriptions;
    std::uint64_t next_subscription_id_ = 1;
    std::vector<EventSubscription> subscriptions_;
};

}
