#include "Hitbox.h"
#include <thread>
#include <chrono>
#include <unordered_map>
#include "Globals.hxx"
#include "Engine/Engine.h"
#include "Engine/Offsets/Offsets.h"
#include "ImGui/imgui.h" // Для рисования

namespace Hitbox {

    static std::unordered_map<uintptr_t, SDK::Vector3> OriginalSizes;

    static void RestorePart(uintptr_t partAddr, const SDK::Vector3& originalSize) {
        try {
            Driver->Write<SDK::Vector3>(
                partAddr + Offsets::Primitive::Size,
                originalSize
            );
        }
        catch (...) {}
    }

    static void RestoreAll() {
        for (auto& [addr, size] : OriginalSizes) {
            RestorePart(addr, size);
        }
        OriginalSizes.clear();
    }

    static void ExpandPart(uintptr_t partAddr) {
        try {
            SDK::Vector3 originalSize = Driver->Read<SDK::Vector3>(
                partAddr + Offsets::Primitive::Size
            );

            if (OriginalSizes.find(partAddr) == OriginalSizes.end()) {
                if (originalSize.x <= 0.f || originalSize.x > 1000.f) return;
                OriginalSizes[partAddr] = originalSize;
            }

            SDK::Vector3 newSize = {
                Globals::Hitbox::Size,
                Globals::Hitbox::Size,
                Globals::Hitbox::Size
            };

            Driver->Write<SDK::Vector3>(
                partAddr + Offsets::Primitive::Size,
                newSize
            );
        }
        catch (...) {}
    }

    // Рисуем 3D Box по позиции и размеру парта
    static void DrawBox3D(
        const SDK::Vector3& center,
        float size,
        ImU32 color,
        ImU32 fillColor,
        float thickness,
        bool fill)
    {
        // VisualEngine для проекции
        SDK::VisualEngine Ve(Globals::VisualEngine.Address);

        float half = size * 0.5f;

        // 8 вершин куба в мировом пространстве
        SDK::Vector3 corners[8] = {
            { center.x - half, center.y - half, center.z - half },
            { center.x + half, center.y - half, center.z - half },
            { center.x + half, center.y + half, center.z - half },
            { center.x - half, center.y + half, center.z - half },
            { center.x - half, center.y - half, center.z + half },
            { center.x + half, center.y - half, center.z + half },
            { center.x + half, center.y + half, center.z + half },
            { center.x - half, center.y + half, center.z + half },
        };

        // Проецируем в экранное пространство
        SDK::Vector2 screen[8];
        bool allValid = true;
        for (int i = 0; i < 8; i++) {
            screen[i] = Ve.World_To_Screen(corners[i]);
            if (screen[i].x < 0 || screen[i].y < 0) {
                allValid = false;
                break;
            }
        }

        if (!allValid) return;

        ImDrawList* drawList = ImGui::GetBackgroundDrawList();

        // Заливка (рисуем грани)
        if (fill) {
            // Передняя грань
            drawList->AddQuadFilled(
                { screen[0].x, screen[0].y },
                { screen[1].x, screen[1].y },
                { screen[2].x, screen[2].y },
                { screen[3].x, screen[3].y },
                fillColor
            );
            // Задняя грань
            drawList->AddQuadFilled(
                { screen[4].x, screen[4].y },
                { screen[5].x, screen[5].y },
                { screen[6].x, screen[6].y },
                { screen[7].x, screen[7].y },
                fillColor
            );
            // Левая грань
            drawList->AddQuadFilled(
                { screen[0].x, screen[0].y },
                { screen[4].x, screen[4].y },
                { screen[7].x, screen[7].y },
                { screen[3].x, screen[3].y },
                fillColor
            );
            // Правая грань
            drawList->AddQuadFilled(
                { screen[1].x, screen[1].y },
                { screen[5].x, screen[5].y },
                { screen[6].x, screen[6].y },
                { screen[2].x, screen[2].y },
                fillColor
            );
            // Верхняя грань
            drawList->AddQuadFilled(
                { screen[3].x, screen[3].y },
                { screen[2].x, screen[2].y },
                { screen[6].x, screen[6].y },
                { screen[7].x, screen[7].y },
                fillColor
            );
            // Нижняя грань
            drawList->AddQuadFilled(
                { screen[0].x, screen[0].y },
                { screen[1].x, screen[1].y },
                { screen[5].x, screen[5].y },
                { screen[4].x, screen[4].y },
                fillColor
            );
        }

        // Рёбра куба (12 рёбер)
        // Передняя грань
        drawList->AddLine({ screen[0].x, screen[0].y }, { screen[1].x, screen[1].y }, color, thickness);
        drawList->AddLine({ screen[1].x, screen[1].y }, { screen[2].x, screen[2].y }, color, thickness);
        drawList->AddLine({ screen[2].x, screen[2].y }, { screen[3].x, screen[3].y }, color, thickness);
        drawList->AddLine({ screen[3].x, screen[3].y }, { screen[0].x, screen[0].y }, color, thickness);
        // Задняя грань
        drawList->AddLine({ screen[4].x, screen[4].y }, { screen[5].x, screen[5].y }, color, thickness);
        drawList->AddLine({ screen[5].x, screen[5].y }, { screen[6].x, screen[6].y }, color, thickness);
        drawList->AddLine({ screen[6].x, screen[6].y }, { screen[7].x, screen[7].y }, color, thickness);
        drawList->AddLine({ screen[7].x, screen[7].y }, { screen[4].x, screen[4].y }, color, thickness);
        // Соединяем переднюю и заднюю
        drawList->AddLine({ screen[0].x, screen[0].y }, { screen[4].x, screen[4].y }, color, thickness);
        drawList->AddLine({ screen[1].x, screen[1].y }, { screen[5].x, screen[5].y }, color, thickness);
        drawList->AddLine({ screen[2].x, screen[2].y }, { screen[6].x, screen[6].y }, color, thickness);
        drawList->AddLine({ screen[3].x, screen[3].y }, { screen[7].x, screen[7].y }, color, thickness);
    }

