#pragma once
#include "Utils/MemoryUtils.h"
#include "Client.h"

#include "SDK/InputMode.h"

namespace Hooks {
	class GameModes {
	private:
		typedef float(__thiscall* gamemode_getpickrange_)(GameMode* _this, InputMode const&, bool);
		typedef bool(__thiscall* gamemode_startdestroyblock_)(GameMode* _this, const glm::vec3&, unsigned char, bool&);
		typedef void(__thiscall* gamemode_stopdestroyblock_)(GameMode* _this, const glm::vec3&);
		typedef bool(__thiscall* gamemode_attack_)(GameMode* _this, Actor& target);

		inline static gamemode_getpickrange_ gamemode_getpickrange;
		inline static gamemode_startdestroyblock_ gamemode_startdestroyblock;
		inline static gamemode_stopdestroyblock_ gamemode_stopdestroyblock;
		inline static gamemode_attack_ gamemode_attack;

		static auto callback_startDestroyBlock(GameMode* _this, const glm::vec3&, unsigned char, bool&) -> bool;
		static auto callback_stopDestroyBlock(GameMode* _this, const glm::vec3&) -> void;
		static auto callback_getPickRange(GameMode* _this, InputMode const& currentInputMode, bool isVR) -> float;
		static auto callback_attack(GameMode* _this, Actor& target) -> bool;
	public:
		inline static int state = -1;
		static void Init() {
			std::thread([&] {
				while (!Client::clientinstance ||
					!Client::clientinstance->getLocalPlayer() ||
					!Client::clientinstance->getLocalPlayer()->getGameMode()
					) {
					if (!Client::running) break;
					Sleep(0);
				}
				if (!Client::clientinstance || !Client::clientinstance->getLocalPlayer() || !Client::clientinstance->getLocalPlayer()->getGameMode() || Client::screenName == _("start_screen")) return;

				auto ptr = *(uintptr_t**)(Client::clientinstance->getLocalPlayer()->getGameMode());

				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[1]), (void*)&callback_startDestroyBlock, &gamemode_startdestroyblock);
				if (state != 0)
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[4]), (void*)&callback_stopDestroyBlock, &gamemode_stopdestroyblock);
				if (state != 0)
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[10]), (void*)&callback_getPickRange, &gamemode_getpickrange);
				if (state != 0)
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[14]), (void*)&callback_attack, &gamemode_attack);

				if (state == 0)
					MessageBoxA(0, _("The program was terminated due to an error.\nError code: 1-12"), _("Valkyrie"), MB_ICONERROR);
				else
					std::cout << _("Test 1-12... OK\n");
				}).detach();
		}
	};
}
