#pragma once

#include <string>

#include "adapters/windows/Hooking.h"
#include "adapters/il2cpp/Il2CppObjectAccess.h"
#include "foundation/diagnostics/Logger.h"

namespace ta::adapters::il2cpp
{
    template <typename T, typename T2>
    [[nodiscard]] bool hook_method(const Il2CppClass* clazz, const char* name, int args, T hook, T2 original)
    {
        const char* class_name = (clazz && clazz->name) ? clazz->name : "(null class)";
        if (!clazz)
        {
            ta::foundation::logger::warn(std::string("hook_method FAILED (null class): ") + (name ? name : "?"));
            return false;
        }

        const MethodInfo* method = ManagedRuntime::method_or_null(
            clazz, name ? name : "", args);
        if (!method)
        {
            ta::foundation::logger::warn(std::string("hook_method FAILED (null method): ") + class_name + "::" + (name ? name : "?"));
            return false;
        }

        if (!method->methodPointer)
        {
            ta::foundation::logger::warn(std::string("hook_method FAILED (null methodPointer): ") + class_name + "::" + (name ? name : "?"));
            return false;
        }

        return ta::adapters::windows::hooks::hook(method->methodPointer, reinterpret_cast<PVOID>(hook), reinterpret_cast<PVOID*>(original));
    }
}
