#pragma once
#include "vectors.hpp"
#include "../driver/driver.hpp"
#include "../extern/Imgui/imgui_internal.h"
#include "../utils/Authentication/skStr.h"
namespace PawnData
{
	inline uint64_t GWorld = 0;
	inline uintptr_t Player = 0;
	inline uint64_t PlayerController = 0;
	inline uint64_t LocalPlayer = 0;
	inline uint64_t RootComponent = 0;
	inline uintptr_t LocalWeapon = 0;
	inline uintptr_t WeaponData = 0;

	inline uintptr_t LocalVehicle = 0;
	inline uintptr_t AcknowledgedPawn = 0;
	inline char TeamIndex = 0;
	inline uintptr_t Mesh = 0;


}

inline Camera vCamera;

inline auto GetBoneLocation(uintptr_t skeletal_mesh, int bone_index) -> Vector3 {

	uintptr_t bone_array = kernel->read_t<uintptr_t>(skeletal_mesh + offsets::BoneArray);

	if (bone_array == NULL)

		bone_array = kernel->read_t<uintptr_t>(skeletal_mesh + offsets::BoneArray + 0x10);

	FTransform bone = kernel->read_t<FTransform>(bone_array + (bone_index * 0x60));

	FTransform component_to_world = kernel->read_t<FTransform>(skeletal_mesh + offsets::ComponentToWorld);

	D3DMATRIX matrix = matrix_multiplication(bone.to_matrix_with_scale(), component_to_world.to_matrix_with_scale());

	return Vector3(matrix._41, matrix._42, matrix._43);
}

struct CamewaDescwipsion {
	Vector3 Location;
	Vector3 Rotation;
	float FieldOfView;
};

Camera GetViewAngles() {
	CamewaDescwipsion camera;
	auto locationPointer = kernel->read_t<uintptr_t>(PawnData::GWorld + offsets::CameraLocation);
	auto rotationPointer = kernel->read_t<uintptr_t>(PawnData::GWorld + offsets::CameraRotation);

	struct Rotation {
		double a;
		char pad_0008[24];
		double b;
		char pad_0028[424];
		double c;
	};
	Rotation rotation;
	rotation = kernel->read_t<Rotation>(rotationPointer);

	camera.Location = kernel->read_t<Vector3>(locationPointer);
	camera.Rotation.x = asin(rotation.c) * (180.0 / std::numbers::pi);
	camera.Rotation.y = ((atan2(rotation.a * -1, rotation.b) * (180.0 / std::numbers::pi)) * -1) * -1;
	camera.FieldOfView = kernel->read_t<float>(PawnData::PlayerController + offsets::CameraFOV) * 90.f; // CameraFOV  - Look for "FOV" if you cant find it.

	return { camera.Location, camera.Rotation, camera.FieldOfView };
}

Vector2 ProjectWorldToScreen(Vector3 WorldLocation) {
	vCamera = GetViewAngles();

	auto mMatrix = to_matrix(vCamera.Rotation);
	auto XAxis = Vector3(mMatrix.m[0][0], mMatrix.m[0][1], mMatrix.m[0][2]);
	auto YAxis = Vector3(mMatrix.m[1][0], mMatrix.m[1][1], mMatrix.m[1][2]);
	auto ZAxis = Vector3(mMatrix.m[2][0], mMatrix.m[2][1], mMatrix.m[2][2]);

	auto vDeltaCoordinates = WorldLocation - vCamera.Location;
	auto tTransform = Vector3(vDeltaCoordinates.Dot(YAxis), vDeltaCoordinates.Dot(ZAxis), vDeltaCoordinates.Dot(XAxis));

	tTransform.z = (tTransform.z < 1.f) ? 1.f : tTransform.z;
	auto fov_radians = tan(vCamera.FieldOfView * std::numbers::pi / 360.f);

	return Vector2(Width / 2 + tTransform.x * ((Width / 2) / fov_radians) / tTransform.z, Height / 2 - tTransform.y * ((Width / 2) / fov_radians) / tTransform.z);
}

bool IsEnemyVisible(uintptr_t Mesh) {
	auto Seconds = kernel->read_t<double>(offsets::CameraRotation + 0x10); // offsets::CameraRotation + 0x10
	auto LastRenderTime = kernel->read_t<float>(Mesh + 0x190);

	return Seconds - LastRenderTime <= 0.06f;
}
//bool is_visible(u_world* g_world) {
//	auto delta_time_seconds = g_driver->read<float>((std::uint64_t)g_world + 0x86C);
//	auto time_seconds = g_driver->read<double>((std::uint64_t)g_world + 0x860);
//
//	auto last_render_time = g_driver->read<float>((std::uint64_t)this + 0x328);
//	auto time_since = time_seconds - last_render_time;
//
//	auto render_time_threshold = fmaxf(0.06f, delta_time_seconds + 0.000099999997);
//	return time_since <= render_time_threshold;
//}



