#pragma once

#include <cstdint>

#include "adapters/il2cpp/Il2CppExports.h"
#include "external/il2cpp/il2cpp-class-internals.h"
#include "external/il2cpp/il2cpp-object-internals.h"
#include "external/il2cpp/il2cpp-api-types.h"

namespace ta::adapters::il2cpp
{
    inline Il2CppClass* il2cpp_class_from_name(
        const Il2CppImage* image, const char* namespaze, const char* name)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_class_from_name) return nullptr;
        return reinterpret_cast<Il2CppClass*(*)(const Il2CppImage*, const char*, const char*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_class_from_name)(image, namespaze, name);
    }

    inline Il2CppClass* il2cpp_class_get_nested_types(
        Il2CppClass* klass, void** iter)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_class_get_nested_types) return nullptr;
        return reinterpret_cast<Il2CppClass*(*)(Il2CppClass*, void**)>(
            ta::adapters::il2cpp::exports::api().il2cpp_class_get_nested_types)(klass, iter);
    }

    inline FieldInfo* il2cpp_class_get_field_from_name(
        Il2CppClass* klass, const char* name)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_class_get_field_from_name) return nullptr;
        return reinterpret_cast<FieldInfo*(*)(Il2CppClass*, const char*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_class_get_field_from_name)(klass, name);
    }

    inline const MethodInfo* il2cpp_class_get_method_from_name(
        Il2CppClass* klass, const char* name, int args_count)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_class_get_method_from_name || !klass || !name) return nullptr;
        return reinterpret_cast<const MethodInfo*(*)(Il2CppClass*, const char*, int, void*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_class_get_method_from_name)(klass, name, args_count, nullptr);
    }

    inline const Il2CppType* il2cpp_class_get_type(Il2CppClass* klass)
    {
        if (!klass) return nullptr;
        return reinterpret_cast<const Il2CppType*>(reinterpret_cast<std::uintptr_t>(klass) + 32); // NOLINT(performance-no-int-to-ptr)
    }

    inline Il2CppDomain* il2cpp_domain_get()
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_domain_get) return nullptr;
        return reinterpret_cast<Il2CppDomain*(*)()>(
            ta::adapters::il2cpp::exports::api().il2cpp_domain_get)();
    }

    inline const Il2CppAssembly** il2cpp_domain_get_assemblies(
        const Il2CppDomain* domain, size_t* size)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_domain_get_assemblies) return nullptr;
        return reinterpret_cast<const Il2CppAssembly**(*)(const Il2CppDomain*, size_t*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_domain_get_assemblies)(domain, size);
    }

    inline void il2cpp_field_static_get_value(
        FieldInfo* field, void* value)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_field_static_get_value || !field || !value) return;
        reinterpret_cast<void(*)(FieldInfo*, void*, std::uintptr_t)>(
            ta::adapters::il2cpp::exports::api().il2cpp_field_static_get_value)(field, value, 0);
    }

    inline Il2CppString* il2cpp_string_new(const char* str)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_string_new || !str) return nullptr;
        return reinterpret_cast<Il2CppString*(*)(const char*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_string_new)(str);
    }

    inline Il2CppObject* il2cpp_type_get_object(const Il2CppType* type)
    {
        if (!ta::adapters::il2cpp::exports::api().il2cpp_type_get_object || !type) return nullptr;
        return reinterpret_cast<Il2CppObject*(*)(const Il2CppType*)>(
            ta::adapters::il2cpp::exports::api().il2cpp_type_get_object)(type);
    }
}
