#include "ESP.h"
#include "Utils/MoveUtils.h"
#include "Utils/PlayerUtils.h"
#include "Utils/ImGuiRenderUtils.h"
#include "Utils/MathUtils.h"
#include "Utils/ColorUtils.h"

#include "Mod/Interface.h"

auto ESP::onClient() -> void {
	for (Setting* setting : Client::findSetting(this, _("Thickness"))) {
		setting->visible = mode == 0;
	}
	for (Setting* setting : Client::findSetting(this, _("Round"))) {
		setting->visible = mode == 0;
	}

	if (!enabled) return;


	if (Client::screenName != _("hud_screen")) {
		renderdatas.clear();
		return;
	}

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

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

	auto level = localplayer->getLevel();
	if (!level) return;

	auto levelrender = clientinstance->getLevelRender();
	if (!levelrender) return;


	std::vector<Player*> list;
	level->forEachPlayer([&](Player& player) {
		if (Utils::Players::isRealPlayer(&player)) {
			list.push_back(&player);
		}

		return true;
		});

	std::vector<RenderData> renderdatas_;
	for (Player* player : list) {
		auto aabbshapecomponent = player->getAABBShapeComponent();
		if (!aabbshapecomponent) continue;

		if (player == localplayer && !self || player == localplayer && self && perspective == 0) continue;

		glm::vec3 aabblower = aabbshapecomponent->mAABB.min;
		glm::vec3 aabbupper = aabbshapecomponent->mAABB.max;
		ImVec2 lower = Utils::ImGuiRender::getWorldPosition(aabblower);
		ImVec2 upper = Utils::ImGuiRender::getWorldPosition(aabbupper);
		std::vector<glm::vec3> aabbArr;
		for (float x : { aabblower.x, aabbupper.x }) {
			for (float y : { aabblower.y, aabbupper.y }) {
				for (float z : { aabblower.z, aabbupper.z }) {
					aabbArr.push_back(glm::vec3(x, y, z));
				}
			}
		}

		std::vector<ImVec2> points;
		for (int i = 0; i < aabbArr.size(); i++) {
			ImVec2 point = Utils::ImGuiRender::getWorldPosition(aabbArr[i]);
			if (point.x > 0.f && point.y > 0.f)
				points.push_back(point);
		}

		if (points.empty()) continue;
		if (points.size() != aabbArr.size()) continue;

		ImVec4 rect = { points[0].x, points[0].y, points[0].x, points[0].y };

		for (ImVec2 point : points) {
			rect.x = std::min(rect.x, point.x);
			rect.y = std::min(rect.y, point.y);
			rect.z = std::max(rect.z, point.x);
			rect.w = std::max(rect.w, point.y);
		}

		renderdatas_.push_back({
			rect,
			
			aabbshapecomponent->mAABB.min, aabbshapecomponent->mAABB.max,

			fmax(1.f, 1.f / std::max(1.f, Utils::Math::getDistance(levelrender->getLevelRenderPlayer()->getCameraPos(), Utils::Move::getPosition(player))))
				});
	}

	renderdatas = renderdatas_;
}

auto ESP::onViewPerspectiveAfter(int* perspective) -> void {
	this->perspective = *perspective;
}

auto ESP::onImGuiRender() -> void {
	auto interfaceMod = Client::findMod<Interface>(_("Interface"));

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

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

	if (Client::screenName != _("hud_screen")) return;

	Utils::ImGuiRender::setDrawList(ImGui::GetBackgroundDrawList());
	for (RenderData renderdata : renderdatas) {
		switch (mode) {
		case 0:
			Utils::ImGuiRender::setThickness((renderdata.thickness * thickness) + 2.f);
			Utils::ImGuiRender::setRound(round);
			Utils::ImGuiRender::setColor(ImColor(0.f, 0.f, 0.f));
			Utils::ImGuiRender::drawRectangle(renderdata.rect);

			Utils::ImGuiRender::setThickness(renderdata.thickness * thickness);
			Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 0, 1.f));
			Utils::ImGuiRender::drawRectangle(renderdata.rect);
			break;
		case 1:
			Utils::ImGuiRender::setColor(Utils::Color::getColor(3.f, 0, 0.2f));
			Utils::ImGuiRender::setSecondColor(Utils::Color::getColor(3.f, 0, 1.f));
			Utils::ImGuiRender::setThickness(renderdata.thickness * thickness);
			Utils::ImGuiRender::setOutline(true);

			Utils::ImGuiRender::fillBox(renderdata.lower, renderdata.upper);
			break;
		}
	}
}

auto ESP::getMode() -> std::string {
	switch (mode) {
	case 0:
		return _("2D");
	case 1:
		return _("3D");
	}

	return _("Unknown");
}