std::string GetWeaponName(uintptr_t Player) {
	std::string weapon_name;

	uint64_t current_weapon = kernel->read_t<uint64_t>(Player + offsets::CurrentWeapon);
	uint64_t weapon_data = kernel->read_t<uint64_t>(current_weapon + offsets::WeaponData);
	uint64_t item_name = kernel->read_t<uint64_t>(weapon_data + 0x40);

	uint64_t FData = kernel->read_t<uint64_t>(item_name + 0x20);
	int FLength = kernel->read_t<int>(item_name + 0x28);

	if (FLength > 0 && FLength < 50)
	{
		wchar_t* WeaponBuffer = new wchar_t[FLength];
		kernel->read_array((FData), WeaponBuffer, FLength * sizeof(wchar_t));

		std::wstring wstr_buf(WeaponBuffer);
		weapon_name.append(std::string(wstr_buf.begin(), wstr_buf.end()));

		delete[] WeaponBuffer;
	}

	return weapon_name;
};


std::string get_player_platform(uintptr_t player_state, ImColor& resultColor)
{
	__int64 FString = kernel->read_t<__int64>(player_state + offsets::Platform);
	uintptr_t platform_ptr = kernel->read_t<uintptr_t>(player_state + offsets::Platform);

	int length = static_cast<int>(kernel->read_t<__int64>(FString + 16));
	if (length == 0) {
		resultColor = ImColor(150, 150, 150);
		return skCrypt("bot").decrypt();
	}

	wchar_t platform_wide[64] = { 0 };
	kernel->read_array(platform_ptr, platform_wide, sizeof(platform_wide));

	std::wstring platform_wstr(platform_wide);
	std::string platform_str(platform_wstr.begin(), platform_wstr.end());

	std::transform(platform_str.begin(), platform_str.end(), platform_str.begin(), ::toupper);

	static const std::unordered_map<std::string, std::pair<std::string, ImColor>> platform_map = {
		{"XBL",      {skCrypt("Xbox Series S").decrypt(),    ImColor(16, 124, 16)}},
		{"XSX",      {skCrypt("Xbox Series X").decrypt(),    ImColor(16, 124, 16)}},
		{"PSN",      {skCrypt("PlayStation 4").decrypt(),   ImColor(0, 102, 204)}},
		{"PS5",      {skCrypt("PlayStation 5").decrypt(),   ImColor(0, 102, 204)}},
		{"SWT",      {skCrypt("Nintendo Switch").decrypt(), ImColor(229, 0, 18)}},
		{"NSW",      {skCrypt("Nintendo Switch").decrypt(), ImColor(229, 0, 18)}},
		{"WIN",      {skCrypt("Windows").decrypt(),         ImColor(0, 191, 255)}},
		{"PC",       {skCrypt("Windows").decrypt(),         ImColor(0, 191, 255)}},
		{"MOBIL-A",  {skCrypt("Android").decrypt(),         ImColor(139, 195, 74)}},
		{"ANDROID",  {skCrypt("Android").decrypt(),         ImColor(139, 195, 74)}},
		{"MOBIL-I",  {skCrypt("iOS").decrypt(),             ImColor(0, 122, 255)}},
		{"IOS",      {skCrypt("iOS").decrypt(),             ImColor(0, 122, 255)}}
	};

	auto it = platform_map.find(platform_str);
	if (it != platform_map.end()) {
		resultColor = it->second.second;
		return it->second.first;
	}

	resultColor = ImColor(200, 200, 200);
	return skCrypt("unknown").decrypt();
}

std::string GetPlayerName(uintptr_t playerState)
{
	try {
		uintptr_t FString = kernel->read_t<uintptr_t>(playerState + offsets::PlayerName);
		int Length = kernel->read_t<int>(FString + 16);
		uintptr_t FText = kernel->read_t<uintptr_t>(FString + 8);

		if (Length <= 0)
			return skCrypt("BOT").decrypt();

		std::vector<wchar_t> NameBuffer(Length);
		kernel->read_array(FText, NameBuffer.data(), Length * sizeof(wchar_t));

		__int64 v6 = Length;
		char v21 = v6 - 1;
		if (!(DWORD)v6)
			v21 = 0;
		int v22 = 0;
		WORD* v23 = (WORD*)NameBuffer.data();
		for (int i = (v21) & 3;; *v23++ += i & 7) {
			int v25 = v6 - 1;
			if (!(DWORD)v6)
				v25 = 0;
			if (v22 >= v25)
				break;
			i += 3;
			++v22;
		}

		std::wstring wbuffer(NameBuffer.begin(), NameBuffer.end());
		std::string result(wbuffer.begin(), wbuffer.end());
		return result;
	}
	catch (...) {
		return skCrypt("Unknown").decrypt();
	}
}

