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

namespace Hooks {
	class Packets {
	private:
		typedef auto(__thiscall* packet_sendToServer_)(LoopbackPacketSender* _this, Packet* packet) -> void*;
		typedef auto(__thiscall* packet_receive_)(PacketHandlerDispatcherInstance*, void*, void*, std::shared_ptr<Packet>&) -> void;
	public:
		inline static packet_sendToServer_ packet_sendToServer;
		inline static packet_receive_ setactormotion_receive;
		inline static packet_receive_ text_receive;
		inline static packet_receive_ removeactor_receive;
		inline static packet_receive_ containeropen_receive;

		inline static PacketHandlerDispatcherInstance* packethandlerdispatcherinstance;
		inline static void* networkindetifier;
		inline static void* neteventcallback;

	private:
		static auto callback_sendToServer(LoopbackPacketSender* _this, Packet* packet) -> void*;
		static auto callback_setactormotion(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void;
		static auto callback_text(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void;
		static auto callback_removeactor(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void;
		static auto callback_containeropen(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void;
		
	public:
		inline static int state = -1;
		static auto Init() -> void {
			std::thread([&] {
				auto setactormotion_ptr = *(uintptr_t**)(Packet::CreatePacket(PacketID::SetActorMotion))->getHandler();
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(setactormotion_ptr[1]), (void*)&callback_setactormotion, &setactormotion_receive);

				auto text_ptr = *(uintptr_t**)(Packet::CreatePacket(PacketID::Text))->getHandler();
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(text_ptr[1]), (void*)&callback_text, &text_receive);

				auto removeactor_ptr = *(uintptr_t**)(Packet::CreatePacket(PacketID::RemoveActor))->getHandler();
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(removeactor_ptr[1]), (void*)&callback_removeactor, &removeactor_receive);

				auto containeropen_ptr = *(uintptr_t**)(Packet::CreatePacket(PacketID::ContainerOpen))->getHandler();
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(containeropen_ptr[1]), (void*)&callback_containeropen, &containeropen_receive);

				while (!Client::clientinstance || !Client::clientinstance->getLoopbackPacketSender()) {
					if (!Client::running) break;
					Sleep(0);
				}
				if (!Client::clientinstance || !Client::clientinstance->getLoopbackPacketSender()) return;

				auto ptr = *(uintptr_t**)(Client::clientinstance->getLoopbackPacketSender());
				state = Utils::Memory::CreateHook(reinterpret_cast<void*>(ptr[4]), (void*)&callback_sendToServer, &packet_sendToServer);
				

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