    static void HitboxLoop() {
        bool HitboxToggled = false;
        bool LastKeyState = false;

        while (true) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));

            // Обработка бинда
            bool isPressed = false;
            if (Globals::Hitbox::Hitbox_Key != ImGuiKey_None) {
                isPressed = ImGui::IsKeyDown((ImGuiKey)Globals::Hitbox::Hitbox_Key);
            }

            if (Globals::Hitbox::Hitbox_Mode == ImKeyBindMode_Toggle) {
                if (isPressed && !LastKeyState) HitboxToggled = !HitboxToggled;
                LastKeyState = isPressed;
            }
            else {
                HitboxToggled = isPressed;
                LastKeyState = isPressed;
            }

            bool isActive = Globals::Hitbox::Enabled && HitboxToggled;

            if (!isActive) {
                if (!OriginalSizes.empty()) RestoreAll();
                continue;
            }

            // Снапшот кэша
            std::vector<Globals::CachedPlayer> players;
            {
                std::lock_guard<std::mutex> lock(Globals::Cache_Mutex);
                players = Globals::Player_Cache;
            }

            // Конвертируем цвета из float[4] в ImU32
            ImU32 boxColor = ImGui::ColorConvertFloat4ToU32(ImVec4(
                Globals::Hitbox::HitboxColor[0],
                Globals::Hitbox::HitboxColor[1],
                Globals::Hitbox::HitboxColor[2],
                Globals::Hitbox::HitboxColor[3]
            ));
            ImU32 fillColor = ImGui::ColorConvertFloat4ToU32(ImVec4(
                Globals::Hitbox::HitboxFillColor[0],
                Globals::Hitbox::HitboxFillColor[1],
                Globals::Hitbox::HitboxFillColor[2],
                Globals::Hitbox::HitboxFillColor[3]
            ));

            std::unordered_map<uintptr_t, bool> currentParts;

            for (const auto& player : players) {
                if (player.Character.Address == 0) continue;

                if (Globals::Hitbox::HeadOnly) {
                    if (player.Head.Address != 0) {
                        currentParts[player.Head.Address] = true;
                        ExpandPart(player.Head.Address);

                        // Рисуем бокс если включено
                        if (Globals::Hitbox::DrawHitbox) {
                            SDK::Part part(player.Head.Address);
                            SDK::Vector3 pos = part.Get_PartPosition();
                            DrawBox3D(
                                pos,
                                Globals::Hitbox::Size,
                                boxColor,
                                fillColor,
                                Globals::Hitbox::HitboxThickness,
                                Globals::Hitbox::FillHitbox
                            );
                        }
                    }
                }
                else {
                    auto processPartWithDraw = [&](const SDK::Instance& inst) {
                        if (inst.Address == 0) return;
                        currentParts[inst.Address] = true;
                        ExpandPart(inst.Address);

                        // Рисуем бокс если включено
                        if (Globals::Hitbox::DrawHitbox) {
                            SDK::Part part(inst.Address);
                            SDK::Vector3 pos = part.Get_PartPosition();
                            DrawBox3D(
                                pos,
                                Globals::Hitbox::Size,
                                boxColor,
                                fillColor,
                                Globals::Hitbox::HitboxThickness,
                                Globals::Hitbox::FillHitbox
                            );
                        }
                        };

                    processPartWithDraw(player.Head);
                    processPartWithDraw(player.Torso);
                    processPartWithDraw(player.UpperTorso);
                    processPartWithDraw(player.LowerTorso);
                    processPartWithDraw(player.HumanoidRootPart);
                }
            }

            // Восстанавливаем парты игроков которых нет в кэше
            for (auto it = OriginalSizes.begin(); it != OriginalSizes.end();) {
                if (currentParts.find(it->first) == currentParts.end()) {
                    RestorePart(it->first, it->second);
                    it = OriginalSizes.erase(it);
                }
                else {
                    ++it;
                }
            }
        }
    }

    void RunService() {
        std::thread(HitboxLoop).detach();
    }
}