#include "Interface.h"
#include "Client.h"
#include "Utils/ImGuiRenderUtils.h"
#include "Utils/TimeUtils.h"
#include "Utils/ColorUtils.h"
#include "Utils/MathUtils.h"
#include "Utils/MoveUtils.h"
#include "Utils/AudioUtils.h"

#include "Mod/KillAura.h"

#include "Datas/LanguageDatas.h"

auto Interface::onUIControlGetPosition(UIControl* _this, glm::vec2* position) -> void {
	std::string name = _this->getName();

	if (smoothinventory) {
		if (name == _("root_screen_panel")) {
			*position = glm::vec2(position->x, 0.f);
		}
	}
}

auto Interface::onGetTexture(ResourceLocation* location, mce::TexturePtr* ptr) -> void {
	auto data = *(BedrockTextureData**)&ptr->clienttexture;
	std::string path = location->mPath.c_str();
	if (!selectedHotbarPtr) {
		if (path == _("textures/ui/selected_hotbar_slot")) {
			selectedHotbarPtr = data;
		}
	}
}

auto Interface::onDrawImage(BedrockTextureData* ptr, glm::vec2* pos) -> void {
	if (smoothhotbar) {
		if (selectedHotbarPtr == ptr) {
			static float lerped = pos->x;
			lerped = Utils::Math::animate(pos->x, lerped, Client::deltaTime * 10.f);
			pos->x = lerped;
		}
	}
}

auto Interface::onSwing(Player* _this, bool* cancel) -> void {
	clicks.push_back(Utils::Time::getMs());
}

