#pragma once
#include "Mod.h"
#include "Utils/MemoryUtils.h"
#include "Utils/FileUtils.h"

class Animations : public Mod {
public:
	int mode = 0;
	float x = 0.f, y = 0.f, z = 0.f;

	bool minimalbobbing = false;
	bool guardonly = true;
	float cameraspeed = 1.f;
	bool javamotion = true;
	bool switchanimation = true;
	float swingspeed = 0.3f;

	Animations() : Mod(_("Animations"), _("Apply The BlockHit/Swing Animation"), Category::RENDER) {

		settings.push_back(new Setting{ _("BlockHit Type"), &mode, new int(6), 0, 1, {
			_("1.7"),
			_("1.7 Old"),
			_("Push"),
			_("Vanilla"),
			_("Exhi"),
			_("Sigma"),
			_("Niggahhh"),
			}, true });

		settings.push_back(new Setting{ _("Minimal Bobbing"), &minimalbobbing, 0, 0, 0, {}, true });
		settings.push_back(new Setting{ _("Smooth Swing"), &guardonly, 0, 0, 0, {}, true });
		settings.push_back(new Setting{ _("Camera Speed"), &cameraspeed, new float(4.f), new float(0.f), 2, {}, true, 20.f });
		settings.push_back(new Setting{ _("Java Motion"), &javamotion, 0, 0, 0, {}, true });
		settings.push_back(new Setting{ _("Switch Animation"), &switchanimation, 0, 0, 0, {}, true });
		settings.push_back(new Setting{ _("Swing Speed"), &swingspeed, new float(2.f), new float(0.f), 2, {}, true });
		settings.push_back(new Setting{ _("X"), &x, new float(2.f), new float(-2.f), 2, {}, true });
		settings.push_back(new Setting{ _("Y"), &y, new float(2.f), new float(-2.f), 2, {}, true });
		settings.push_back(new Setting{ _("Z"), &z, new float(2.f), new float(-2.f), 2, {}, true });

		{
			void* ptr;
			if (Utils::File::getVersion() == _("1.21.80"))
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 59"));
			else if (Utils::File::getVersion() == _("1.21.73"))
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 31 09"));
			else if (Utils::File::getVersion() == _("1.21.72"))
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 61"));
			else if (Utils::File::getVersion() == _("1.21.71"))
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 59"));
			else if (Utils::File::getVersion() == _("1.21.70"))
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 C1"));
			else
				ptr = Utils::Memory::FindPattern(_("F3 44 0F 59 05 52"));

			ptr = (void*)((uintptr_t)ptr + *reinterpret_cast<int*>((uintptr_t)ptr + 5) + 9);
			swingangle_ = reinterpret_cast<float*>(ptr);
			DWORD oldProtect;
			VirtualProtect((LPVOID)swingangle_, sizeof(float), PAGE_READWRITE, &oldProtect);
		}

		{
			if (Utils::File::getVersion() == _("1.21.80"))
				flux_ = Utils::Memory::FindPattern(_("E8 B0 7F 6C FE"));
			else if (Utils::File::getVersion() == _("1.21.73"))
				flux_ = Utils::Memory::FindPattern(_("E8 70 52 86 FE"));
			else if (Utils::File::getVersion() == _("1.21.72"))
				flux_ = Utils::Memory::FindPattern(_("E8 70 51 86"));
			else if (Utils::File::getVersion() == _("1.21.71"))
				flux_ = Utils::Memory::FindPattern(_("E8 F0 A7 86"));
			else if (Utils::File::getVersion() == _("1.21.70"))
				flux_ = Utils::Memory::FindPattern(_("E8 00 A8 86"));
			else
				flux_ = Utils::Memory::FindPattern(_("E8 A9 8E 87"));

			DWORD oldProtect;
			VirtualProtect(flux_, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
			memcpy(ogBytes_flux, flux_, 5);
			VirtualProtect(flux_, 5, oldProtect, &oldProtect);
		}

		{
			if (Utils::File::getVersion() == _("1.21.80"))
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 81 51 D2"));
			else if (Utils::File::getVersion() == _("1.21.73"))
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 39 C5 D0"));
			else if (Utils::File::getVersion() == _("1.21.72"))
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 F9 BF D0"));
			else if (Utils::File::getVersion() == _("1.21.71"))
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 19 AE D0"));
			else if (Utils::File::getVersion() == _("1.21.70"))
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 59 CF D0"));
			else
				viewbobbing_ = Utils::Memory::FindPattern(_("FF 15 79 07 D2"));

			DWORD oldProtect;
			VirtualProtect(viewbobbing_, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
			memcpy(ogBytes_viewbobbing, viewbobbing_, 6);
			VirtualProtect(viewbobbing_, 6, oldProtect, &oldProtect);
		}

		enabled = false;
	}

	bool guarding = false;
private:
	bool queue = false;
	bool regetvelocity = false;

	bool patchedflux = false;
	float* swingangle_;
	void* flux_;
	void* ogBytes_flux[5] = { 0 };

	bool patchedviewbob = false;
	void* viewbobbing_;
	void* ogBytes_viewbobbing[6] = { 0 };

	int perspective_ = 0;
	virtual auto onViewPerspectiveAfter(int* perspective) -> void override;
	virtual auto onRenderActorBefore(Actor* actor, glm::vec3* camera, glm::vec3* position) -> void override;
	virtual auto onMouse(char button, char action, bool* cancel) -> void override;
	virtual auto onSwingDuration(int* duration) -> void override;
	virtual auto onBobHurt(glm::mat4* matrix, bool* cancel) -> void override;
	virtual auto onDimensionChanged() -> void override;
	virtual auto onClient() -> void override;
	virtual auto onDisabled() -> void override;
	virtual auto getMode() -> std::string override;
};
