#include "Fly.h"
#include "Utils/MoveUtils.h"
#include "Utils/TimeUtils.h"
#include "Utils/ChatUtils.h"

auto Fly::onWorldTick(Player* _this) -> void {
	if (!enabled) return;

	auto clientinstance = Client::clientinstance;
	if (!clientinstance) return;

	auto minecraft = clientinstance->getMinecraft();
	if (!minecraft) return;

	auto actorrotationcomponent = _this->getActorRotationComponent();
	if (!actorrotationcomponent) return;

	float angle = (actorrotationcomponent->mRotationDegree.y + 90) * (3.1415927f / 180);
	float yaw = Utils::Move::getMoveYaw() + actorrotationcomponent->mRotationDegree.y;

	glm::vec3 velocity = Utils::Move::getVelocity(_this);
	glm::vec3 position = Utils::Move::getPosition(_this);

	if (damagefly) {
		if (!damaged) {
			damaged = _this->getHurtTime() > 0;
			minecraft->getTimer()->mTicksPerSecond = 20.f;
			if (half) Utils::Move::setVelocity(_this, glm::vec3(0.f, (nohalfy ? velocity.y : 0.f), 0.f));
			return;
		}

		static long long start = Utils::Time::getMs();
		long long now = Utils::Time::getMs();
		if (now - start >= 1000.f * damagetime) {
			damaged = false;
			start = now;
		}
	}

	switch (mode) {
	case 0: {
		minecraft->getTimer()->mTicksPerSecond = timer;

		velocity.y = 0.f;
		if (Client::screenName == _("hud_screen")) {
			if (Utils::Move::isSneaking())
				velocity.y = -(speed * 2.f);
			else if (Utils::Move::isJumping())
				velocity.y = (speed * 2.f);

			if (Utils::Move::isForwarding()) {
				velocity.x = cos(angle) * (speed * 2.f);
				velocity.z = sin(angle) * (speed * 2.f);
			}


			if (Utils::Move::isMoving()) {
				velocity.x = cos(yaw * (3.1415927f / 180)) * (speed * 2.f);
				velocity.z = sin(yaw * (3.1415927f / 180)) * (speed * 2.f);
			}
		}

		Utils::Move::setVelocity(_this, velocity);
		break;
	}
	case 1: {
		minecraft->getTimer()->mTicksPerSecond = timer;

		if (Client::screenName == _("hud_screen")) {
			if (Utils::Move::isForwarding()) {
				velocity.x = cos(angle) * (speed * 2.f);
				velocity.z = sin(angle) * (speed * 2.f);
			}

			if (Utils::Move::isMoving()) {
				velocity.x = cos(yaw * (3.1415927f / 180)) * (speed * 2.f);
				velocity.z = sin(yaw * (3.1415927f / 180)) * (speed * 2.f);
			}
		}

		if (!getY) {
			jumpY = position.y;
			getY = true;
		}

		if (position.y <= jumpY) {
			jumpY = position.y;

			velocity.y = (jumpheight * 2.f);
		}

		Utils::Move::setVelocity(_this, velocity);
		break;
	}
	case 2: {
		minecraft->getTimer()->mTicksPerSecond = timer;

		if (Utils::Move::isOnGround(_this) && Utils::Move::isMoving) {
			Utils::Move::setJumping(_this, true);
			testdownvalue_ = 0.f;
		}
		else {
			Utils::Move::setJumping(_this, false);
		}

		if (boost) {
			long long now = Utils::Time::getMs();
			static long long start = now;
			static bool boosting = false;
			if (now - start >= 0.4 * 1000.f) {
				boosting = !boosting;
				start = now;
			}
			if (boosting) {
				velocity.y = (-1.00 * 0.45);

				if (Client::screenName == _("hud_screen")) {
					if (Utils::Move::isForwarding()) {
						velocity.x = cos(angle) * (0.33 - testdownvalue_);
						velocity.z = sin(angle) * (0.33 - testdownvalue_);
					}


					if (Utils::Move::isMoving()) {
						velocity.x = cos(yaw * (3.1415927f / 180)) * (0.33 - testdownvalue_);
						velocity.z = sin(yaw * (3.1415927f / 180)) * (0.33 - testdownvalue_);
					}
				}

			}
			else {
				velocity.y = (-0.55 * 0.45);

				if (Client::screenName == _("hud_screen")) {
					if (Utils::Move::isForwarding()) {
						velocity.x = cos(angle) * (0.31 - testdownvalue_);
						velocity.z = sin(angle) * (0.31 - testdownvalue_);
					}


					if (Utils::Move::isMoving()) {
						velocity.x = cos(yaw * (3.1415927f / 180)) * (0.31 - testdownvalue_);
						velocity.z = sin(yaw * (3.1415927f / 180)) * (0.31 - testdownvalue_);
					}
				}

			}
		}
		else {
			velocity.y = (-0.55 * 0.45);

			if (Client::screenName == _("hud_screen")) {
				if (Utils::Move::isForwarding()) {
					velocity.x = cos(angle) * (0.31 - testdownvalue_);
					velocity.z = sin(angle) * (0.31 - testdownvalue_);
				}


				if (Utils::Move::isMoving()) {
					velocity.x = cos(yaw * (3.1415927f / 180)) * (0.31 - testdownvalue_);
					velocity.z = sin(yaw * (3.1415927f / 180)) * (0.31 - testdownvalue_);
				}
			}

		}

		//Slow down
		if (slowitdown) {
			long long now = Utils::Time::getMs();
			static long long start = now;
			static bool test_slowing = false;
			if (now - start >= 0.02 * 1000.f) {
				test_slowing = !test_slowing;
				start = now;
			}
			if (test_slowing) {
				testdownvalue_ += (1.00 * 0.005);
			}
		}
		Utils::Move::setVelocity(_this, velocity);
		break;
	}
	case 3: {
		if (vanillajump) {
			if (Utils::Move::isOnGround(_this) && Utils::Move::isMoving) {
				Utils::Move::setJumping(_this, true);
				downvalue_ = 0.f;
			}
			else {
				Utils::Move::setJumping(_this, false);
			}
		}

		if (boost) {
			long long now = Utils::Time::getMs();
			static long long start = now;
			static bool boosting = false;
			if (now - start >= boosttiming * 1000.f) {
				boosting = !boosting;
				start = now;
			}
			if (boosting) {
				minecraft->getTimer()->mTicksPerSecond = boosttimer;

				velocity.y = (-boostglide * 0.45);

				if (Client::screenName == _("hud_screen")) {
					if (Utils::Move::isForwarding()) {
						velocity.x = cos(angle) * (boostspeed - downvalue_);
						velocity.z = sin(angle) * (boostspeed - downvalue_);
					}


					if (Utils::Move::isMoving()) {
						velocity.x = cos(yaw * (3.1415927f / 180)) * (boostspeed - downvalue_);
						velocity.z = sin(yaw * (3.1415927f / 180)) * (boostspeed - downvalue_);
					}
				}

			}
			else {
				minecraft->getTimer()->mTicksPerSecond = timer;

				velocity.y = (-glide * 0.45);

				if (Client::screenName == _("hud_screen")) {
					if (Utils::Move::isForwarding()) {
						velocity.x = cos(angle) * (speed - downvalue_);
						velocity.z = sin(angle) * (speed - downvalue_);
					}


					if (Utils::Move::isMoving()) {
						velocity.x = cos(yaw * (3.1415927f / 180)) * (speed - downvalue_);
						velocity.z = sin(yaw * (3.1415927f / 180)) * (speed - downvalue_);
					}
				}

			}
		}

		else {
			minecraft->getTimer()->mTicksPerSecond = timer;

			velocity.y = (-glide * 0.45);

			if (Client::screenName == _("hud_screen")) {
				if (Utils::Move::isForwarding()) {
					velocity.x = cos(angle) * (speed - downvalue_);
					velocity.z = sin(angle) * (speed - downvalue_);
				}


				if (Utils::Move::isMoving()) {
					velocity.x = cos(yaw * (3.1415927f / 180)) * (speed - downvalue_);
					velocity.z = sin(yaw * (3.1415927f / 180)) * (speed - downvalue_);
				}
			}

		}

		//Slow down
		if (slowitdown) {
			long long now = Utils::Time::getMs();
			static long long start = now;
			static bool slowing = false;
			if (now - start >= downamount * 1000.f) {
				slowing = !slowing;
				start = now;
			}
			if (slowing) {
				downvalue_ += (downvalue * 0.005);
			}
		}
		Utils::Move::setVelocity(_this, velocity);
		break;
	}
	}
}

