#define NOMINMAX
#include "Engine/Engine.h"
#include "Globals.hxx"
#include "Core/Features/Cache/Cache.h"
#include "Engine/Offsets/Offsets.h"

#include <windows.h>
#include <tlhelp32.h>
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
#include <algorithm>

#include <thread>
#include <chrono>
#include <unordered_map>
#include <string>
#include <cmath>

static SDK::Vector3 LookVector(const SDK::Matrix3& rotationMatrix) {
    return { rotationMatrix.data[2], rotationMatrix.data[2 + 3], rotationMatrix.data[2 + 6] };
}

static SDK::Vector3 RightVector(const SDK::Matrix3& rotationMatrix) {
    return { rotationMatrix.data[0], rotationMatrix.data[0 + 3], rotationMatrix.data[0 + 6] };
}

namespace Misc {

    // ==========================================
    // ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ДЛЯ ДЕСИНКА
    // ==========================================

    // Записываем 0 = лагаем (десинк активен)
    static void DesyncWriteLag() {
        try {
            Driver->Write<int>(
                Globals::Datamodel.Address + Offsets::PhysicsSenderMaxBandwidthBps,
                0
            );
        }
        catch (...) {
            try {
                Driver->Write<int>(
                    Globals::Datamodel.Address + Offsets::PhysicsSenderMaxBandwidthBpsScaling,
                    0
                );
            }
            catch (...) {}
        }
    }

    // Записываем 1000 = нормально (десинк выключен)
    static void DesyncWriteNormal() {
        try {
            Driver->Write<int>(
                Globals::Datamodel.Address + Offsets::PhysicsSenderMaxBandwidthBps,
                1000
            );
        }
        catch (...) {
            try {
                Driver->Write<int>(
                    Globals::Datamodel.Address + Offsets::PhysicsSenderMaxBandwidthBpsScaling,
                    1000
                );
            }
            catch (...) {}
        }
    }

