#pragma once

#include <cstddef>
#include <cstdint>
#include <string>
#include <unordered_set>

#include "adapters/il2cpp/Il2CppObjectInstance.h"
#include "adapters/eft/common/EftMongoId.h"
#include "adapters/unity/bindings/UnityTypes.h"
#include "adapters/il2cpp/Il2CppCollections.h"
#include "adapters/unity/bindings/UnityApi.h"
#include "features/items/contracts/WishlistSnapshot.h"

namespace ta::adapters::eft::items
{
class WishlistReader final
{
public:
    bool refresh(ta::adapters::il2cpp::Il2CppObjectInstance& main_player);
    const ta::features::items::contracts::WishlistSnapshot& current() const;
    void clear();

private:
    static constexpr int max_dictionary_count = 20000;
    static constexpr std::size_t expected_item_count = 256;

    struct MethodCache
    {
        Il2CppClass* klass = nullptr;
        const MethodInfo* method = nullptr;
        bool resolved = false;
    };

    struct FieldCache
    {
        Il2CppClass* klass = nullptr;
        std::ptrdiff_t offset = -1;
        bool resolved = false;
    };

    ta::features::items::contracts::WishlistSnapshot current_{};
    MethodCache profile_getter_cache_{};
    FieldCache wishlist_manager_field_cache_{};
    FieldCache user_items_field_cache_{};
    FieldCache wishlist_items_field_cache_{};

    static std::string to_string(const ta::adapters::eft::common::EftMongoId& id);
    static Il2CppObject* read_object_field(Il2CppObject* object, std::ptrdiff_t offset);
    static ta::adapters::unity::dict<ta::adapters::eft::common::EftMongoId, int>* as_valid_dictionary(Il2CppObject* dictionary);
    static void add_keys(Il2CppObject* dictionary, std::unordered_set<std::string>& target);

    const MethodInfo* resolve_cached_method(Il2CppClass* klass, const char* name, int arg_count, MethodCache& cache);
    std::ptrdiff_t resolve_cached_field_offset(Il2CppClass* klass, const char* name, FieldCache& cache);
    Il2CppObject* get_profile(ta::adapters::il2cpp::Il2CppObjectInstance& main_player);
};
}
