#pragma once

#include <cstddef>

#include "adapters/eft/bindings/EftTraders.h"
#include "adapters/il2cpp/Il2CppObjectInstance.h"
#include "adapters/il2cpp/Il2CppResolver.h"
#include "adapters/il2cpp/ManagedRuntime.h"
#include "adapters/il2cpp/Il2CppObjectAccess.h"
#include "adapters/il2cpp/Il2CppString.h"

namespace ta::adapters::eft::player::runtime
{
    class PlayerAccess
    {
    public:
        static Il2CppObject* get_profile(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            const auto getter =
                main_player.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_Profile", 0);
            return getter ? getter(main_player.get_instance()) : nullptr;
        }

        static Il2CppObject* get_active_health_controller(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            const auto getter =
                main_player.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_ActiveHealthController", 0);
            return getter ? getter(main_player.get_instance()) : nullptr;
        }

        static Il2CppObject* get_skills(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            const auto getter =
                main_player.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_Skills", 0);
            return getter ? getter(main_player.get_instance()) : nullptr;
        }

        static Il2CppObject* get_loyalty(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            const auto getter =
                main_player.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_Loyalty", 0);
            return getter ? getter(main_player.get_instance()) : nullptr;
        }

        static Il2CppObject* get_eft_stats(ta::adapters::il2cpp::Il2CppObjectInstance& profile)
        {
            const auto getter =
                profile.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_EftStats", 0);
            return getter ? getter(profile.get_instance()) : nullptr;
        }

        static Il2CppObject* get_physical(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            Il2CppObject* physical = nullptr;
            return main_player.try_get_field("Physical", physical) ? physical : nullptr;
        }

        static Il2CppObject* get_movement_context(ta::adapters::il2cpp::Il2CppObjectInstance& main_player)
        {
            const auto getter =
                main_player.get_method<Il2CppObject*(*)(Il2CppObject*)>("get_MovementContext", 0);
            return getter ? getter(main_player.get_instance()) : nullptr;
        }

        static bool get_trader_id(const int index, const char*& trader_id)
        {
            if (index < 0 || index >= static_cast<int>(ta::adapters::eft::traders::all.size()))
                return false;

            trader_id = ta::adapters::eft::traders::all[static_cast<std::size_t>(index)].id;
            return true;
        }

        static const MethodInfo* resolve_profile_try_get_trader_info(const Il2CppClass* game_world_class)
        {
            if (!game_world_class || !game_world_class->image)
                return nullptr;

            const Il2CppClass* profile_class =
                ta::adapters::il2cpp::resolve_class(game_world_class->image, "EFT", "Profile");
            if (!profile_class)
                return nullptr;

            return ta::adapters::il2cpp::ManagedRuntime::method_or_null(profile_class, "TryGetTraderInfo", 2);
        }
    };
}