auto Interface::onImGuiRender() -> void {
	auto clientinstance = Client::clientinstance;
	if (!clientinstance) return;

	auto guidata = clientinstance->getGuiData();
	if (!guidata) return;
	
	static bool backinput = false;
	static bool pressed = false;
	if (Client::screenName != _("start_screen"))
		pressed = false;

	if (mainmenu == 1 || mainmenu == 2) {
		backinput = false;
		static bool back = false;
		if (back && Client::screenName != _("start_screen")) {
			shapes.clear();
			Client::forceCancelinputs = false;
		}
		static float animation = Client::screenName == _("start_screen") ? 1.f : 0.f;
		animation = Utils::Math::animate(Client::screenName == _("start_screen") ? 1.f : 0.f, animation, Client::deltaTime * (Client::screenName == _("start_screen") ? 20.f : 2.f));

		Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
		Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f, animation));
		Utils::ImGuiRender::fillRectangle(ImVec4(0, 0, Client::syncwindowsize.x, Client::syncwindowsize.y));

		if (mainmenu == 1) {
			Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 800.f, animation * 0.1f));
			Utils::ImGuiRender::setSecondColor(Utils::Color::getColor(3.f, 0.f, animation));
			Utils::ImGuiRender::fillGradientOpaqueRectangle(ImVec4(0, 0, Client::syncwindowsize.x, Client::syncwindowsize.y));
		}

		if (mainmenu == 2)
		{
			if (Client::screenName == _("start_screen") && shapes.empty()) {
				srand((unsigned int)time(0));
				for (int i = 0; i < 30; ++i) {
					OrganicShape shape;
					shape.center = ImVec2(rand() % 1800 + 60, rand() % 1000 + 40);
					shape.velocity = ImVec2((rand() % 5 - 2), (rand() % 5 - 2));
					shape.base_radius = rand() % 40 + 30;
					shape.color = ImColor(rand() % 255, rand() % 255, rand() % 255);
					shape.noise_seed = (float)(rand() % 1000);
					shapes.push_back(shape);
				}
			}

			for (auto& shape : shapes) {
				shape.center.x += shape.velocity.x;
				shape.center.y += shape.velocity.y;

				if (shape.center.x < 0 || shape.center.x > Client::syncwindowsize.x)
					shape.velocity.x *= -1;
				if (shape.center.y < 0 || shape.center.y > Client::syncwindowsize.y)
					shape.velocity.y *= -1;

				ImGui::GetBackgroundDrawList()->PathClear();

				for (int i = 0; i < 5; ++i) {
					float angle = i * (2.0f * IM_PI / 6);
					float noise = sinf(angle * 3.0f + ImGui::GetTime() + shape.noise_seed) * 0.2f;
					float radius = shape.base_radius * (1.0f + noise);

					ImVec2 point = ImVec2(
						shape.center.x + cosf(angle) * radius,
						shape.center.y + sinf(angle) * radius
					);
					ImGui::GetBackgroundDrawList()->PathLineTo(point);
				}

				ImGui::GetBackgroundDrawList()->PathFillConvex(ImColor(shape.color.Value.x, shape.color.Value.y, shape.color.Value.z, animation));
			}
		}

		Utils::ImGuiRender::setBlurStreangth(10.f * animation);
		Utils::ImGuiRender::fillBlurRectangle(ImVec4(0, 0, Client::syncwindowsize.x, Client::syncwindowsize.y));

		ImVec4 rect = ImVec4(
			(Client::syncwindowsize.x / 2) - (125.f * (Client::guiScale / 3)),
			(playPos.y * Client::guiScale) - (20.f * (Client::guiScale / 3)),
			(Client::syncwindowsize.x / 2) + (125.f * (Client::guiScale / 3)),
			(playPos.y * Client::guiScale) + (20.f * (Client::guiScale / 3))
		);
		Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[0 + (4 * font)]);
		Utils::ImGuiRender::setSize(1.4f);
		ImVec2 playSize = Utils::ImGuiRender::getTextSize(_("Play"));
		ImVec2 pos = ImVec2(
			(Client::syncwindowsize.x / 2) - (playSize.x / 2),
			(playPos.y * Client::guiScale) - (playSize.y / 2)
		);
		Utils::ImGuiRender::setSize(3.5f * animation);

		Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[1 + (4 * font)]);
		ImVec2 titleSize = Utils::ImGuiRender::getTextSize(_("Valkyrie"));
		ImVec2 titlePos = ImVec2(Client::syncwindowsize.x / 2 - (titleSize.x / 2), rect.y - 150.f);
		int index = 0;

		for (char s : std::string(_("Valkyrie"))) {
			std::stringstream ss;
			ss.precision(0);
			ss << s;

			ImVec2 size = Utils::ImGuiRender::getTextSize(ss.str());

			Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * 60.f, animation));
			Utils::ImGuiRender::drawText(ss.str(), titlePos);
			Utils::ImGuiRender::drawShadow(ImVec2(titlePos.x, titlePos.y + (size.y / 2)));
			titlePos.x += size.x;
			index++;
		}

		Utils::ImGuiRender::setRound(15.f);
		Utils::ImGuiRender::setColor(ImColor(0.1f, 0.1f, 0.1f, animation));
		Utils::ImGuiRender::fillRectangle(rect);
		Utils::ImGuiRender::setSize(10.f);
		Utils::ImGuiRender::setThickness(100.f);
		Utils::ImGuiRender::fillShadowRectangle(rect);

		Utils::ImGuiRender::setBlurStreangth(10.f * animation);
		Utils::ImGuiRender::fillBlurRectangle(rect);

		if (Client::screenName == _("start_screen") && Utils::ImGuiRender::isHoveringRect(rect)) {
			if (ImGui::IsMouseDown(0)) {
				if (!pressed)
					Utils::Audio::playmc(_("random.pop2"), 1.f, 1.f);
				pressed = true;
			}

			Client::forceCancelinputs = false;
			back = false;
		}
		else if (Client::screenName == _("start_screen")) {
			Client::forceCancelinputs = true;
			back = true;
		}

		Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[0 + (4 * font)]);
		Utils::ImGuiRender::setSize(1.4f);
		Utils::ImGuiRender::setColor(ImColor(1.f, 1.f, 1.f ,animation));
		Utils::ImGuiRender::drawText(_("Play"), pos);

		ImVec2 versionSize = Utils::ImGuiRender::getTextSize(_("Minecraft ") + Utils::File::getVersion());
		Utils::ImGuiRender::setSize(1.3f);
		Utils::ImGuiRender::setColor(ImColor(0.4f, 0.4f, 0.4f, animation));
		Utils::ImGuiRender::drawText(_("Minecraft ") + Utils::File::getVersion(), ImVec2(10.f, Client::syncwindowsize.y - (versionSize.y + 10.f)));
	}
	else {
		if (!backinput) {
			shapes.clear();
			Client::forceCancelinputs = false;
			backinput = true;
		}
		pressed = false;
	}
	
	auto localplayer = clientinstance->getLocalPlayer();
	if (!localplayer) return;

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

	auto timer = minecraft->getTimer();
	if (!timer) return;

	std::stringstream ssfps, sscps, ssbps;

	ssfps.precision(0);
	ssfps << std::fixed << Client::framerate;
	
	sscps.precision(0);
	sscps << std::fixed << static_cast<int>(clicks.size());

	ssbps.precision(1);
	ssbps << std::fixed << Utils::Move::getSpeed(localplayer) * timer->mTicksPerSecond;

	static std::string fpsstr = ssfps.str();
	std::string cpsstr = sscps.str();
	std::string bpsstr = ssbps.str();

	static long long start = Utils::Time::getMs();
	long long now = Utils::Time::getMs();
	if (now - start >= 1000.f) {
		fpsstr = ssfps.str();

		start = now;
	}

	if (Client::screenName != _("hud_screen") && Client::screenName != _("chat_screen")) return;
	
	switch (info) {
	case 1: {
		Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[1 + (4 * font)]);
		if (fps) {
			Utils::ImGuiRender::setSize(1.5f);

			if (fpspos.x == ImVec2().x) {
				fpspos = ImVec2(30.f, Client::windowsize.y - (Utils::ImGuiRender::getTextSize("").y + 10.f));
			}

			ImVec2 fpspos_ = fpspos;
			ImVec4 fpsrect = ImVec4(fpspos_.x - 10.f, fpspos_.y - 25.f, fpspos_.x + 10.f + Utils::ImGuiRender::getTextSize(_("FPS: ") + fpsstr).x, fpspos_.y + 25.f);

			Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
			Utils::ImGuiRender::setRound(10.f);

			if (blurs) {
				Utils::ImGuiRender::setBlurStreangth(blurs);
				Utils::ImGuiRender::fillBlurRectangle(fpsrect);
			}

			Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f, 0.6f));
			Utils::ImGuiRender::fillRectangle(fpsrect);
			Utils::ImGuiRender::setSize(20.f);
			Utils::ImGuiRender::setThickness(100.f);
			Utils::ImGuiRender::fillShadowRectangle(fpsrect);

			Utils::ImGuiRender::setSize(1.5f);
			fpspos_.y -= Utils::ImGuiRender::getTextSize(_("FPS: ") + fpsstr).y / 2;
			int index = 0;
			for (char s : std::string(_("FPS: "))) {
				std::stringstream ss;
				ss.precision(0);
				ss << s;

				Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 60 * index, 1.f));
				Utils::ImGuiRender::drawText(ss.str(), fpspos_);
				fpspos_.x += Utils::ImGuiRender::getTextSize(ss.str()).x;
				index++;
			}
			Utils::ImGuiRender::setColor(ImColor(1.f, 1.f, 1.f, 1.f));
			Utils::ImGuiRender::drawText(fpsstr, fpspos_);
		}

		if (cps) {
			Utils::ImGuiRender::setSize(1.5f);

			if (cpspos.x == ImVec2().x) {
				cpspos = ImVec2((30.f + (15.f + Utils::ImGuiRender::getTextSize(_("FPS: ") + fpsstr).x)) + 60.f, Client::windowsize.y - (Utils::ImGuiRender::getTextSize("").y + 10.f));
			}

			ImVec2 pos_ = cpspos;
			ImVec4 rect = ImVec4(pos_.x - 10.f, pos_.y - 25.f, pos_.x + 10.f + Utils::ImGuiRender::getTextSize(_("CPS: ") + cpsstr).x, pos_.y + 25.f);

			Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
			Utils::ImGuiRender::setRound(10.f);

			if (blurs != 0.f) {
				Utils::ImGuiRender::setBlurStreangth(blurs);
				Utils::ImGuiRender::fillBlurRectangle(rect);
			}

			Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f, 0.6f));
			Utils::ImGuiRender::fillRectangle(rect);
			Utils::ImGuiRender::setSize(20.f);
			Utils::ImGuiRender::setThickness(100.f);
			Utils::ImGuiRender::fillShadowRectangle(rect);

			Utils::ImGuiRender::setSize(1.5f);
			pos_.y -= Utils::ImGuiRender::getTextSize(_("CPS: ") + cpsstr).y / 2;
			int index = 0;
			for (char s : std::string(_("CPS: "))) {
				std::stringstream ss;
				ss.precision(0);
				ss << s;

				Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 60 * index, 1.f));
				Utils::ImGuiRender::drawText(ss.str(), pos_);
				pos_.x += Utils::ImGuiRender::getTextSize(ss.str()).x;
				index++;
			}
			Utils::ImGuiRender::setColor(ImColor(1.f, 1.f, 1.f, 1.f));
			Utils::ImGuiRender::drawText(cpsstr, pos_);
		}

		if (bps) {
			Utils::ImGuiRender::setSize(1.5f);

			if (bpspos.x == ImVec2().x) {
				bpspos = ImVec2((30.f + (10.f + Utils::ImGuiRender::getTextSize(_("FPS: ") + fpsstr).x + Utils::ImGuiRender::getTextSize(_("CPS: ") + cpsstr).x)) + (60.f * 2), Client::windowsize.y - (Utils::ImGuiRender::getTextSize("").y + 10.f));
			}

			ImVec2 pos_ = bpspos;
			ImVec4 rect = ImVec4(pos_.x - 10.f, pos_.y - 25.f, pos_.x + 10.f + Utils::ImGuiRender::getTextSize(_("BPS: ") + bpsstr).x, pos_.y + 25.f);

			Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
			Utils::ImGuiRender::setRound(10.f);

			if (blurs != 0.f) {
				Utils::ImGuiRender::setBlurStreangth(blurs);
				Utils::ImGuiRender::fillBlurRectangle(rect);
			}

			Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f, 0.6f));
			Utils::ImGuiRender::fillRectangle(rect);
			Utils::ImGuiRender::setSize(20.f);
			Utils::ImGuiRender::setThickness(100.f);
			Utils::ImGuiRender::fillShadowRectangle(rect);

			Utils::ImGuiRender::setSize(1.5f);
			pos_.y -= Utils::ImGuiRender::getTextSize(_("BPS: ") + bpsstr).y / 2;
			int index = 0;
			for (char s : std::string(_("BPS: "))) {
				std::stringstream ss;
				ss.precision(0);
				ss << s;

				Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 60 * index, 1.f));
				Utils::ImGuiRender::drawText(ss.str(), pos_);
				pos_.x += Utils::ImGuiRender::getTextSize(ss.str()).x;
				index++;
			}
			Utils::ImGuiRender::setColor(ImColor(1.f, 1.f, 1.f, 1.f));
			Utils::ImGuiRender::drawText(bpsstr, pos_);
		}

		break;
	}
	case 2:
		Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
		Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[1 + (4 * font)]);
		Utils::ImGuiRender::setSize(1.3f);
		
		Utils::ImGuiRender::setColor(ImColor(1.f, 1.f, 1.f, 1.f));
		ImVec2 pos = ImVec2(10.f, Client::windowsize.y - (Utils::ImGuiRender::getTextSize(_("")).y + 10.f));
		if (fps) {
			Utils::ImGuiRender::drawText(_("FPS: ") + fpsstr + ((cps || bps) ? _(" | ") : _("")), pos);
			pos.x += Utils::ImGuiRender::getTextSize(_("FPS: ") + fpsstr + ((cps || bps) ? _(" | ") : _(""))).x;
		}
		if (cps) {
			Utils::ImGuiRender::drawText(_("CPS: ") + cpsstr + (bps ? _(" | ") : _("")), pos);
			pos.x += Utils::ImGuiRender::getTextSize(_("CPS: ") + cpsstr + (bps ? _(" | ") : _(""))).x;
		}
		if (bps) {
			Utils::ImGuiRender::drawText(_("BPS: ") + bpsstr, pos);
			pos.x += Utils::ImGuiRender::getTextSize(_("BPS: ") + bpsstr).x;
		}

		break;
	}
}

