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

namespace Hooks {
	class Players {
	private:
		typedef auto(__thiscall* player_interpolatedheadyaw_)(Player* _this, float a1) -> float;
		typedef auto(__thiscall* player_interpolatedbodyyaw_)(Player* _this, float a1) -> float;
		typedef auto(__thiscall* player_getshadowradius_)(Player* _this) -> float;
		typedef auto(__thiscall* player_isonfire_)(Player* _this) -> bool;
		typedef auto(__thiscall* player_)(Player* _this) -> void;

		inline static player_interpolatedheadyaw_ player_interpolatedheadyaw;
		inline static player_interpolatedbodyyaw_ player_interpolatedbodyyaw;

		inline static player_ player_basetick;
		inline static player_getshadowradius_ player_getshadowradius;
		inline static player_isonfire_ player_isonfire;
		inline static player_ player_swing;
		inline static player_ player_worldtick;

		static auto callback_interpolatedheadyaw(Player* _this, float a1) -> float;
		static auto callback_interpolatedbodyyaw(Player* _this, float a1) -> float;

		static auto callback_basetick(Player* _this) -> void;
		static auto callback_getshadowradius(Player* _this) -> float;
		static auto callback_isonfire(Player* _this) -> bool;
		static auto callback_swing(Player* _this) -> void;
		static auto callback_worldtick(Player* _this) -> void;

	public:
		inline static int state = -1;
		static auto Init() -> void {
			std::thread([&] {
				while (!Client::clientinstance || !Client::clientinstance->getLocalPlayer()) {
					if (!Client::running) break;
					Sleep(0);
				}
				if (!Client::clientinstance || !Client::clientinstance->getLocalPlayer() || Client::screenName == _("start_screen")) return;

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

				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[14]), (void*)&callback_interpolatedheadyaw, &player_interpolatedheadyaw);
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[15]), (void*)&callback_interpolatedbodyyaw, &player_interpolatedbodyyaw);

				if (Utils::File::getVersion() == _("1.21.80"))
					state = Utils::Memory::CreateHook(Utils::Memory::FindPattern(_("48 8D 05 0F 81 59")), (void*)&callback_basetick, &player_basetick);
				else if (Utils::File::getVersion() == _("1.21.73"))
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[25]), (void*)&callback_basetick, &player_basetick);
				else if (Utils::File::getVersion() == _("1.21.72"))
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[25]), (void*)&callback_basetick, &player_basetick);
				else if (Utils::File::getVersion() == _("1.21.71"))
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[25]), (void*)&callback_basetick, &player_basetick);
				else if (Utils::File::getVersion() == _("1.21.70"))
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[25]), (void*)&callback_basetick, &player_basetick);
				else if (Utils::File::getVersion() == _("1.21.62"))
					state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[25]), (void*)&callback_basetick, &player_basetick);

				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[35]), (void*)&callback_getshadowradius, &player_getshadowradius);
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[48]), (void*)&callback_isonfire, &player_isonfire);
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[111]), (void*)&callback_swing, &player_swing);
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[182]), (void*)&callback_worldtick, &player_worldtick);

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