#define NOMINMAX
#include <Windows.h>
#include <thread>
#include <vector>
#include <algorithm>
#include <immintrin.h>
#include <cmath>
#include <limits>
#include <iostream>
#include "Silent.h" // Подключаем наш обновленный Silent.h
#include "Engine/Math/Math.h"

// --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ (взяты из твоего кода с исправлениями) ---

std::uint64_t SilentHelper::CachedInputObject = 0;

void SilentHelper::SetFramePosX(std::uint64_t Position) const { Driver->Write<std::uint64_t>(Address + Offsets::Silent::FramePositionOffsetX, Position); }
void SilentHelper::SetFramePosY(std::uint64_t Position) const { Driver->Write<std::uint64_t>(Address + Offsets::Silent::FramePositionOffsetY, Position); }

static std::uint64_t GetCurrentInputObject(std::uint64_t BaseAddress) {
    return Driver->Read<std::uint64_t>(BaseAddress + Offsets::MouseService::InputObject + sizeof(std::shared_ptr<void*>));
}

void SilentHelper::InitializeMouseService(std::uint64_t Address) {
    SilentHelper::CachedInputObject = GetCurrentInputObject(Address);
    if (SilentHelper::CachedInputObject &&
        SilentHelper::CachedInputObject != 0xFFFFFFFFFFFFFFFF) {
        const char* BasePointer = reinterpret_cast<const char*>(
            SilentHelper::CachedInputObject
            );
        _mm_prefetch(BasePointer + Offsets::MouseService::MousePosition, _MM_HINT_T0);
    }
}

void SilentHelper::WriteMousePosition(std::uint64_t Address, float X, float Y) {
    if (!SilentHelper::CachedInputObject ||
        SilentHelper::CachedInputObject == 0xFFFFFFFFFFFFFFFF) {
        SilentHelper::CachedInputObject = GetCurrentInputObject(Address);
        if (!SilentHelper::CachedInputObject ||
            SilentHelper::CachedInputObject == 0xFFFFFFFFFFFFFFFF) return;
    }
    SDK::Vector2 NewPosition = { X, Y };
    Driver->Write<SDK::Vector2>(
        SilentHelper::CachedInputObject + Offsets::MouseService::MousePosition,
        NewPosition
    );
}

// Остальные вспомогательные функции, но с правильным типом Player
static float GetEffectiveFov() {
    if (!Globals::Silent::GunBasedFov) return Globals::Silent::Fov;
    std::string ToolName = Globals::LocalPlayer.Tool_Name;
    if (ToolName.empty()) return Globals::Silent::Fov;
    std::transform(ToolName.begin(), ToolName.end(), ToolName.begin(), ::tolower);
    if (ToolName.find("double-barrel") != std::string::npos || ToolName.find("double barrel") != std::string::npos) return Globals::Silent::FovDoubleBarrel;
    if (ToolName.find("tacticalshotgun") != std::string::npos || ToolName.find("tactical shotgun") != std::string::npos) return Globals::Silent::FovTacticalShotgun;
    if (ToolName.find("revolver") != std::string::npos) return Globals::Silent::FovRevolver;
    return Globals::Silent::Fov;
}

// FIX: Используем правильный тип Globals::CachedPlayer
static SDK::Instance GetTargetPart(const Globals::CachedPlayer& Player, int AimPart) {
    if (AimPart == 0) return Player.Head;
    if (AimPart == 1) return Player.UpperTorso.Address ? Player.UpperTorso : Player.Torso;
    if (AimPart == 2) return Player.LowerTorso.Address ? Player.LowerTorso : Player.Torso;
    return Player.Head; // По умолчанию
}

// FIX: Используем правильный тип Globals::CachedPlayer
static bool IsPlayerKnocked(const Globals::CachedPlayer& Player) {
    if (!Player.Character.Address) return false;
    SDK::Instance BodyEffects = Player.Character.Find_First_Child("BodyEffects");
    if (!BodyEffects.Address) return false;
    SDK::Instance Ko = BodyEffects.Find_First_Child("K.O");
    if (!Ko.Address) return false;
    return Driver->Read<bool>(Ko.Address + Offsets::Misc::Value);
}

