#include "ArrayList.h"
#include "Client.h"
#include "Utils/ImGuiRenderUtils.h"
#include "Utils/MathUtils.h"
#include "Utils/ColorUtils.h"

#include "Mod/Interface.h"

auto ArrayList::onImGuiRender() -> void {
	if (Client::screenName == _("start_screen")) return;

	Interface* interfaceMod = Client::findMod<Interface>(_("Interface"));
	Utils::ImGuiRender::setFont(ImGui::GetIO().Fonts->Fonts[(bold ? 1 : 0) + (4 * interfaceMod->font)]);
	
	static std::vector<Mod*> list = Client::modlist;

	{
		static std::vector<bool> list_enabled;
		static std::vector<std::string> list_getmode;
		static std::vector<bool> list_bools;

		static bool sort = false;
		if (!sort) {
			if (list_enabled.empty()) {
				for (Mod* mod : Client::modlist) {
					list_enabled.push_back(mod->enabled);
				}

				sort = true;
			}
			if (list_getmode.empty()) {
				for (Mod* mod : Client::modlist) {
					list_getmode.push_back(mod->getMode());
				}

				sort = true;
			}
			if (list_bools.empty()) {
				for (Mod* mod : Client::modlist) {
					for (Setting* setting : mod->settings) {
						if (setting->type == 0) {
							list_bools.push_back(*(bool*)setting->ptr);
						}
					}
				}
			}

			for (size_t i = 0; i < list_enabled.size(); i++) {
				if (list_enabled[i] != Client::modlist[i]->enabled) {
					sort = true;
					list_enabled[i] = Client::modlist[i]->enabled;
				}
			}
			for (size_t i = 0; i < list_getmode.size(); i++) {
				if (list_getmode[i] != Client::modlist[i]->getMode()) {
					sort = true;
					list_getmode[i] = Client::modlist[i]->getMode();
				}
			}
			for (size_t i = 0; i < list_bools.size(); i++) {
				for (Mod* mod : Client::modlist) {
					for (Setting* setting : mod->settings) {
						if (setting->type == 0) {
							if (list_bools[i] != *(bool*)setting->ptr) {
								sort = true;
								list_bools[i] = *(bool*)setting->ptr;
							}
						}
					}
				}
			}

			static bool lastbold = bold;
			if (lastbold != bold) {
				sort = true;
				lastbold = bold;
			}
		}

		if (sort) {
			if (!Client::modlist.empty()) {
				std::sort(list.begin(), list.end(), [&](Mod* a, Mod* b) {
					if (a && b) {
						return Utils::ImGuiRender::getTextSize(a->name + (a->getMode().empty() ? _("") : (showMode ? (_(" ") + a->getMode()) : _("")))).x >
							Utils::ImGuiRender::getTextSize(b->name + (b->getMode().empty() ? _("") : (showMode ? (_(" ") + b->getMode()) : _("")))).x;
					}
					});

				sort = false;
			}
		}
	}

	ImVec4 lastrect = ImVec4();

	int index = 0;
	for (Mod* mod : list) {
		if (!mod) continue;
		mod->datas.animation = Utils::Math::animate((mod->enabled && mod->visible) ? 1.f : 0.f, mod->datas.animation, Client::deltaTime * 5.f);
		if (mod->datas.animation < 0.01f) continue;

		Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());

		Utils::ImGuiRender::setSize(size);
		ImVec2 textsize_ = Utils::ImGuiRender::getTextSize(mod->name + (mod->getMode().empty() ? _("") : (showMode ? (_(" ") + mod->getMode()) : _(""))));
		ImVec2 textpos = ImVec2(Client::windowsize.x - ((textsize_.x + 10.f) * mod->datas.animation), 10.f);

		if (mod->datas.y == 0.f) {
			mod->datas.y = textpos.y + (((6.f * padding) + textsize_.y) * index) + barwidth;
		}
		mod->datas.y = Utils::Math::animate(textpos.y + (((6.f * padding) + textsize_.y) * index) + (barwidth), mod->datas.y, Client::deltaTime * 5.f);
		textpos.y = mod->datas.y;
		ImVec4 rect = ImVec4(
			textpos.x - 5.5f,
			textpos.y - (3.f * padding),
			textpos.x + textsize_.x + 5.5f,
			textpos.y + ((3.f * padding) + textsize_.y)
		);

		if (clickToggle && Utils::ImGuiRender::isHoveringRect(rect) && ImGui::IsMouseClicked(0)) {
			mod->enabled = false;
			mod->onDisabled();

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

				mod2->onAnyDisabled();
			}
		}

		ImVec4 siderect = ImVec4(rect.z - (3.f * barwidth), rect.y + barpadding, rect.z, rect.w - barpadding);

		if (shadow == 0) {
			ImColor shadowColor = ImColor(0.f, 0.f, 0.f);
			if (shadowinterfaceColor) {
				shadowColor = Utils::Color::getColor(4.f, index * (colorindex * 60.f), 1.f * mod->datas.animation);
			}
			shadowColor.Value.w = shadowopacity * mod->datas.animation;

			Utils::ImGuiRender::setColor(shadowColor);
			Utils::ImGuiRender::setSize(10.f * shadowamount);
			Utils::ImGuiRender::setThickness(100.f * shadowamount);
			Utils::ImGuiRender::setRound(0.f);
			Utils::ImGuiRender::fillShadowRectangle(rect);
		}

		switch (style) {
		case 1:
		case 2:
		case 3:
		case 4:
			if (style == 2 || style == 4 || style == 1) {
				rect = ImVec4(rect.x - (2.f * barwidth), rect.y, rect.z - (3.f * barwidth), rect.w);
				textpos.x -= (2.f * barwidth);
			}

			if (style == 3) {
				siderect = ImVec4(rect.x - (3.f * barwidth), rect.y + barpadding, rect.x, rect.w - barpadding);
			}

			if (style == 4 || style == 1) {
				ImVec4 toprect = ImVec4(rect.x - (barwidth * 3), rect.y, rect.z + (barwidth * 3.f), rect.y + (barwidth * 3.f));
				rect.y += barwidth * 3.f;
				rect.w += barwidth * 3.f;
				textpos.y += barwidth * 3.f;
				siderect.y += barwidth * 3.f;
				siderect.w += barwidth * 3.f;

				if (index == 0) {
					Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index* (colorindex * 60.f), shadowopacity* mod->datas.animation));
					Utils::ImGuiRender::setSize(10.f * shadowamount);
					Utils::ImGuiRender::setThickness(100.f * shadowamount);
					Utils::ImGuiRender::setRound(0.f);Utils::ImGuiRender::fillShadowRectangle(toprect);
					Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * (colorindex * 60.f), mod->datas.animation));
					Utils::ImGuiRender::fillRectangle(toprect);
				}
			}

			Utils::ImGuiRender::setSize(10.f * shadowamount);
			Utils::ImGuiRender::setThickness(100.f * shadowamount);
			Utils::ImGuiRender::setRound(0.f);
			Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index* (colorindex * 60.f), shadowopacity* mod->datas.animation));
			Utils::ImGuiRender::fillShadowRectangle(siderect);

			Utils::ImGuiRender::setRound(barrounding);
			Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index* (colorindex * 60.f), mod->datas.animation));
			if (style == 2)
				Utils::ImGuiRender::fillRectangleCustomRadius(siderect, ImVec4(0, 0, barrounding, barrounding));
			else
				Utils::ImGuiRender::fillRectangle(siderect);

			if (style == 1) {
				siderect = ImVec4(rect.x - (3.f * barwidth), rect.y + barpadding, rect.x, rect.w - barpadding);
				Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * 60, shadowopacity * mod->datas.animation));
				Utils::ImGuiRender::setSize(10.f * shadowamount);
				Utils::ImGuiRender::setThickness(100.f * shadowamount);
				Utils::ImGuiRender::setRound(0.f);
				Utils::ImGuiRender::fillShadowRectangle(siderect);
				Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * (colorindex * 60.f), mod->datas.animation));
				Utils::ImGuiRender::fillRectangle(siderect);

				if (index > 0) {
					ImVec4 prevunder = ImVec4(lastrect.x - (3.f * barwidth), lastrect.w, lastrect.x + (rect.x - lastrect.x), lastrect.w + (3.f * barwidth));
					Utils::ImGuiRender::fillRectangle(prevunder);
				}
			}
			break;
		}

		if (blurs != 0.f) {
			Utils::ImGuiRender::setDrawList(ImGui::GetForegroundDrawList());
			Utils::ImGuiRender::setBlurStreangth(blurs * mod->datas.animation);
			Utils::ImGuiRender::setRound(0.f);
			Utils::ImGuiRender::fillBlurRectangleWithClip(rect, ImVec4(0, 0, Client::windowsize.x, Client::windowsize.y));
			Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
		}


		Utils::ImGuiRender::setRound(0.f);
		Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f, opacity * mod->datas.animation));
		Utils::ImGuiRender::fillRectangle(rect);

		int sindex = 0;
		for (char s : mod->name + (mod->getMode().empty() ? _("") : (showMode ? (_(" ") + mod->getMode()) : _("")))) {
			std::stringstream ss;
			ss << s;

			Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
			Utils::ImGuiRender::setSize(size);

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

			ImColor shadowColor = ImColor(0.f, 0.f, 0.f);
			if (shadowinterfaceColor) {
				shadowColor = Utils::Color::getColor(4.f, (gradient ? sindex : index) * (colorindex * 60.f), 1.f * mod->datas.animation);
			}
			shadowColor.Value.w = shadowopacity * mod->datas.animation;

			if (shadow == 1 && shadowamount != 0.f) {
				Utils::ImGuiRender::setColor(shadowColor);
				Utils::ImGuiRender::setSize(10.f * shadowamount);
				Utils::ImGuiRender::setThickness(100.f * shadowamount);
				Utils::ImGuiRender::drawShadow(ImVec2(textpos.x, textpos.y + (textsize_.y / 2)));
			}

			Utils::ImGuiRender::setSize(size);

			if (sindex < mod->name.size())
				Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, (gradient ? sindex : index) * (colorindex * 60.f), 1.f * mod->datas.animation));
			else if (showMode)
				Utils::ImGuiRender::setColor(ImColor(0.6f, 0.6f, 0.6f, 1.f * mod->datas.animation));

			Utils::ImGuiRender::setSize(size);
			Utils::ImGuiRender::setDrawList(ImGui::GetForegroundDrawList());
			Utils::ImGuiRender::drawText(ss.str(), textpos);

			textpos.x += textsize_.x;
			sindex++;
		}

		if (mod->enabled && mod->visible) {
			index++;
			lastrect = rect;
		}
	}

	if (style == 1) {
		ImVec4 underrect = ImVec4(lastrect.x - (barwidth * 3), lastrect.w, lastrect.z + (barwidth * 3), lastrect.w + (barwidth * 3));
		Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * 60, shadowopacity * 1.f * index));
		Utils::ImGuiRender::setSize(10.f * shadowamount);
		Utils::ImGuiRender::setThickness(240.f * shadowamount);
		Utils::ImGuiRender::setRound(0.f);
		Utils::ImGuiRender::fillShadowRectangle(underrect);
		Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
		Utils::ImGuiRender::setColor(Utils::Color::getColor(4.f, index * (colorindex * 60.f), 1.f * index));
		Utils::ImGuiRender::fillRectangle(underrect);
	}
}

auto ArrayList::onClient() -> void {
	for (Setting* setting : Client::findSetting(this, _("Bar"))) {
		if (style == 1 || style == 2 || style == 3 || style == 4)
			setting->visible = true;
		else
			setting->visible = false;
	}
}

auto ArrayList::getMode() -> std::string {
	switch (style) {
	case 0:
		return _("Normal");
	case 1:
		return _("Outline");
	case 2:
		return _("Bar");
	case 3:
		return _("Right");
	case 4:
		return _("Border");
	}

	return _("Unknown");
}