    // ==========================================
    // FIRE RATE (без изменений)
    // ==========================================
    static void FireRate() {
        while (true) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            if (!Globals::Misc::firerate) continue;

            try {
                SDK::Instance datamodel(Globals::Datamodel.Address);
                if (datamodel.Address == 0) continue;

                auto replicatedStorage = datamodel.Find_First_Child("ReplicatedStorage");
                if (replicatedStorage.Address == 0) continue;

                auto weaponsFolder = replicatedStorage.Find_First_Child("Weapons");
                if (weaponsFolder.Address == 0) continue;

                for (auto& weapon : weaponsFolder.Children()) {
                    if (weapon.Address == 0) continue;
                    auto fireRateValue = weapon.Find_First_Child("FireRate");
                    if (fireRateValue.Address != 0) {
                        double new_value = static_cast<double>(Globals::Misc::fireratevalue);
                        Driver->Write<double>(fireRateValue.Address + Offsets::Misc::Value, new_value);
                    }
                }
            }
            catch (...) {}
        }
    }

    // ==========================================
    // FLY (без изменений)
    // ==========================================
    static void Fly() {
        bool AirCheck = false;
        bool FlyToggled = false;
        bool LastPressed = false;

        while (true) {
            if (!Globals::Misc::Fly || Globals::Misc::Fly_Speed <= 0.f) {
                FlyToggled = false;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }

            int vk = ImGuiKeyToVK((ImGuiKey)Globals::Misc::Fly_Key);
            bool isPressed = (vk != 0) && ((GetAsyncKeyState(vk) & 0x8000) != 0);

            if (Globals::Misc::Fly_Mode == ImKeyBindMode_Toggle) {
                if (isPressed && !LastPressed) FlyToggled = !FlyToggled;
                LastPressed = isPressed;
            }
            else {
                FlyToggled = isPressed;
            }

            bool isActive = (vk == 0) ? true : FlyToggled;

            if (!isActive) {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }

            auto& lp = Globals::LocalPlayer;
            if (!lp.HumanoidRootPart.Address || !Globals::Camera.Address) {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }

            SDK::Part HumanoidRootPart(lp.HumanoidRootPart.Address);
            SDK::Camera Camera(Globals::Camera.Address);

            SDK::Matrix3 CamRot = Camera.Get_CameraRot();
            SDK::Vector3 LookVec = LookVector(CamRot);
            SDK::Vector3 RightVec = RightVector(CamRot);
            SDK::Vector3 Direction(0, 0, 0);

            if (GetAsyncKeyState('W') & 0x8000) { Direction = Direction - LookVec; AirCheck = true; }
            if (GetAsyncKeyState('S') & 0x8000) { Direction = Direction + LookVec; AirCheck = true; }
            if (GetAsyncKeyState('A') & 0x8000) { Direction = Direction - RightVec; AirCheck = true; }
            if (GetAsyncKeyState('D') & 0x8000) { Direction = Direction + RightVec; AirCheck = true; }
            if (GetAsyncKeyState(VK_SPACE) & 0x8000) { Direction.y += 1.0f; AirCheck = true; }
            if (GetAsyncKeyState(VK_LCONTROL) & 0x8000) { Direction.y -= 1.0f; AirCheck = true; }

            if (Direction.magnitude() > 0) Direction = Direction.normalize();

            if (!AirCheck) {
                HumanoidRootPart.Write_Velocity({ 0.f, 0.f, 0.f });
            }
            else {
                SDK::Vector3 Velocity = {
                    Direction.x * Globals::Misc::Fly_Speed,
                    Direction.y * Globals::Misc::Fly_Speed,
                    Direction.z * Globals::Misc::Fly_Speed
                };
                HumanoidRootPart.Write_Velocity(Velocity);
            }

            AirCheck = false;
        }
    }

    // ==========================================
    // NOCLIP (без изменений)
    // ==========================================
    static void Noclip() {
        bool NoclipToggled = false;
        bool LastKeyState = false;
        bool WasNoclipping = false;
        std::unordered_map<uintptr_t, uint32_t> OriginalFlags;
        uintptr_t LastCharacter = 0;

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

            int vk = ImGuiKeyToVK((ImGuiKey)Globals::Misc::Noclip_Key);
            bool isPressed = (vk != 0) && ((GetAsyncKeyState(vk) & 0x8000) != 0);

            if (Globals::Misc::Noclip_Mode == ImKeyBindMode_Toggle) {
                if (isPressed && !LastKeyState) NoclipToggled = !NoclipToggled;
                LastKeyState = isPressed;
            }
            else {
                NoclipToggled = isPressed;
            }

            bool isActive = (vk == 0) ? true : NoclipToggled;

            if (!Globals::Misc::Noclip) isActive = false;

            auto& lp = Globals::LocalPlayer;
            if (!lp.HumanoidRootPart.Address) continue;

            uintptr_t CharacterAddr = Driver->Read<uintptr_t>(
                lp.HumanoidRootPart.Address + Offsets::Instance::Parent
            );
            if (!CharacterAddr) continue;

            if (CharacterAddr != LastCharacter) {
                LastCharacter = CharacterAddr;
                OriginalFlags.clear();
            }

            SDK::Instance Character(CharacterAddr);

            if (!isActive) {
                if (WasNoclipping) {
                    for (auto& pair : OriginalFlags) {
                        uintptr_t primitive = Driver->Read<uintptr_t>(
                            pair.first + Offsets::BasePart::Primitive
                        );
                        if (primitive) Driver->Write<uint32_t>(
                            primitive + Offsets::Primitive::Flags, pair.second
                        );
                    }
                    OriginalFlags.clear();
                    WasNoclipping = false;
                }
                continue;
            }

            WasNoclipping = true;

            for (auto& child : Character.Children()) {
                if (child.Address == 0) continue;

                uintptr_t primitive = Driver->Read<uintptr_t>(
                    child.Address + Offsets::BasePart::Primitive
                );
                if (primitive) {
                    uint32_t flags = Driver->Read<uint32_t>(
                        primitive + Offsets::Primitive::Flags
                    );

                    if (OriginalFlags.find(child.Address) == OriginalFlags.end()) {
                        OriginalFlags[child.Address] = flags;
                    }

                    uint32_t newFlags = flags & ~Offsets::PrimitiveFlags::CanCollide;
                    if (flags != newFlags) {
                        Driver->Write<uint32_t>(
                            primitive + Offsets::Primitive::Flags, newFlags
                        );
                    }
                }
            }
        }
    }

    // ==========================================
    // DESYNC (НОВАЯ ВЕРСИЯ - через память)
    // ==========================================
    static void Desync() {
        // Состояние клавиши (аналог desyncbind из старого кода)
        bool DesyncToggled = false;
        bool LastKeyState = false;

        // Состояние цикла (из desyncnew.cpp)
        bool was_enabled = false;
        bool cycle_active = false;
        bool is_currently_lagging = false;
        std::chrono::steady_clock::time_point last_change_time;

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

            // --- ПЕРЕБИНД: вместо Headers::misc::desyncbind используем твою систему ---
            int vk = ImGuiKeyToVK((ImGuiKey)Globals::Misc::Desync_Key);
            bool isPressed = (vk != 0) && ((GetAsyncKeyState(vk) & 0x8000) != 0);

            // Обрабатываем режим кнопки (Toggle / Hold)
            if (Globals::Misc::Desync_Mode == ImKeyBindMode_Toggle) {
                if (isPressed && !LastKeyState) DesyncToggled = !DesyncToggled;
                LastKeyState = isPressed;
            }
            else { // Hold
                DesyncToggled = isPressed;
                LastKeyState = isPressed;
            }

            // Если фича выключена в настройках - принудительно сбрасываем
            if (!Globals::Misc::Desync) {
                DesyncToggled = false;
            }

            // is_now_pressed - аналог переменной из desyncnew.cpp
            bool is_now_pressed = DesyncToggled;

            // --- ЛОГИКА ИЗ desyncnew.cpp ---

            bool normal_desync_active = Globals::Misc::Desync && !Globals::Misc::desync_interval_enabled;
            bool interval_desync_active = Globals::Misc::Desync && Globals::Misc::desync_interval_enabled;

            if (normal_desync_active) {
                // Кнопку нажали - начинаем лагать
                if (!was_enabled && is_now_pressed) {
                    DesyncWriteLag();
                    Globals::Misc::desync_active = true;

                    // Сохраняем позицию для визуала
                    auto& lp = Globals::LocalPlayer;
                    if (lp.HumanoidRootPart.Address) {
                        SDK::Part hrp(lp.HumanoidRootPart.Address);
                        Globals::Misc::desync_activation_pos = hrp.Get_PartPosition();
                    }
                }

                // Кнопку отпустили - перестаем лагать
                if (was_enabled && !is_now_pressed) {
                    DesyncWriteNormal();
                    Globals::Misc::desync_active = false;
                }
            }
            else if (interval_desync_active) {
                // Начало цикла
                if (!was_enabled && is_now_pressed) {
                    DesyncWriteLag();
                    Globals::Misc::desync_active = true;
                    cycle_active = true;
                    is_currently_lagging = true;
                    last_change_time = std::chrono::steady_clock::now();

                    Globals::Misc::desync_interval_is_lagging = true;

                    int hold_time_lag = std::max(
                        50,
                        Globals::Misc::desync_pulse_interval_ms * 15
                    );
                    Globals::Misc::desync_interval_total_time = hold_time_lag / 1000.f;
                    Globals::Misc::desync_interval_time_left = Globals::Misc::desync_interval_total_time;

                    // Сохраняем позицию для визуала
                    auto& lp = Globals::LocalPlayer;
                    if (lp.HumanoidRootPart.Address) {
                        SDK::Part hrp(lp.HumanoidRootPart.Address);
                        Globals::Misc::desync_activation_pos = hrp.Get_PartPosition();
                    }
                }

                // Цикл работает пока кнопка нажата
                if (is_now_pressed && cycle_active) {
                    auto now = std::chrono::steady_clock::now();
                    auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                        now - last_change_time
                    ).count();

                    if (is_currently_lagging) {
                        int hold_time_lag = std::max(
                            50,
                            Globals::Misc::desync_pulse_interval_ms * 15
                        );

                        Globals::Misc::desync_interval_is_lagging = true;
                        Globals::Misc::desync_interval_total_time = hold_time_lag / 1000.f;
                        Globals::Misc::desync_interval_time_left = std::fmax(
                            0.f, (hold_time_lag - elapsed_ms) / 1000.f
                        );

                        // Время лага вышло - восстанавливаем на время паузы
                        if (elapsed_ms >= hold_time_lag) {
                            DesyncWriteNormal();
                            is_currently_lagging = false;
                            last_change_time = now;

                            Globals::Misc::desync_interval_is_lagging = false;

                            int hold_time_normal = std::max(
                                100,
                                Globals::Misc::desync_pulse_interval_ms * 20
                            );
                            Globals::Misc::desync_interval_total_time = hold_time_normal / 1000.f;
                            Globals::Misc::desync_interval_time_left = hold_time_normal / 1000.f;
                        }
                    }
                    else {
                        // Сейчас пауза
                        int hold_time_normal = std::max(
                            100,
                            Globals::Misc::desync_pulse_interval_ms * 20
                        );

                        Globals::Misc::desync_interval_is_lagging = false;
                        Globals::Misc::desync_interval_total_time = hold_time_normal / 1000.f;
                        Globals::Misc::desync_interval_time_left = std::fmax(
                            0.f, (hold_time_normal - elapsed_ms) / 1000.f
                        );

                        // Пауза вышла - снова лагаем
                        if (elapsed_ms >= hold_time_normal) {
                            DesyncWriteLag();
                            is_currently_lagging = true;
                            last_change_time = now;

                            Globals::Misc::desync_interval_is_lagging = true;

                            int hold_time_lag = std::max(
                                50,
                                Globals::Misc::desync_pulse_interval_ms * 15
                            );
                            Globals::Misc::desync_interval_total_time = hold_time_lag / 1000.f;
                            Globals::Misc::desync_interval_time_left = hold_time_lag / 1000.f;
                        }
                    }
                }

                // Кнопку отпустили - сбрасываем всё
                if (was_enabled && !is_now_pressed) {
                    DesyncWriteNormal();
                    Globals::Misc::desync_active = false;
                    cycle_active = false;
                    is_currently_lagging = false;

                    Globals::Misc::desync_interval_is_lagging = false;
                    Globals::Misc::desync_interval_time_left = 0.f;
                    Globals::Misc::desync_interval_total_time = 0.f;
                }
            }
            else {
                // Фича выключена - восстанавливаем нормальное состояние
                DesyncWriteNormal();
                Globals::Misc::desync_active = false;
                cycle_active = false;
                is_currently_lagging = false;

                Globals::Misc::desync_interval_is_lagging = false;
                Globals::Misc::desync_interval_time_left = 0.f;
                Globals::Misc::desync_interval_total_time = 0.f;
            }

            was_enabled = is_now_pressed;
        }
    }

    // ==========================================
    // RUN ALL THREADS
    // ==========================================
    void RunService() {
        std::thread(FireRate).detach();
        std::thread(Fly).detach();
        std::thread(Noclip).detach();
        std::thread(Desync).detach();
    }
}