// FIX: Используем правильный тип Globals::CachedPlayer
static bool IsTargetWithinFov(const Globals::CachedPlayer& Player) {
    if (!Player.Character.Address) return false;
    static HWND Window = FindWindowA(nullptr, "Roblox");
    if (!Window) return false;
    POINT CursorPoint;
    if (!GetCursorPos(&CursorPoint) || !ScreenToClient(Window, &CursorPoint)) return false;
    SDK::Vector2 Cursor = { (float)CursorPoint.x, (float)CursorPoint.y };
    SDK::Instance TargetPart = GetTargetPart(Player, Globals::Silent::AimPart);
    if (!TargetPart.Address) return false;
    SDK::Part PartObj(TargetPart.Address);
    SDK::Vector3 PartPosition = PartObj.Get_PartPosition();
    SDK::VisualEngine Ve(Globals::VisualEngine.Address);
    SDK::Vector2 PartScreen = Ve.World_To_Screen(PartPosition);
    if (PartScreen.x < 0 || PartScreen.y < 0) return false;
    return PartScreen.distance(Cursor) <= GetEffectiveFov();
}

static Globals::CachedPlayer GetClosestPlayerFromCursor() {
    static HWND Window = FindWindowA(nullptr, "Roblox");
    if (!Window) return {};
    POINT CursorPoint;
    if (!GetCursorPos(&CursorPoint) || !ScreenToClient(Window, &CursorPoint)) return {};
    SDK::Vector2 Cursor = { (float)CursorPoint.x, (float)CursorPoint.y };

    // FIX: Безопасный доступ к кэшу игроков
    std::vector<Globals::CachedPlayer> PlayersSnapshot;
    {
        std::lock_guard<std::mutex> lock(Globals::Cache_Mutex);
        PlayersSnapshot = Globals::Player_Cache;
    }

    if (PlayersSnapshot.empty()) return {};

    Globals::CachedPlayer ClosestPlayer{};
    float ShortestDistance = FLT_MAX;

    for (const auto& Player : PlayersSnapshot) {
        if (!Player.Character.Address || Player.Character.Address == Globals::LocalPlayer.Character.Address) continue;
        SDK::Instance TargetPart = GetTargetPart(Player, Globals::Silent::AimPart);
        if (!TargetPart.Address) continue;
        SDK::Part PartObj(TargetPart.Address);
        SDK::Vector3 PartPosition = PartObj.Get_PartPosition();
        SDK::VisualEngine Ve(Globals::VisualEngine.Address);
        SDK::Vector2 PartScreen = Ve.World_To_Screen(PartPosition);
        if (PartScreen.x < 0 || PartScreen.y < 0) continue;
        float DistanceFromCursor = PartScreen.distance(Cursor);
        if (Globals::Silent::UseFov && DistanceFromCursor > GetEffectiveFov()) continue;
        if (Globals::Silent::KnockedCheck && IsPlayerKnocked(Player)) continue;
        if (DistanceFromCursor < ShortestDistance) {
            ShortestDistance = DistanceFromCursor;
            ClosestPlayer = Player;
        }
    }
    return ClosestPlayer;
}

static void UpdateSilentAimKeyState() {
    int Vk = ImGuiKeyToVK(Globals::Silent::Silent_Key);
    if (!Vk) return;
    bool Pressed = (GetAsyncKeyState(Vk) & 0x8000) != 0;
    if (Globals::Silent::Silent_Mode == ImKeyBindMode_Toggle) {
        if (Pressed && !SilentAimKeyWasPressed) {
            SilentAimLocked = !SilentAimLocked;
        }
    }
    else {
        SilentAimLocked = Pressed;
    }
    SilentAimKeyWasPressed = Pressed;
}

// --- ОСНОВНЫЕ ФУНКЦИИ ---

