#pragma once

#include <cstdint>
#include <mutex>

#include "adapters/il2cpp/Il2CppObjectInstance.h"
#include "external/il2cpp/il2cpp-api-types.h"

namespace ta::adapters::eft::runtime
{
    struct EftGameContextSnapshot final
    {
        const Il2CppClass* game_world_class = nullptr;
        ta::adapters::il2cpp::Il2CppObjectInstance game_world_instance{nullptr};
        ta::adapters::il2cpp::Il2CppObjectInstance main_player{nullptr};
        std::uint64_t revision = 0;

        [[nodiscard]] bool has_world() const noexcept
        {
            return game_world_class != nullptr && game_world_instance.get_instance() != nullptr;
        }

        [[nodiscard]] bool has_player() const noexcept
        {
            return main_player.get_instance() != nullptr;
        }
    };

    class EftGameContext final
    {
    public:
        void publish(const Il2CppClass* game_world_class,
                     ta::adapters::il2cpp::Il2CppObjectInstance game_world_instance,
                     ta::adapters::il2cpp::Il2CppObjectInstance main_player) noexcept
        {
            std::lock_guard lock(mutex_);
            snapshot_.game_world_class = game_world_class;
            snapshot_.game_world_instance = game_world_instance;
            snapshot_.main_player = main_player;
            ++snapshot_.revision;
        }

        [[nodiscard]] EftGameContextSnapshot snapshot() const noexcept
        {
            std::lock_guard lock(mutex_);
            return snapshot_;
        }

        void clear() noexcept
        {
            std::lock_guard lock(mutex_);
            snapshot_.game_world_class = nullptr;
            snapshot_.game_world_instance = ta::adapters::il2cpp::Il2CppObjectInstance(nullptr);
            snapshot_.main_player = ta::adapters::il2cpp::Il2CppObjectInstance(nullptr);
            ++snapshot_.revision;
        }

    private:
        mutable std::mutex mutex_;
        EftGameContextSnapshot snapshot_{};
    };
}