struct TargetInfo {
	uintptr_t mesh;
	uintptr_t pawn;
	Vector2 head2D;
	bool isVisible;
	float distance;
};

bool is_dead(uintptr_t pawn_private)
{
	return (kernel->read_t<char>(pawn_private + offsets::bIsDying) >> 5) & 1;
}

enum class EFort_Rarity : std::uint8_t {
	common = 0,
	uncommon = 1,
	rare = 2,
	epic = 3,
	legendary = 4,
	mythic = 5,
	transcendent = 6,
	unattainable = 7,
	num_rarity_values = 8
};

EFort_Rarity GetRarity(uintptr_t pawn) {
	if (!pawn) return EFort_Rarity::common;
	uintptr_t currentWeapon = kernel->read_t<uint64_t>(pawn + offsets::CurrentWeapon);
	if (!currentWeapon) return EFort_Rarity::common;
	uintptr_t data = kernel->read_t<uintptr_t>(currentWeapon + offsets::WeaponData);
	return kernel->read_t<EFort_Rarity>(data + offsets::Rarity);

}

inline ImColor GetWeaponColor(int32_t Tier)
{
	if (Tier == 0 || Tier == 7)
		return ImColor(255, 255, 255); // Common
	else if (Tier == 1)
		return ImColor(0, 255, 64);    // Uncommon
	else if (Tier == 2)
		return ImColor(0, 160, 255);   // Rare
	else if (Tier == 3)
		return ImColor(200, 80, 255);  // Epic
	else if (Tier == 4)
		return ImColor(255, 180, 30);  // Legendary
	else if (Tier == 5)
		return ImColor(255, 255, 80);  // Mythic
	else
		return ImColor(255, 255, 255); // Default
}


std::string get_rank_name(int tier)
{
	switch (tier)
	{
	case 0: return "Bronze I";
	case 1: return "Bronze II";
	case 2: return "Bronze III";
	case 3: return "Silver I";
	case 4: return "Silver II";
	case 5: return "Silver III";
	case 6: return "Gold I";
	case 7: return "Gold II";
	case 8: return "Gold III";
	case 9: return "Platinum I";
	case 10: return "Platinum II";
	case 11: return "Platinum III";
	case 12: return "Diamond I";
	case 13: return "Diamond II";
	case 14: return "Diamond III";
	case 15: return "Elite";
	case 16: return "Champion";
	case 17: return "Unreal";
	default: return "Unranked";
	}
}

ImVec4 get_rank_color(int tier)
{
	switch (tier)
	{
	case 0: return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);    // Unranked
	case 1:
	case 2: return ImVec4(0.902f, 0.580f, 0.227f, 1.0f); // Bronze
	case 3:
	case 4:
	case 5: return ImVec4(0.843f, 0.843f, 0.843f, 1.0f); // Silver
	case 6:
	case 7:
	case 8: return ImVec4(1.0f, 0.871f, 0.0f, 1.0f); // Gold
	case 9:
	case 10:
	case 11: return ImVec4(0.0f, 0.7f, 0.7f, 1.0f);  // Platinum
	case 12:
	case 13:
	case 14: return ImVec4(0.1686f, 0.3294f, 0.8235f, 1.0f); // Diamond
	case 15: return ImVec4(0.7f, 0.7f, 0.7f, 1.0f);   // Elite
	case 16: return ImVec4(1.0f, 0.6f, 0.0f, 1.0f);   // Champion
	case 17: return ImVec4(0.6f, 0.0f, 0.6f, 1.0f);   // Unreal
	default: return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);    // Unranked
	}
}

void draw_text(ImFont* font, float fontSize, ImVec2 position, ImColor color, const char* text)
{
	ImGui::GetBackgroundDrawList()->AddText(font, fontSize, ImVec2(position.x - 1, position.y - 1), ImColor(0, 0, 0), text);
	ImGui::GetBackgroundDrawList()->AddText(font, fontSize, ImVec2(position.x + 1, position.y - 1), ImColor(0, 0, 0), text);
	ImGui::GetBackgroundDrawList()->AddText(font, fontSize, ImVec2(position.x - 1, position.y + 1), ImColor(0, 0, 0), text);
	ImGui::GetBackgroundDrawList()->AddText(font, fontSize, ImVec2(position.x + 1, position.y + 1), ImColor(0, 0, 0), text);
	ImGui::GetBackgroundDrawList()->AddText(font, fontSize, position, color, text);
}