auto Interface::onClient() -> void {
	for (Setting* setting : Client::findSetting(this, _("Fps"))) {
		if (info == 1 || info == 2)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Cps"))) {
		if (info == 1 || info == 2)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Bps"))) {
		if (info == 1 || info == 2)
			setting->visible = true;
		else
			setting->visible = false;
	}
	for (Setting* setting : Client::findSetting(this, _("Delta Time"))) {
		setting->visible = customdelta;
	}

	for (Setting* setting : Client::findSetting(this, _("Custom Color Settings"))) {
		setting->visible = theme == 9;
	}
	for (Setting* setting : Client::findSetting(this, _("Red"))) {
		setting->visible = theme == 9;
	}
	for (Setting* setting : Client::findSetting(this, _("Green"))) {
		setting->visible = theme == 9;
	}
	for (Setting* setting : Client::findSetting(this, _("Blue"))) {
		setting->visible = theme == 9;
	}

	Datas::Language::language = static_cast<Datas::Language::Languages>(language);

	if (customdelta) {
		Client::deltaTime = deltaTime / 10.f;
	}

	if (!clicks.empty() && Utils::Time::getMs() - clicks.front() >= 1000.f) {
		clicks.pop_front();
	}

	static bool renameaura_ = renameaura;
	auto killauraMod = Client::findMod<KillAura>(renameaura_ ? _("Aura") : _("Kill Aura"));
	if (killauraMod) {
		killauraMod->name = renameaura ? _("Aura") : _("Kill Aura");
		renameaura_ = renameaura;
	}
	else {
		renameaura_ = renameaura;
	}
}

auto Interface::getMode() -> std::string {
	switch (font) {
	case 0:
		return _("Product Sans");
	case 1:
		return _("Minecraft");
	case 2:
		return _("Proxima Nova");
	}
	return _("Unknown");
}