void Silent::SilentFramePos() {
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

    for (;;) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        if (!MouseService || !MouseService->Address) {
            if (Globals::Datamodel.Address) {
                MouseService = std::make_unique<SDK::Instance>(Globals::Datamodel.Find_First_Child_Of_Class("MouseService"));
            }
            if (!MouseService || !MouseService->Address) {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }
        }

        UpdateSilentAimKeyState();

        // ... Логика скрытия GUI "Aim" (без изменений) ...

        if (!Globals::Silent::Enabled || !SilentAimLocked) {
            if (IsSilentReady.load()) { // Если аим был активен, сбрасываем его состояние
                std::lock_guard<std::mutex> lock(SilentDataMutex);
                SilentCachedTarget = {};
                IsSilentReady = false;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
            continue;
        }

        // ... Логика поиска "Aim" GUI ...

        Globals::CachedPlayer target_player;
        bool sticky_target_is_valid = false;

        { // Читаем текущую цель из кэша
            std::lock_guard<std::mutex> lock(SilentDataMutex);
            if (SilentCachedTarget.Character.Address != 0) {
                target_player = SilentCachedTarget;
                sticky_target_is_valid = true;
            }
        }

        if (!Globals::Silent::StickyAim || !sticky_target_is_valid || (Globals::Silent::UseFov && !IsTargetWithinFov(target_player))) {
            target_player = GetClosestPlayerFromCursor();
        }

        if (target_player.Character.Address != 0) {
            if (Globals::Silent::KnockedCheck && IsPlayerKnocked(target_player)) {
                target_player = {}; // Сбрасываем, если цель в нокауте
            }
        }

        // Обновляем состояние аима
        if (target_player.Character.Address != 0) {
            SDK::Instance TargetPart = GetTargetPart(target_player, Globals::Silent::AimPart);
            if (TargetPart.Address != 0) {
                SDK::Part PartObj(TargetPart.Address);
                SDK::Vector3 Part3D = PartObj.Get_PartPosition();
                SDK::VisualEngine Ve(Globals::VisualEngine.Address);
                SDK::Vector2 PartScreen = Ve.World_To_Screen(Part3D);

                // FIX: Безопасно обновляем общие данные
                std::lock_guard<std::mutex> lock(SilentDataMutex);
                SilentPartPos = PartScreen;
                SilentCachedTarget = target_player;
                IsSilentReady = true;

                // FIX: Удалена строка с Dims, которая вызывала ошибку
            }
        }
        else {
            // FIX: Безопасно сбрасываем состояние, если цель не найдена
            std::lock_guard<std::mutex> lock(SilentDataMutex);
            if (IsSilentReady.load()) { // Проверяем, чтобы не делать лишних блокировок
                SilentCachedTarget = {};
                IsSilentReady = false;
            }
        }
    }
}

void Silent::SilentMouse() {
    SilentHelper MouseServiceInstance{};
    bool MouseServiceInitialized = false;

    for (;;) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        if (!MouseService || !MouseService->Address) {
            MouseServiceInitialized = false;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            continue;
        }

        if (!Globals::Silent::Enabled || !SilentAimLocked) {
            MouseServiceInitialized = false;
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
            continue;
        }

        // FIX: Проверяем атомарный флаг без блокировки
        if (IsSilentReady.load()) {
            SDK::Vector2 currentTargetPos;
            {
                // FIX: Берем позицию под блокировкой, чтобы избежать чтения "рваных" данных
                std::lock_guard<std::mutex> lock(SilentDataMutex);
                currentTargetPos = SilentPartPos;
            }

            if (currentTargetPos.x < -5000.0f || currentTargetPos.y < -5000.0f ||
                currentTargetPos.x > 15000.0f || currentTargetPos.y > 15000.0f) {
                continue;
            }

            try {
                if (!MouseServiceInitialized) {
                    MouseServiceInstance.InitializeMouseService(MouseService->Address);
                    MouseServiceInitialized = true;
                }
                MouseServiceInstance.WriteMousePosition(MouseService->Address, currentTargetPos.x, currentTargetPos.y);
            }
            catch (...) {
                MouseServiceInitialized = false;
            }
        }
    }
}

void Silent::RunService() {
    std::thread(SilentFramePos).detach();
    std::thread(SilentMouse).detach();
}