auto Fly::onDimensionChanged() -> void {
	if (requestdisable) {
		enabled = false;
		onDisabled();

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

			mod->onAnyDisabled();
		}

		requestdisable = false;
	}
}

auto Fly::onWinGame() -> void {
	if (autoenablewhenwin) {
		enabled = true;
		onEnabled();

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

			mod->onAnyEnabled();
		}

		requestdisable = true;
	}
}

auto Fly::onDisabled() -> void {
	testdownvalue_ = 0.f;
	downvalue_ = 0.f;
	jumpY = 0.f;
	getY = false;

	auto clientinstance = Client::clientinstance;
	if (!clientinstance) return;

	auto localplayer = clientinstance->getLocalPlayer();
	if (!localplayer) return;

	auto minecraft = clientinstance->getMinecraft();
	if (!minecraft) return;

	minecraft->getTimer()->mTicksPerSecond = 20.f;
	if (half) Utils::Move::setVelocity(localplayer, glm::vec3(0.f, (nohalfy ? Utils::Move::getVelocity(localplayer).y : 0.f), 0.f));

	if (forceonground)	Utils::Move::setVelocity(localplayer, glm::vec3(0.f, -10.f, 0.f));
}

auto Fly::onClient() -> void {
	for (Setting* setting : Client::findSetting(this, _("Jump Height"))) {
		setting->visible = mode == 1;
	}
	//Debug 1
	for (Setting* setting : Client::findSetting(this, _("Boost Timer"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	//Debug 1 done
	for (Setting* setting : Client::findSetting(this, _("Damage"))) {
		if (setting->name == _("Damage Fly")) continue;

		setting->visible = damagefly;
	}
	for (Setting* setting : Client::findSetting(this, _("No Half Y"))) {
		setting->visible = half;
	}

	//Debug 2
	for (Setting* setting : Client::findSetting(this, _("Debug"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Jump from ground"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Glide amount"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Boost"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Slow Down"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Slower"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Force"))) {
		if (mode == 3)
			setting->visible = true;
		else
			setting->visible = false;
	}
}

auto Fly::getMode() -> std::string {
	switch (mode) {
	case 0:
		return _("Vanilla");
	case 1:
		return _("Jump");
	case 2:
		return _("Flareon Glide");
	case 3:
		return _("Debug");
	}

	return _("Unknown");
}
