#include "ColorUtils.h"
#include "Client.h"

#include "Mod/Interface.h"

auto Utils::Color::lerpColor(ImColor color1, ImColor color2, float amount) -> ImColor {
	amount = std::min(1.f, std::max(0.f, amount));
	return ImColor(
		color1.Value.x + amount * (color2.Value.x - color1.Value.x),
		color1.Value.y + amount * (color2.Value.y - color1.Value.y),
		color1.Value.z + amount * (color2.Value.z - color1.Value.z),
		color1.Value.w + amount * (color2.Value.w - color1.Value.w)
	);
}

auto Utils::Color::hsvToRgb(float h, float s, float v, float& rout, float& gout, float& bout) -> void {
	if (s == 0.f) {
		rout = gout = bout = v;
		return;
	}

	h = fmodf(h, 1.f) / (60.f / 360.f);
	int i = (int)h;
	float f = h - (float)i;
	float p = v * (1.f - s);
	float q = v * (1.f - s * f);
	float t = v * (1.f - s * (1.f - f));

	switch (i) {
	case 0:
		rout = v;
		gout = t;
		bout = p;
		break;
	case 1:
		rout = q;
		gout = v;
		bout = p;
		break;
	case 2:
		rout = p;
		gout = v;
		bout = t;
		break;
	case 3:
		rout = p;
		gout = q;
		bout = v;
		break;
	case 4:
		rout = t;
		gout = p;
		bout = v;
		break;
	case 5:
	default:
		rout = v;
		gout = p;
		bout = q;
		break;
	}
}

auto Utils::Color::getRainbowColor(float seconds, int index, float brightness, float saturation, float alpha) -> ImColor {
	float hue = ((Utils::Time::getMs() + index) % (int)(seconds * 1000)) / (float)(seconds * 1000);

	ImColor color = ImColor();
	hsvToRgb(hue, saturation, brightness, color.Value.x, color.Value.y, color.Value.z);
	return ImColor(color.Value.x, color.Value.y, color.Value.z, alpha);
}

auto Utils::Color::getWaveColor(float seconds, int index, std::vector<std::pair<float, ImColor>> map) -> ImColor {
	float hue = ((Utils::Time::getMs() + index) % (int)(seconds * 1000)) / (float)(seconds * 1000);

	ImColor color = ImColor();
	for (int i = 0; i < map.size() - 1; i++) {
		if (hue >= map[i].first && hue <= map[i + 1].first) {
			float amount = (hue - map[i].first) / (map[i + 1].first - map[i].first);
			color = lerpColor(map[i].second, map[i + 1].second, amount);
			break;
		}
	}

	return color;
}

auto Utils::Color::getColor(float seconds, int index, float alpha) -> ImColor {
	auto interfaceMod = Client::findMod<Interface>(_("Interface"));
	switch (interfaceMod->theme) {
	default:
	case 0:
		return ImColor(1.f, 1.f, 1.f, alpha);
	case 1:
		return getRainbowColor(seconds, index, 1.f, 1.f, alpha);
	case 2: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(1.f, 0.f, 0.f, alpha)},
						{ 0.5f, ImColor(0.2f, 0.f, 0.f, alpha)},
						{ 1.f, ImColor(1.f, 0.f, 0.f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 3: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(1.f, 1.f, 1.f, alpha)},
						{ 0.5f, ImColor(0.f, 0.5f, 0.5f, alpha)},
						{ 1.f, ImColor(1.f, 1.f, 1.f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 4: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(0.f, 0.f, 0.f, alpha)},
						{ 0.5f, ImColor(0.4f, 0.25f, 1.f, alpha)},
						{ 1.f, ImColor(0.f, 0.f, 0.f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 5: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(1.f, 1.f, 1.f, alpha)},
						{ 0.5f, ImColor(1.f, 0.5f, 0.1f, alpha)},
						{ 1.f, ImColor(1.f, 1.f, 1.f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 6: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(0.4f, 1.f, 0.6f, alpha)},
						{ 0.5f, ImColor(0.f, 1.f, 0.26f, alpha)},
						{ 1.f, ImColor(0.4f, 1.f, 0.6f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 7: {
		std::vector<std::pair<float, ImColor>> list = {
						{ 0.f, ImColor(0.8f, 0.8f, 0.8f, alpha)},
						{ 0.5f, ImColor(0.f, 0.f, 0.f, alpha)},
						{ 1.f, ImColor(0.8f, 0.8f, 0.8f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 8: {
		std::vector<std::pair<float, ImColor>> list = {
						{0.0f,  ImColor(0.85f, 1.f, 1.f, alpha)},
						{0.5f,  ImColor(0.155f, 0.25f, 1.f, alpha)},
						{1.0f,  ImColor(0.85f, 1.f, 1.f, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	case 9: {
		std::vector<std::pair<float, ImColor>> list = {
						{0.0f,  ImColor(interfaceMod->red1, interfaceMod->green1, interfaceMod->blue1, alpha)},
						{0.5f,  ImColor(interfaceMod->red2, interfaceMod->green2, interfaceMod->blue2, alpha)},
						{1.0f,  ImColor(interfaceMod->red1, interfaceMod->green1, interfaceMod->blue1, alpha)}
		};
		return getWaveColor(seconds, index, list);
	}
	}
}

auto Utils::Color::getMCColor(std::string str, float alpha) -> ImColor {
	if (str == _("0")) {
		return ImColor(0.f, 0.f, 0.f, alpha);
	}
	else if (str == _("1")) {
		return ImColor(0.f, 0.f, 170.f / 255.f, alpha);
	}
	else if (str == _("2")) {
		return ImColor(0.f, 170.f / 255.f, 0.f, alpha);
	}
	else if (str == _("3")) {
		return ImColor(0.f, 170.f / 255.f, 170.f / 255.f, alpha);
	}
	else if (str == _("4")) {
		return ImColor(170.f / 255.f, 0.f, 0.f, alpha);
	}
	else if (str == _("5")) {
		return ImColor(170.f / 255.f, 0.f, 0.f, alpha);
	}
	else if (str == _("6")) {
		return ImColor(1.f, 170.f / 255.f, 0.f, alpha);
	}
	else if (str == _("7")) {
		return ImColor(170.f / 255.f, 170.f / 255.f, 170.f / 255.f, alpha);
	}
	else if (str == _("8")) {
		return ImColor(85.f / 255.f, 85.f / 255.f, 85.f / 255.f, alpha);
	}
	else if (str == _("9")) {
		return ImColor(85.f / 255.f, 85.f / 255.f, 1.f, alpha);
		;
	}

	else if (str == _("a")) {
		return ImColor(85.f / 255.f, 1.f, 85.f / 255.f, alpha);
	}
	else if (str == _("b")) {
		return ImColor(85.f / 255.f, 1.f, 1.f, alpha);
	}
	else if (str == _("c")) {
		return ImColor(1.f, 85.f / 255.f, 85.f / 255.f, alpha);
	}
	else if (str == _("d")) {
		return ImColor(1.f, 85.f / 255.f, 1.f, alpha);
	}
	else if (str == _("e")) {
		return ImColor(1.f, 1.f, 85.f / 255.f, alpha);
	}
	else if (str == _("f")) {
		return ImColor(1.f, 1.f, 1.f, alpha);
	}

	return ImColor(1.f, 1.f, 1.f, alpha);
}