#include "Packets.h"
#include "Client.h"

#include "Utils/StringUtils.h"
#include "Utils/ChatUtils.h"

#include "Datas/UserDatas.h"

#include "Mod/Test.h"

auto Hooks::Packets::callback_sendToServer(LoopbackPacketSender* _this, Packet* packet) -> void* {
	if (packet->getID() == PacketID::Text) {
		auto textpacket = reinterpret_cast<TextPacket*>(packet);

		std::string message = textpacket->getMessage();
		//Utils::Chat::display_(message);
		if (message.at(0) == '.' && message.size() > 1) {
			std::string messagewdot = message.substr(1);

			std::vector<std::string> argments;
			for (auto part : messagewdot | std::ranges::views::split(' ')) {
				argments.push_back(std::string(part.begin(), part.end()));
			}

			std::string input = Utils::String::substrSpace(messagewdot);
			for (Command* command : Client::commandlist) {
				for (std::string name : command->names) {
					Utils::String::toLowercase(name);

					std::string linput = input;
					Utils::String::toLowercase(linput);
					if (linput == name) {
						if (!command->onExecute(argments)) {
							Utils::Chat::display(
								reinterpret_cast<const char*>(u8"The method of use is different. §7(The current usage is ") + command->usage + ")",
								Utils::Chat::Type::RED);
						}
						return 0;
					}
				}
			}

			Utils::Chat::display(reinterpret_cast<const char*>(_(u8"Command §7")) + input + reinterpret_cast<const char*>(_(u8"§c was not found. You can view the list with .help.")), Utils::Chat::RED);
			return 0;
		}
	}

	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketSendBefore2(packet);
	}

	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketSendBefore(packet);
	}

	bool cancel = false;
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketSendAfter(packet, &cancel);
	}
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketSendAfter2(packet, &cancel);
	}
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketSendAfter3(packet, &cancel);
	}

	if (!cancel)
		return packet_sendToServer(_this, packet);
}

auto Hooks::Packets::callback_setactormotion(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void {
	bool cancel = false;
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;
			
		mod->onPacketReceive(packet.get(), &cancel);
	}

	if (!cancel)
		setactormotion_receive(_this, networkindetifier, neteventcallback, packet);
}

auto Hooks::Packets::callback_text(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void {
	TextPacket* textpacket = reinterpret_cast<TextPacket*>(packet.get());

	bool cancel = false;
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketReceive(packet.get(), &cancel);
	}

	std::string msg = textpacket->getMessage();
	if (msg == reinterpret_cast<const char*>(_(u8"§c§l» §r§c§lGame OVER!"))) {
		for (Mod* mod : Client::modlist) {
			if (!mod->enabled && mod->onlyenabled) continue;

			mod->onWinGame();
		}
		Client::wins++;
	}

	{
		for (Client::UserData userdata : Client::users) {
			std::string name = userdata.mcid;
			std::string username = userdata.username;

			if (name.empty()) continue;

			size_t pos = msg.find(name);

			if (pos != std::string::npos) {
				std::string colorBefore = _("");

				for (int i = static_cast<int>(pos) - 1; i >= 0; --i) {
					if (msg[i] == '§' && i + 1 < msg.size()) {
						colorBefore = msg.substr(i, 2);
						break;
					}
				}

				std::string replacement;

				if (!colorBefore.empty()) {
					replacement = colorBefore + username + reinterpret_cast<const char*>(_(u8" §7(")) + name + _(")");
				}
				else {
					replacement = username + reinterpret_cast<const char*>(_(u8" §7(")) + name + _(")");
				}

				msg.replace(pos, name.length(), replacement);
			}

			textpacket->setMessage(msg);
		}


	}

	if (!cancel)
		text_receive(_this, networkindetifier, neteventcallback, packet);
}

auto Hooks::Packets::callback_removeactor(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void {
	RemoveActorPacket* removeactor = reinterpret_cast<RemoveActorPacket*>(packet.get());
	
	bool cancel = false;
	for (Mod* mod : Client::modlist) {
		if (!mod->enabled && mod->onlyenabled) continue;

		mod->onPacketReceive(packet.get(), &cancel);
	}

	{
		for (Client::AttackData data : Client::attackdatas) {
			if (removeactor->getRuntimeID().rawID == data.runtimeId) {
				for (Mod* mod : Client::modlist) {
					if (!mod->enabled && mod->onlyenabled) continue;

					mod->onKilledPlayer(data.actor);
				}
				Client::kills++;
			}
		}
	}

	if (!cancel)
		removeactor_receive(_this, networkindetifier, neteventcallback, packet);
}

auto Hooks::Packets::callback_containeropen(PacketHandlerDispatcherInstance* _this, void* networkindetifier, void* neteventcallback, std::shared_ptr<Packet>& packet) -> void {
	Hooks::Packets::packethandlerdispatcherinstance = _this;
	Hooks::Packets::networkindetifier = networkindetifier;
	Hooks::Packets::neteventcallback = neteventcallback;

	containeropen_receive(_this, networkindetifier, neteventcallback, packet);
}
