#include "memory/visual_mods.hpp"
#include "memory/aob_scanner.hpp"
#include "memory/game_layout.hpp"
#include "memory/rpm_reader.hpp"
#include <vector>
#include <cstring>
#include <cmath>
#include <string>

namespace {

bool IsCanonicalUserPointer(uint64_t p) {
    // Win64 user-mode canonical: bit 47 = 0 → bits 48–63 = 0.
    return p >= 0x10000ull && p < 0x0000800000000000ull;
}

bool LooksLikeCameraFields(uint64_t vtable, float cur, float minD, float maxD,
                           float fov, float zNear, float zFar,
                           uintptr_t moduleBase, size_t moduleSize,
                           bool unlockedKeepAlive) {
    if (!std::isnormal(cur) || !std::isnormal(maxD)) return false;
    // Bit-pattern float (ma trận 11/09/2026 PID 3132) không phải vtable.
    if (!IsCanonicalUserPointer(vtable)) return false;
    const float maxHi = unlockedKeepAlive ? 1200.0f : 500.0f;
    if (maxD < 8.0f || maxD > maxHi) return false;
    if (cur < 3.0f || cur > 1200.0f) return false;
    if (cur > maxD * 5.0f) return false;

    const bool minOk = std::isnormal(minD) && minD >= 1.0f && minD <= 120.0f && minD < maxD;
    const bool spreadOk = (maxD - minD) >= 5.0f;
    const bool fovOk = std::isnormal(fov) && ((fov >= 0.30f && fov <= 1.80f) || (fov >= 5.0f && fov <= 90.0f));
    const bool zNearOk = std::isnormal(zNear) && zNear >= 0.001f && zNear <= 5.0f && zNear < zFar;
    const bool zFarOk = std::isnormal(zFar) && zFar >= 20.0f && zFar <= 50000.0f && zNearOk;
    const bool vtableOk = moduleBase != 0 && moduleSize != 0
        && vtable >= moduleBase && vtable < moduleBase + moduleSize;
    const float maxAllowedDistance = unlockedKeepAlive ? 400.0f : 120.0f;
    const bool typical = (maxD >= 12.0f && maxD <= maxAllowedDistance && cur >= 6.0f && cur <= 500.0f);

    // Bất biến: Khi đã biết module chính, vtable BẮT BUỘC phải nằm trong module image (chống buffer vertex/text rác)
    if (moduleBase != 0 && moduleSize != 0 && !vtableOk) return false;
    // Bắt buộc phải có độ chênh lệch zoom tối thiểu giữa min và max
    if (!minOk || !spreadOk || !fovOk) return false;

    int score = 0;
    if (typical) score += 3;
    if (minOk) score += 2;
    if (fovOk) score += 2;
    if (zFarOk) score += 2;
    if (vtableOk) score += 3;
    return score >= 5;
}

bool LooksLikeCameraAt(IMemoryReader& reader, uintptr_t addr, uintptr_t moduleBase, size_t moduleSize) {
    if (addr < 0x10000) return false;
    uint64_t vtable = 0;
    float cur = 0, minD = 0, maxD = 0, fov = 0, zNear = 0, zFar = 0;
    if (!reader.ReadValue<uint64_t>(addr, vtable)) return false;
    if (!reader.ReadValue<float>(addr + 0x2C, cur)) return false;
    if (!reader.ReadValue<float>(addr + 0x30, minD)) return false;
    if (!reader.ReadValue<float>(addr + 0x34, maxD)) return false;
    if (!reader.ReadValue<float>(addr + 0x38, fov)) return false;
    if (!reader.ReadValue<float>(addr + 0x3C, zNear)) return false;
    if (!reader.ReadValue<float>(addr + 0x40, zFar)) return false;
    return LooksLikeCameraFields(vtable, cur, minD, maxD, fov, zNear, zFar, moduleBase, moduleSize, false);
}

bool LooksLikeFogFields(float density, float start, float end, float falloff) {
    if (!std::isfinite(density) || density < 0.05f || density > 4.0f) return false;
    if (!std::isfinite(start) || !std::isfinite(end) || !std::isfinite(falloff)) return false;
    // start/end phải là khoảng cách thế giới (không phải nửa QWORD con trỏ / denormal).
    if (start < 1.0f || start >= 2000.0f) return false;
    if (end < 15.0f || end > 8000.0f || end <= start) return false;
    if (falloff < 0.01f || falloff > 2.5f) return false;
    return true;
}

bool LooksLikeFogAt(IMemoryReader& reader, uintptr_t addr) {
    if (addr < 0x10000) return false;
    float density = 0, start = 0, end = 0, falloff = 0;
    if (!reader.ReadValue<float>(addr, density)) return false;
    if (!reader.ReadValue<float>(addr + 4, start)) return false;
    if (!reader.ReadValue<float>(addr + 8, end)) return false;
    if (!reader.ReadValue<float>(addr + 12, falloff)) return false;
    return LooksLikeFogFields(density, start, end, falloff);
}

bool ResolveMainModule(uint32_t pid, IMemoryReader& reader, ModuleInfo& mainMod) {
    const std::wstring procCandidates[] = {
        L"PathOfExile.exe", L"PathOfExileSteam.exe", L"PathOfExile_x64.exe",
        L"PathOfExile_x64Steam.exe", L"PathOfExile2.exe"
    };
    for (const auto& name : procCandidates) {
        if (AobScanner::FindModule(pid, name, mainMod) && mainMod.base != 0 && mainMod.size != 0) {
            return true;
        }
    }
    bool found = false;
    reader.ForEachReadableRegion([&](uintptr_t base, size_t size) -> bool {
        if (!found && base != 0 && size >= 0x1000) {
            mainMod.name = "readable";
            mainMod.base = base;
            mainMod.size = size;
            found = true;
        }
        return true;
    });
    return found;
}

struct CameraAobSpec {
    const char* pattern;
    bool derefPointer;
};

} // namespace

VisualModsEngine::VisualModsEngine(IMemoryReader& reader)
    : m_reader(reader) {
    m_minimapGridCodePatch.name = "POE2_Minimap_GridFill";
    m_minimapGridCodePatch.originalBytes = { 0x44, 0x38, 0x59, 0x61, 0x75, 0x1F };
    m_minimapGridCodePatch.patchedBytes  = { 0xEB, 0x23, 0x90, 0x90, 0x90, 0x90 };
    m_minimapGridCodePatch.isPatched = false;

    m_minimapUniformCodePatch.name = "POE2_Minimap_VisibilityUniform";
    m_minimapUniformCodePatch.originalBytes = { 0x74, 0x05 };
    m_minimapUniformCodePatch.patchedBytes  = { 0x90, 0x90 };
    m_minimapUniformCodePatch.isPatched = false;

    m_minimapBoundCodePatch.name = "POE2_Minimap_CyanBound";
    m_minimapBoundCodePatch.originalBytes = { 0x0F, 0x97, 0xC0 };
    m_minimapBoundCodePatch.patchedBytes  = { 0x30, 0xC0, 0x90 };
    m_minimapBoundCodePatch.isPatched = false;

    if (m_reader.IsAttached()) {
        ModuleInfo mainMod;
        if (ResolveMainModule(m_reader.AttachedPid(), m_reader, mainMod)) {
            m_moduleBase = mainMod.base;
            m_moduleSize = mainMod.size;
            m_minimapGridCodePatch.address = m_moduleBase + kPoe2MinimapGridFillRva;
            m_minimapUniformCodePatch.address = m_moduleBase + kPoe2MinimapUniformRva;
            m_minimapBoundCodePatch.address = m_moduleBase + kPoe2MinimapBoundRva;
        }
    }
}

VisualModsEngine::~VisualModsEngine() {
    // Tự động hoàn nguyên an toàn khi đối tượng bị hủy
    PanicRestoreAll();
}

uintptr_t VisualModsEngine::CameraVtableAddress() const {
    if (m_cameraVtableOverride != 0) return m_cameraVtableOverride;
    if (m_moduleBase != 0) return m_moduleBase + kPoe2CameraVtableRva;
    if (m_reader.IsAttached()) {
        ModuleInfo mainMod;
        if (ResolveMainModule(m_reader.AttachedPid(), const_cast<IMemoryReader&>(m_reader), mainMod)) {
            return mainMod.base + kPoe2CameraVtableRva;
        }
    }
    return 0;
}

void VisualModsEngine::SetCameraAddress(uintptr_t addr) {
    if (m_cameraAddr != addr) {
        if (m_zoomActive) {
            RestoreCamera();
        }
        m_cameraAddr = addr;
        m_origCameraSaved = false;
        m_isPoe2Camera = false;
        if (m_cameraAddr >= 0x10000 && m_reader.IsAttached()) {
            float m00 = 0.0f, m11 = 0.0f;
            if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset, m00) &&
                m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset + 0x14, m11) &&
                m00 >= 0.5f && m00 <= 4.0f && m11 >= 0.5f && m11 <= 4.0f) {
                m_isPoe2Camera = true;
            } else {
                uint64_t vt = 0;
                if (m_reader.ReadValue<uint64_t>(m_cameraAddr, vt)) {
                    const uintptr_t expectedVt = CameraVtableAddress();
                    if (expectedVt != 0 && vt == expectedVt) {
                        m_isPoe2Camera = true;
                    }
                }
            }
            if (m_isPoe2Camera) {
                float z = 1.0f;
                if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, z)) {
                    m_origPoe2Zoom = (std::isnormal(z) && z > 0.1f && z <= 10.0f) ? z : 1.0f;
                } else {
                    m_origPoe2Zoom = 1.0f;
                }
            }
        }
    }
}

bool VisualModsEngine::IsPoe2Camera() const {
    if (m_isPoe2Camera) return true;
    if (m_cameraAddr >= 0x10000 && m_reader.IsAttached()) {
        float m00 = 0.0f, m11 = 0.0f;
        if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset, m00) &&
            m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset + 0x14, m11) &&
            m00 >= 0.5f && m00 <= 4.0f && m11 >= 0.5f && m11 <= 4.0f) {
            m_isPoe2Camera = true;
            return true;
        }
        uint64_t vt = 0;
        const uintptr_t expectedVt = CameraVtableAddress();
        if (expectedVt != 0 && m_reader.ReadValue<uint64_t>(m_cameraAddr, vt) && vt == expectedVt) {
            m_isPoe2Camera = true;
            return true;
        }
    }
    return false;
}

void VisualModsEngine::SetFogAddress(uintptr_t addr) {
    if (m_fogDensityAddr != addr) {
        if (m_fogDisabled) {
            RestoreFog();
        }
        m_fogDensityAddr = addr;
        m_origFogSaved = false;
    }
}

void VisualModsEngine::AddZoomClampAddress(uintptr_t addr) {
    if (addr == 0) return;
    if (m_zoomCodePatch.address == 0) {
        m_zoomCodePatch.address = addr;
        m_zoomCodePatch.name = "POE2_ZoomClamp_SSE";
    } else if (m_zoomCodePatch.address != addr) {
        for (const auto& rec : m_extraZoomCodePatches) {
            if (rec.address == addr) return;
        }
        CodePatchRecord rec;
        rec.address = addr;
        rec.name = "POE2_ZoomClamp_SSE_Extra";
        m_extraZoomCodePatches.push_back(rec);
    }
}

bool VisualModsEngine::EnsureOrigCameraSaved() {
    if (m_cameraAddr == 0 || !m_reader.IsAttached()) return false;
    if (m_origCameraSaved) return true;

    if (IsPoe2Camera()) {
        float curZoom = 1.0f;
        if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, curZoom)) {
            m_origPoe2Zoom = (std::isnormal(curZoom) && curZoom > 0.1f && curZoom <= 10.0f) ? curZoom : 1.0f;
        } else {
            m_origPoe2Zoom = 1.0f;
        }
        m_origCameraSaved = true;
        return true;
    }

    float curMaxDist = 0.0f;
    float curZFar = 0.0f;
    if (m_reader.ReadValue<float>(m_cameraAddr + 0x34, curMaxDist)) {
        // Trần đã hack (>90) không được làm orig — tránh nhân 4x chồng (45→180→720).
        m_origMaxDistance = (curMaxDist >= 8.0f && curMaxDist <= 90.0f) ? curMaxDist : 45.0f;
    } else {
        m_origMaxDistance = 45.0f;
    }

    if (m_reader.ReadValue<float>(m_cameraAddr + 0x40, curZFar)) {
        m_origZFar = (curZFar >= 20.0f && curZFar <= 400.0f) ? curZFar : 150.0f;
    } else {
        m_origZFar = 150.0f;
    }
    m_origCameraSaved = true;
    return true;
}

bool VisualModsEngine::WriteMaxAndZFar(float capMultiplier) {
    if (m_cameraAddr == 0 || !m_reader.IsAttached()) return false;
    const float cap = ClampVisualZoom(capMultiplier);
    const float targetMaxDist = VisualMaxDistanceTarget(m_origMaxDistance, cap);
    const float targetZFar = VisualZFarTarget(m_origZFar, cap);
    const bool okDist = m_reader.WriteValue<float>(m_cameraAddr + 0x34, targetMaxDist);
    const bool okZFar = m_reader.WriteValue<float>(m_cameraAddr + 0x40, targetZFar);
    return okDist || okZFar;
}

bool VisualModsEngine::WriteCurrentDistance(float multiplier) {
    if (m_cameraAddr == 0 || !m_reader.IsAttached()) return false;
    const float target = VisualMaxDistanceTarget(m_origMaxDistance, multiplier);
    return m_reader.WriteValue<float>(m_cameraAddr + 0x2C, target);
}

float VisualModsEngine::ReadLiveZoomMultiplier() const {
    if (m_cameraAddr == 0 || !m_reader.IsAttached()) {
        return m_currentZoomMultiplier;
    }
    if (IsPoe2Camera()) {
        float cur = 0.0f;
        if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, cur) && cur > 0.01f) {
            return cur;
        }
        return m_currentZoomMultiplier;
    }
    if (m_origMaxDistance <= 0.0f) {
        return m_currentZoomMultiplier;
    }
    float cur = 0.0f;
    if (!m_reader.ReadValue<float>(m_cameraAddr + 0x2C, cur)) {
        return m_currentZoomMultiplier;
    }
    return cur / m_origMaxDistance;
}

bool VisualModsEngine::CameraLooksValid(uintptr_t moduleBase, size_t moduleSize) const {
    if (m_cameraAddr < 0x10000 || !m_reader.IsAttached()) return false;

    const uintptr_t modBase = (moduleBase != 0) ? moduleBase : m_moduleBase;
    const size_t modSz = (moduleSize != 0) ? moduleSize : m_moduleSize;

    // 1. Kiểm tra ma trận chiếu 4x4 tại m_cameraAddr + kPoe2CameraMatrixOffset (+0x1A0)
    // Đọc float m00 (+0x1A0) và m11 (+0x1B4). Nếu m00 >= 0.5f && m00 <= 4.0f && m11 >= 0.5f && m11 <= 4.0f,
    // xác nhận đây là 3D Scene Camera thật!
    float m00 = 0.0f, m11 = 0.0f;
    if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset, m00) &&
        m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraMatrixOffset + 0x14, m11)) {
        if (m00 >= 0.5f && m00 <= 4.0f && m11 >= 0.5f && m11 <= 4.0f) {
            m_isPoe2Camera = true;
            return true;
        }
    }

    // 2. POE2 VTABLE check
    uint64_t vtable = 0;
    if (m_reader.ReadValue<uint64_t>(m_cameraAddr, vtable)) {
        const uintptr_t expectedVt = (m_cameraVtableOverride != 0) ? m_cameraVtableOverride :
                                     ((modBase != 0) ? (modBase + kPoe2CameraVtableRva) : CameraVtableAddress());
        if (expectedVt != 0 && vtable == expectedVt) {
            m_isPoe2Camera = true;
            return true;
        }
    }

    // 3. Fallback: Heuristic camera fields
    if (!m_isPoe2Camera) {
        float cur = 0, minD = 0, maxD = 0, fov = 0, zNear = 0, zFar = 0;
        if (m_reader.ReadValue<float>(m_cameraAddr + 0x2C, cur) &&
            m_reader.ReadValue<float>(m_cameraAddr + 0x30, minD) &&
            m_reader.ReadValue<float>(m_cameraAddr + 0x34, maxD) &&
            m_reader.ReadValue<float>(m_cameraAddr + 0x38, fov) &&
            m_reader.ReadValue<float>(m_cameraAddr + 0x3C, zNear) &&
            m_reader.ReadValue<float>(m_cameraAddr + 0x40, zFar)) {
            return LooksLikeCameraFields(vtable, cur, minD, maxD, fov, zNear, zFar, modBase, modSz, true);
        }
    }
    return false;
}

bool VisualModsEngine::ApplyZoom(float zoomMultiplier) {
    const float clampedMultiplier = ClampVisualZoom(zoomMultiplier);
    m_capUnlockOnly = false;
    m_wheelDriveActive = false;
    const float cap = (m_zoomCap > clampedMultiplier) ? m_zoomCap : kVisualZoomMax;
    m_currentZoomMultiplier = clampedMultiplier;

    if (IsPoe2Camera() && m_cameraAddr != 0) {
        EnsureOrigCameraSaved();
        const bool ok1 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, clampedMultiplier);
        const bool ok2 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, clampedMultiplier);
        ApplyZoomCodePatch(cap);
        m_zoomActive = true;
        std::cout << "[VisualMods] POE2 Camera Zoom Hack: " << clampedMultiplier
                  << "x (Offset +0x520=" << clampedMultiplier << ", +0x528=" << clampedMultiplier
                  << ") [ACTIVE]" << std::endl;
        return ok1 || ok2 || IsCodePatchActive();
    }

    if (!EnsureOrigCameraSaved()) return false;

    const bool okCur = WriteCurrentDistance(clampedMultiplier);
    const bool okLimits = WriteMaxAndZFar(clampedMultiplier);

    if (okCur || okLimits) {
        m_zoomActive = true;
        const float targetMaxDist = VisualMaxDistanceTarget(m_origMaxDistance, clampedMultiplier);
        const float targetZFar = VisualZFarTarget(m_origZFar, clampedMultiplier);
        std::cout << "[VisualMods] Camera Zoom Hack: " << clampedMultiplier
                  << "x (CurrentDistance=" << targetMaxDist
                  << ", MaxDistance=" << targetMaxDist
                  << ", zFar=" << targetZFar << ") [ACTIVE]" << std::endl;
        return true;
    }
    return false;
}

bool VisualModsEngine::UnlockZoomCap(float maxMultiplier) {
    const float cap = ClampVisualZoom(maxMultiplier);
    m_zoomCap = cap;
    m_capUnlockOnly = true;
    m_zoomActive = true;

    if (IsPoe2Camera() && m_cameraAddr != 0) {
        EnsureOrigCameraSaved();
        if (!IsCodePatchActive()) {
            ApplyZoomCodePatch(cap);
        }
        std::cout << "[VisualMods] POE2 UnlockZoomCap: " << cap << "x (Native Clamp NOP Active)" << std::endl;
        return true;
    }

    if (!EnsureOrigCameraSaved()) return false;

    const float live = ReadLiveZoomMultiplier();
    m_currentZoomMultiplier = (live >= kVisualZoomMin)
        ? (std::min)(cap, live)
        : kVisualZoomMin;

    if (!WriteMaxAndZFar(cap)) return false;

    const float targetMaxDist = VisualMaxDistanceTarget(m_origMaxDistance, cap);
    const float targetZFar = VisualZFarTarget(m_origZFar, cap);
    std::cout << "[VisualMods] UnlockZoomCap: " << cap
              << "x (MaxDistance=" << targetMaxDist
              << ", zFar=" << targetZFar
              << ", currentDistance giu nguyen) [CAP]" << std::endl;
    return true;
}

bool VisualModsEngine::SetZoomCap(float maxMultiplier) {
    const float cap = ClampVisualZoom(maxMultiplier);
    m_zoomCap = cap;
    m_zoomActive = true;
    m_capUnlockOnly = true;

    if (IsPoe2Camera() && m_cameraAddr != 0) {
        EnsureOrigCameraSaved();
        if (m_currentZoomMultiplier > cap) {
            m_currentZoomMultiplier = cap;
            m_wheelDriveActive = true;
            m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, m_currentZoomMultiplier);
            m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, m_currentZoomMultiplier);
        }
        return true;
    }

    if (!EnsureOrigCameraSaved()) return false;

    if (m_currentZoomMultiplier > cap) {
        m_currentZoomMultiplier = cap;
        m_wheelDriveActive = true;
        WriteCurrentDistance(m_currentZoomMultiplier);
    }
    return WriteMaxAndZFar(cap);
}

bool VisualModsEngine::StepZoom(float delta) {
    if (IsPoe2Camera() && m_cameraAddr != 0) {
        EnsureOrigCameraSaved();
        if (!m_zoomActive) {
            float liveZ = 1.0f;
            if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, liveZ) && liveZ >= 1.0f && liveZ <= kVisualZoomMax) {
                m_currentZoomMultiplier = liveZ;
            } else {
                m_currentZoomMultiplier = 1.0f;
            }
        }
        m_wheelDriveActive = true;
        m_zoomActive = true;
        const float cap = m_zoomCap > kVisualZoomMin ? m_zoomCap : kVisualZoomMax;
        float baseTarget = m_currentZoomMultiplier;
        float liveTarget = 0.0f;
        if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, liveTarget) && liveTarget >= 1.0f && liveTarget <= cap) {
            baseTarget = liveTarget;
        }
        m_currentZoomMultiplier = std::clamp(
            baseTarget + delta,
            kVisualZoomMin,
            cap);

        const bool ok1 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, m_currentZoomMultiplier);
        const bool ok2 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, m_currentZoomMultiplier);
        if (m_zoomCodePatch.address != 0 || !m_extraZoomCodePatches.empty()) {
            NopZoomClampInstruction(true);
        } else if (m_moduleBase != 0) {
            NopZoomClampInstruction(true);
        }
        return ok1 || ok2;
    }

    if (!EnsureOrigCameraSaved()) return false;

    if (!m_zoomActive) {
        if (!UnlockZoomCap(m_zoomCap > kVisualZoomMin ? m_zoomCap : kVisualZoomMax)) {
            return false;
        }
    }

    m_wheelDriveActive = true;
    m_currentZoomMultiplier = std::clamp(
        m_currentZoomMultiplier + delta,
        kVisualZoomMin,
        m_zoomCap);

    const bool okCur = WriteCurrentDistance(m_currentZoomMultiplier);
    // Duy trì trần maxDistance và zFar ở m_zoomCap (thay vì ghi đè m_currentZoomMultiplier khiến kẹp trần)
    const bool okLimits = WriteMaxAndZFar(m_zoomCap);
    return okCur || okLimits;
}

bool VisualModsEngine::WriteWithProtect(uintptr_t address, const void* buffer, size_t size) {
    if (address < 0x10000 || !buffer || size == 0) return false;
    return m_reader.Write(address, buffer, size);
}

bool VisualModsEngine::NopZoomClampInstruction(bool enable) {
    if (m_zoomCodePatch.address == 0) {
        ModuleInfo mainMod;
        const uint32_t pid = m_reader.AttachedPid();
        if (ResolveMainModule(pid, m_reader, mainMod) && mainMod.base != 0 && mainMod.size != 0) {
            auto pat = AobPattern::Parse("F3 0F 5D 0D ? ? ? ? F3 0F 11 8B 54 03 00 00");
            uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, pat, 4 * 1024 * 1024);
            if (hit) {
                m_zoomCodePatch.address = hit;
            }
        }
    }
    if (m_moduleBase != 0) {
        auto tryAddVerifiedClamp = [&](uintptr_t addr) {
            if (addr == 0 || !m_reader.IsAttached()) return;
            uint8_t probe[4] = {};
            if (m_reader.Read(addr, probe, 4) &&
                ((probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) ||
                 (probe[0] == 0x90 && probe[1] == 0x90))) {
                AddZoomClampAddress(addr);
            }
        };
        tryAddVerifiedClamp(m_moduleBase + kPoe2RealZoomClampRva);
        tryAddVerifiedClamp(m_moduleBase + kPoe2ZoomClampRva1);
        tryAddVerifiedClamp(m_moduleBase + kPoe2ZoomClampRva2);
    }
    if (m_zoomCodePatch.address == 0) return false;

    auto nopRecord = [&](CodePatchRecord& rec) -> bool {
        if (rec.address == 0) return false;
        if (enable) {
            if (rec.isPatched) return true;
            uint8_t probe[4] = {};
            if (m_reader.Read(rec.address, probe, 4) && probe[0] == 0x90 && probe[1] == 0x90) {
                rec.isPatched = true;
                return true;
            }
            if (rec.originalBytes.size() != 8) {
                rec.originalBytes.resize(8);
                m_reader.Read(rec.address, rec.originalBytes.data(), 8);
            }
            rec.patchedBytes.assign(8, 0x90);
            if (WriteWithProtect(rec.address, rec.patchedBytes.data(), 8)) {
                rec.isPatched = true;
                return true;
            }
            return false;
        } else {
            if (!rec.originalBytes.empty()) {
                if (WriteWithProtect(rec.address,
                                     rec.originalBytes.data(),
                                     rec.originalBytes.size())) {
                    rec.isPatched = false;
                    return true;
                }
                return false;
            }
            rec.isPatched = false;
            return true;
        }
    };

    bool anyOk = nopRecord(m_zoomCodePatch);
    for (auto& extra : m_extraZoomCodePatches) {
        if (nopRecord(extra)) anyOk = true;
    }

    if (enable) {
        if (anyOk) {
            m_nopClampInstruction = true;
            m_zoomActive = true;
        }
    } else {
        m_nopClampInstruction = false;
    }
    return anyOk;
}

bool VisualModsEngine::ApplyZoomCodePatch(float maxMultiplier) {
    if (!m_reader.IsAttached()) return false;

    const float cap = ClampVisualZoom(maxMultiplier);
    m_zoomCap = cap;

    // 1. Quét tìm clamp trong .text nếu chưa có địa chỉ (Multi-AOB + Context Sanity Verification)
    if (m_zoomCodePatch.address == 0 && m_maxZoomFloatAddr == 0) {
        ModuleInfo mainMod;
        const uint32_t pid = m_reader.AttachedPid();
        if (ResolveMainModule(pid, m_reader, mainMod) && mainMod.base != 0 && mainMod.size != 0) {
            // Thử mẫu POE2 Real Wheel Clamp trước
            auto realPat = AobPattern::Parse(kPoe2RealZoomClampPattern);
            uintptr_t realHit = AobScanner::ScanModule(m_reader, mainMod, realPat, 4 * 1024 * 1024);
            if (realHit != 0) {
                const uintptr_t clampAddr = realHit + 12;
                m_zoomCodePatch.address = clampAddr;
                m_zoomCodePatch.name = "POE2_RealZoomClamp_minss";
                uintptr_t floatTarget = AobScanner::ResolveRipTarget(m_reader, clampAddr, 4);
                if (floatTarget != 0) {
                    m_maxZoomFloatAddr = floatTarget;
                }
            } else {
                const std::string candidatePatterns[] = {
                    "F3 0F 5D 0D ? ? ? ? F3 0F 11 8B 54 03 00 00",
                    "F3 0F 5D 0D ? ? ? ? F3 0F 11 89 54 03 00 00",
                    "F3 0F 10 40 34 0F 2F",    // POE2 Direct Float Clamp fallback
                    "F3 0F 10 ? 34 0F 2F"      // POE2 Register Wildcard fallback
                };

                for (const auto& patStr : candidatePatterns) {
                    const AobPattern clampPat = AobPattern::Parse(patStr);
                    auto hits = AobScanner::ScanModuleHits(m_reader, mainMod, clampPat, 4 * 1024 * 1024, 8);
                    for (uintptr_t cand : hits) {
                        if (m_zoomCodePatch.address == 0) {
                            m_zoomCodePatch.address = cand;
                            m_zoomCodePatch.name = "ZoomClamp_" + patStr;

                            uint8_t probe[4] = {};
                            if (m_reader.Read(cand, probe, 4)) {
                                if (probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) {
                                    m_maxZoomFloatAddr = AobScanner::ResolveRipTarget(m_reader, cand, 4);
                                }
                            }
                            std::cout << "[VisualMods] Tim thay Zoom Clamp hop le tai .text @ 0x"
                                      << std::hex << cand << std::dec << " (Pattern: " << patStr << ")" << std::endl;
                        } else if (cand != m_zoomCodePatch.address) {
                            AddZoomClampAddress(cand);
                        }
                    }
                    if (m_zoomCodePatch.address != 0) break;
                }
            }

            if (m_zoomCodePatch.address == 0) {
                std::cout << "[VisualMods] Canh bao: Khong tim thay AOB clamp hop le trong .text."
                          << " Tu dong ha cap xuong che do Data-Only Heap Mode an toan!" << std::endl;
            }
        }
    }

    if (m_moduleBase != 0) {
        auto tryAddVerifiedClamp = [&](uintptr_t addr) {
            if (addr == 0 || !m_reader.IsAttached()) return;
            uint8_t probe[4] = {};
            if (m_reader.Read(addr, probe, 4) &&
                ((probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) ||
                 (probe[0] == 0x90 && probe[1] == 0x90))) {
                AddZoomClampAddress(addr);
            }
        };
        tryAddVerifiedClamp(m_moduleBase + kPoe2RealZoomClampRva);
        tryAddVerifiedClamp(m_moduleBase + kPoe2ZoomClampRva1);
        tryAddVerifiedClamp(m_moduleBase + kPoe2ZoomClampRva2);
    }

    // 2. Bảo toàn hằng số float trong .rdata (TUYỆT ĐỐI KHÔNG GHI ĐÈ FLOAT VÀO .RDATA)
    // Lý do kỹ thuật: Địa chỉ 0x7ff6b3229ca4 bị MSVC ICF (/OPT:ICF) gộp chung với hằng số 2.0f của UI.
    // Ghi đè float tại đây sẽ phá vỡ tỷ lệ giao diện game. Ta giữ nguyên 2.0f sạch sẽ 100%.
    if (m_maxZoomFloatAddr == 0 && m_zoomCodePatch.address != 0) {
        uint8_t probe[4] = {};
        if (m_reader.Read(m_zoomCodePatch.address, probe, 4)) {
            if (probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) {
                m_maxZoomFloatAddr = AobScanner::ResolveRipTarget(m_reader, m_zoomCodePatch.address, 4);
            }
        }
    }

    if (m_maxZoomFloatAddr != 0) {
        if (!m_origMaxZoomFloatSaved) {
            float curVal = 2.0f;
            if (m_reader.ReadValue<float>(m_maxZoomFloatAddr, curVal) && curVal > 0.0f && curVal <= 50.0f) {
                m_origMaxZoomFloat = curVal;
            } else {
                m_origMaxZoomFloat = 2.0f;
            }
            m_origMaxZoomFloatSaved = true;
        }

        // Đảm bảo .rdata luôn sạch sẽ, bảo toàn giá trị gốc 2.0f. Nếu bị lệch, tự động hoàn nguyên ngay.
        float currentVal = 0.0f;
        if (m_reader.ReadValue<float>(m_maxZoomFloatAddr, currentVal)) {
            if (std::abs(currentVal - m_origMaxZoomFloat) > 0.001f) {
                WriteWithProtect(m_maxZoomFloatAddr, &m_origMaxZoomFloat, sizeof(float));
                std::cout << "[VisualMods] Bao ve .rdata: Da khoi phuc hằng so float tai 0x"
                          << std::hex << m_maxZoomFloatAddr << std::dec << " ve "
                          << m_origMaxZoomFloat << "f (chong loi ty le UI do MSVC ICF)." << std::endl;
            }
        }
        m_maxZoomFloatPatched = false;
    }

    // 3. Xử lý Patching an toàn tại các địa chỉ code clamp trong .text
    bool anyCodePatched = false;
    auto patchClampInstruction = [&](CodePatchRecord& rec) -> bool {
        if (rec.address == 0) return false;
        uint8_t probe[4] = {};
        if (!m_reader.Read(rec.address, probe, 4)) return false;

        const bool isPoe1Legacy = (probe[0] == 0x80 && probe[1] == 0x78 && probe[2] == 0x2F && probe[3] == 0x00)
                               || (probe[0] == 0x80 && probe[2] == 0x2F && probe[3] == 0x00);
        if (isPoe1Legacy) {
            std::cout << "[VisualMods] CANH BAO AN TOAN: Phat hien mau POE1 legacy 80 78 2F 00 tai 0x"
                      << std::hex << rec.address << std::dec
                      << " -> VÔ HIỆU HÓA VÁ NOPs de chong crash 0xc0000005 tai 0x02bb83d2! Chuyen sang Safe Mode." << std::endl;
            rec.address = 0;
            rec.isPatched = false;
            return false;
        }

        if (probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) {
            // POE2 8-byte minss: F3 0F 5D 0D ? ? ? ?
            // Thay thế bằng 8 NOPs: Vô hiệu hóa lệnh kẹp 2.0f trong .text an toàn mà không làm thay đổi các hàm UI
            if (rec.originalBytes.size() != 8) {
                rec.originalBytes.resize(8);
                m_reader.Read(rec.address, rec.originalBytes.data(), 8);
            }
            rec.patchedBytes.assign(8, 0x90);
            if (WriteWithProtect(rec.address, rec.patchedBytes.data(), 8)) {
                rec.isPatched = true;
                std::cout << "[VisualMods] ApplyZoomCodePatch: Da NOP 8 byte minss tai 0x"
                          << std::hex << rec.address << std::dec
                          << " (Native Unclamp an toan, .rdata luon sach 2.0f)." << std::endl;
                return true;
            }
            return false;
        } else if (probe[0] == 0x90 && probe[1] == 0x90 && probe[2] == 0x90 && probe[3] == 0x90) {
            // Đã được NOP unclamp trước đó: giữ nguyên originalBytes, đánh dấu isPatched = true
            rec.isPatched = true;
            return true;
        } else {
            // Fallback: 4-byte clamp patch (như test 40d)
            if (rec.originalBytes.size() != 4) {
                rec.originalBytes.resize(4);
                m_reader.Read(rec.address, rec.originalBytes.data(), 4);
            }
            rec.patchedBytes.assign(4, 0x90);
            if (WriteWithProtect(rec.address, rec.patchedBytes.data(), 4)) {
                rec.isPatched = true;
                std::cout << "[VisualMods] ApplyZoomCodePatch: Da va clamp tai 0x"
                          << std::hex << rec.address << std::dec
                          << " (Native 144 FPS smooth zoom active)." << std::endl;
                return true;
            }
            return false;
        }
    };

    if (patchClampInstruction(m_zoomCodePatch)) {
        anyCodePatched = true;
    }
    for (auto& extra : m_extraZoomCodePatches) {
        if (patchClampInstruction(extra)) {
            anyCodePatched = true;
        }
    }

    if (anyCodePatched) {
        m_zoomActive = true;
        m_capUnlockOnly = true;
    }

    // 4. Fallback / Safe Mode: Cập nhật limits trên heap nếu camera instance đã sẵn sàng
    if (m_cameraAddr != 0) {
        if (IsPoe2Camera()) {
            EnsureOrigCameraSaved();
            m_zoomActive = true;
            m_capUnlockOnly = true;
            m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, m_currentZoomMultiplier);
            m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, m_currentZoomMultiplier);
        } else {
            EnsureOrigCameraSaved();
            m_zoomActive = true;
            m_capUnlockOnly = true;
            WriteMaxAndZFar(cap);
        }
    }

    return anyCodePatched || m_zoomActive;
}

bool VisualModsEngine::RestoreZoomCodePatch() {
    bool ok = true;

    // 1. Đảm bảo float 2.0f trong .rdata luôn sạch sẽ, không bị ô nhiễm
    if (m_maxZoomFloatAddr != 0) {
        float curVal = 0.0f;
        if (m_reader.ReadValue<float>(m_maxZoomFloatAddr, curVal)) {
            if (std::abs(curVal - m_origMaxZoomFloat) > 0.001f) {
                if (WriteWithProtect(m_maxZoomFloatAddr, &m_origMaxZoomFloat, sizeof(float))) {
                    std::cout << "[VisualMods] RestoreZoomCodePatch: Da hoan nguyen float max zoom ve "
                              << m_origMaxZoomFloat << "f tai 0x" << std::hex << m_maxZoomFloatAddr << std::dec << std::endl;
                } else {
                    ok = false;
                }
            }
        }
        m_maxZoomFloatPatched = false;
    }

    // 2. Hoàn nguyên byte gốc của lệnh minss (F3 0F 5D 0D ...) trong 1 khung hình
    if (m_zoomCodePatch.address == 0 && m_moduleBase != 0) {
        m_zoomCodePatch.address = m_moduleBase + kPoe2RealZoomClampRva;
    }
    if (m_zoomCodePatch.isPatched && m_zoomCodePatch.address != 0 && !m_zoomCodePatch.originalBytes.empty()) {
        if (WriteWithProtect(m_zoomCodePatch.address,
                             m_zoomCodePatch.originalBytes.data(),
                             m_zoomCodePatch.originalBytes.size())) {
            m_zoomCodePatch.isPatched = false;
            std::cout << "[VisualMods] RestoreZoomCodePatch: Da hoan nguyen byte clamp tai 0x"
                      << std::hex << m_zoomCodePatch.address << std::dec
                      << " sach se 100%." << std::endl;
        } else {
            std::cerr << "[VisualMods] RestoreZoomCodePatch: Hoan nguyen that bai tai 0x"
                      << std::hex << m_zoomCodePatch.address << std::dec << std::endl;
            ok = false;
        }
    }
    m_zoomCodePatch.isPatched = false;

    // 3. Hoàn nguyên các clamp address phụ (nếu có)
    for (auto& extra : m_extraZoomCodePatches) {
        if (extra.isPatched && extra.address != 0 && !extra.originalBytes.empty()) {
            if (WriteWithProtect(extra.address, extra.originalBytes.data(), extra.originalBytes.size())) {
                extra.isPatched = false;
            } else {
                ok = false;
            }
        }
        extra.isPatched = false;
    }

    m_nopClampInstruction = false;
    return ok;
}

bool VisualModsEngine::RestoreCamera() {
    if (!m_zoomActive || m_cameraAddr == 0) return false;

    if (IsPoe2Camera()) {
        const float resetVal = 1.0f;
        const bool ok1 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, resetVal);
        const bool ok2 = m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, resetVal);
        m_zoomActive = false;
        m_capUnlockOnly = false;
        m_wheelDriveActive = false;
        m_currentZoomMultiplier = 1.0f;
        m_zoomCap = kVisualZoomMin;

        // Khôi phục byte gốc của lệnh minss tại 0x7FF6AFD8D5FC (modBase + kPoe2RealZoomClampRva)
        RestoreZoomCodePatch();

        std::cout << "[VisualMods] POE2 Camera đã hoàn nguyên về mặc định gốc (Zoom="
                  << resetVal << "f)." << std::endl;
        return (ok1 || ok2);
    }

    const bool okCur  = m_reader.WriteValue<float>(m_cameraAddr + 0x2C, m_origMaxDistance);
    const bool okDist = m_reader.WriteValue<float>(m_cameraAddr + 0x34, m_origMaxDistance);
    const bool okZFar = m_reader.WriteValue<float>(m_cameraAddr + 0x40, m_origZFar);

    m_zoomActive = false;
    m_capUnlockOnly = false;
    m_wheelDriveActive = false;
    m_currentZoomMultiplier = 1.0f;
    m_zoomCap = kVisualZoomMin;
    std::cout << "[VisualMods] Camera đã hoàn nguyên về mặc định gốc (CurrentDist="
              << m_origMaxDistance << ", MaxDist="
              << m_origMaxDistance << ", zFar=" << m_origZFar << ")." << std::endl;
    return (okCur && okDist && okZFar);
}

void VisualModsEngine::Maintain() {
    if (!m_reader.IsAttached()) return;

    // Đảm bảo hằng số float 2.0f trong .rdata luôn sạch sẽ, không bị ô nhiễm (chống lỗi tỷ lệ UI do MSVC ICF)
    if (m_maxZoomFloatAddr != 0) {
        float curVal = 0.0f;
        if (m_reader.ReadValue<float>(m_maxZoomFloatAddr, curVal)) {
            if (std::abs(curVal - m_origMaxZoomFloat) > 0.001f) {
                WriteWithProtect(m_maxZoomFloatAddr, &m_origMaxZoomFloat, sizeof(float));
            }
        }
        m_maxZoomFloatPatched = false;
    }

    // Duy trì Code Patching cho Zoom Clamp trong .text nếu bị game nạp lại
    auto maintainClampRecord = [&](const CodePatchRecord& rec) {
        if (rec.isPatched && rec.address != 0 && !rec.patchedBytes.empty()) {
            std::vector<uint8_t> probe(rec.patchedBytes.size());
            if (m_reader.Read(rec.address, probe.data(), probe.size())) {
                if (probe != rec.patchedBytes) {
                    WriteWithProtect(rec.address, rec.patchedBytes.data(), rec.patchedBytes.size());
                }
            }
        }
    };
    maintainClampRecord(m_zoomCodePatch);
    for (const auto& extra : m_extraZoomCodePatches) {
        maintainClampRecord(extra);
    }
    maintainClampRecord(m_minimapGridCodePatch);
    maintainClampRecord(m_minimapUniformCodePatch);
    maintainClampRecord(m_minimapBoundCodePatch);

    if (m_zoomActive && m_cameraAddr != 0) {
        if (!CameraLooksValid()) {
            return;
        }
        if (IsPoe2Camera()) {
            const float cap = m_zoomCap > kVisualZoomMin ? m_zoomCap : kVisualZoomMax;
            float curTarget = 0.0f;
            if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, curTarget)) {
                if (curTarget > cap) {
                    m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, cap);
                    curTarget = cap;
                }
            }
            float curVal = 0.0f;
            if (m_reader.ReadValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, curVal)) {
                if (curVal > cap) {
                    m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, cap);
                } else if (!m_capUnlockOnly && std::abs(curVal - m_currentZoomMultiplier) > 0.01f) {
                    m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomOffset, m_currentZoomMultiplier);
                    m_reader.WriteValue<float>(m_cameraAddr + kPoe2CameraZoomTargetOffset, m_currentZoomMultiplier);
                }
            }
        } else {
            const float capForLimits = (m_capUnlockOnly || m_wheelDriveActive)
                ? m_zoomCap
                : m_currentZoomMultiplier;
            const float targetMaxDist = VisualMaxDistanceTarget(m_origMaxDistance, capForLimits);
            const float targetZFar = VisualZFarTarget(m_origZFar, capForLimits);

            float curMaxDist = 0.0f;
            if (m_reader.ReadValue<float>(m_cameraAddr + 0x34, curMaxDist)) {
                if (std::abs(curMaxDist - targetMaxDist) > 0.5f) {
                    const bool w2 = m_reader.WriteValue<float>(m_cameraAddr + 0x34, targetMaxDist);
                    const bool w3 = m_reader.WriteValue<float>(m_cameraAddr + 0x40, targetZFar);
                    if (w2 || w3) {
                        std::cout << "[VisualMods] Maintain: Đã tự động khôi phục Camera Zoom "
                                  << (m_capUnlockOnly ? "Cap " : "Hack ")
                                  << capForLimits << "x (targetMax=" << targetMaxDist
                                  << ", zFar=" << targetZFar << ") thành công!" << std::endl;
                    }
                }
            }
            // Không ghim currentDistance: game / lăn lên phải thu góc được.
            if (!m_capUnlockOnly) {
                WriteCurrentDistance(m_currentZoomMultiplier);
            }
        }
    }

    // Duy trì loại bỏ Atlas Fog nếu bị game nạp lại
    if (m_fogCodePatch.isPatched && m_fogCodePatch.address != 0) {
        uint8_t probe[5] = {};
        if (m_reader.Read(m_fogCodePatch.address, probe, 5)) {
            if (probe[0] != 0x90) {
                const uint8_t nops[5] = {0x90, 0x90, 0x90, 0x90, 0x90};
                WriteWithProtect(m_fogCodePatch.address, nops, 5);
            }
        }
    }

    // Duy trì loại bỏ sương mù (Volumetric Fog)
    if (m_fogDisabled && m_fogDensityAddr != 0) {
        float curFog = 0.0f;
        if (m_reader.ReadValue<float>(m_fogDensityAddr, curFog)) {
            if (curFog > 0.0f) {
                const float zero = 0.0f;
                if (m_reader.WriteValue<float>(m_fogDensityAddr, zero)) {
                    std::cout << "[VisualMods] Maintain: Đã tự động khôi phục Volumetric Fog = 0.0f thành công!" << std::endl;
                }
            }
        }
    }

    // Tự động mở sáng toàn bộ Minimap (Auto-Reveal Minimap)
    if (m_autoRevealMinimap && m_reader.IsAttached()) {
        if (!AreMinimapShaderPatchesActive()) {
            ApplyMinimapShaderPatches();
        }
        uintptr_t modBase = m_moduleBase;
        if (modBase == 0) {
            ModuleInfo mainMod;
            if (ResolveMainModule(m_reader.AttachedPid(), const_cast<IMemoryReader&>(m_reader), mainMod)) {
                modBase = mainMod.base;
                m_moduleBase = mainMod.base;
                m_moduleSize = mainMod.size;
            }
        }
        if (modBase != 0) {
            uintptr_t inGameState = 0;
            if (m_reader.ReadValue<uintptr_t>(modBase + kPoe2InGameStateStaticRva, inGameState) && inGameState >= 0x10000) {
                uintptr_t areaInstance = 0;
                if (!m_reader.ReadValue<uintptr_t>(inGameState + kPoe2AreaInstanceOffset, areaInstance) || areaInstance < 0x10000) {
                    m_reader.ReadValue<uintptr_t>(inGameState + 0x2A0, areaInstance);
                }
                if (areaInstance >= 0x10000) {
                    const auto now = std::chrono::steady_clock::now();
                    if (areaInstance != m_lastRevealedAreaInstance) {
                        if (RevealEntireMinimap()) {
                            m_lastRevealedAreaInstance = areaInstance;
                            m_lastRevealCheckTime = now;
                        }
                    } else if (std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastRevealCheckTime).count() >= 2000) {
                        uintptr_t pExpl = 0;
                        uintptr_t pExplEnd = 0;
                        uintptr_t pTerr = 0;
                        if (m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2ExplorationBufferOffset, pExpl) &&
                            m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2ExplorationBufferOffset + 8, pExplEnd) &&
                            m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2TerrainBufferOffset, pTerr)) {
                            if (pExpl >= 0x10000 && pExplEnd > pExpl && pTerr >= 0x10000) {
                                const size_t sz = static_cast<size_t>(pExplEnd - pExpl);
                                if (sz > 1000 && sz <= 16 * 1024 * 1024) {
                                    uint8_t explSample[64] = {};
                                    uint8_t terrSample[64] = {};
                                    const uintptr_t sampleOffset = sz / 2;
                                    if (m_reader.Read(pExpl + sampleOffset, explSample, sizeof(explSample)) &&
                                        m_reader.Read(pTerr + sampleOffset, terrSample, sizeof(terrSample))) {
                                        if (std::memcmp(explSample, terrSample, sizeof(explSample)) != 0) {
                                            RevealEntireMinimap();
                                        }
                                    }
                                }
                            }
                        }
                        m_lastRevealCheckTime = now;
                    }
                }
            }
        }
    }
}

bool VisualModsEngine::DisableFog() {
    if (!m_reader.IsAttached()) return false;

    bool patchedAtlas = false;
    // 1. Quét mẫu Atlas Fog SSE trong .text nếu chưa có
    if (m_fogCodePatch.address == 0) {
        ModuleInfo mainMod;
        const uint32_t pid = m_reader.AttachedPid();
        if (ResolveMainModule(pid, m_reader, mainMod) && mainMod.base != 0 && mainMod.size != 0) {
            auto fogPat = AobPattern::Parse("F3 0F 59 51 ? F3 0F 58 C1 F3 0F 58 C2 C3");
            uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, fogPat, 4 * 1024 * 1024);
            if (hit != 0) {
                m_fogCodePatch.address = hit;
                m_fogCodePatch.name = "POE2_AtlasFog_SSE";
            }
        }
    }

    // 2. Ghi 5 NOPs vào Atlas Fog
    if (m_fogCodePatch.address != 0 && !m_fogCodePatch.isPatched) {
        constexpr size_t kFogPatchSize = 5;
        if (m_fogCodePatch.originalBytes.size() != kFogPatchSize) {
            m_fogCodePatch.originalBytes.resize(kFogPatchSize);
            m_reader.Read(m_fogCodePatch.address, m_fogCodePatch.originalBytes.data(), kFogPatchSize);
        }
        m_fogCodePatch.patchedBytes.assign(kFogPatchSize, 0x90);
        if (WriteWithProtect(m_fogCodePatch.address, m_fogCodePatch.patchedBytes.data(), kFogPatchSize)) {
            m_fogCodePatch.isPatched = true;
            m_fogDisabled = true;
            patchedAtlas = true;
            std::cout << "[VisualMods] POE2 Atlas Fog Disabled: Da ghi 5 NOPs tai 0x"
                      << std::hex << m_fogCodePatch.address << std::dec << " [VIRTUALPROTECTEX OK]." << std::endl;
        }
    }

    // 3. Volumetric fog fallback nếu có fogDensityAddr
    bool volumetricDone = false;
    if (m_fogDensityAddr != 0) {
        if (!m_origFogSaved) {
            float curDensity = 1.0f;
            if (m_reader.ReadValue<float>(m_fogDensityAddr, curDensity)) {
                m_origFogDensity = (curDensity > 0.0f && curDensity <= 10.0f) ? curDensity : 1.0f;
            } else {
                m_origFogDensity = 1.0f;
            }
            m_origFogSaved = true;
        }
        const float zeroDensity = 0.0f;
        if (m_reader.WriteValue<float>(m_fogDensityAddr, zeroDensity)) {
            m_fogDisabled = true;
            volumetricDone = true;
            std::cout << "[VisualMods] Volumetric Fog Disabled (FogDensity = 0.0f - Tăng 15-20% FPS)." << std::endl;
        }
    }

    return patchedAtlas || volumetricDone || m_fogCodePatch.isPatched || m_fogDisabled;
}

bool VisualModsEngine::RestoreFog() {
    bool ok = true;

    // 1. Khôi phục 5 byte gốc của Atlas Fog
    if (m_fogCodePatch.isPatched && m_fogCodePatch.address != 0) {
        if (!m_fogCodePatch.originalBytes.empty()) {
            if (WriteWithProtect(m_fogCodePatch.address,
                                 m_fogCodePatch.originalBytes.data(),
                                 m_fogCodePatch.originalBytes.size())) {
                m_fogCodePatch.isPatched = false;
                std::cout << "[VisualMods] Atlas Fog da hoan nguyen 5 byte goc tai 0x"
                          << std::hex << m_fogCodePatch.address << std::dec << " sach se 100%." << std::endl;
            } else {
                ok = false;
            }
        }
        m_fogCodePatch.isPatched = false;
    }

    // 2. Khôi phục Volumetric Fog
    if (m_fogDensityAddr != 0) {
        if (!m_reader.WriteValue<float>(m_fogDensityAddr, m_origFogDensity)) {
            ok = false;
        } else {
            std::cout << "[VisualMods] Volumetric Fog đã hoàn nguyên về mặc định gốc (FogDensity="
                      << m_origFogDensity << ")." << std::endl;
        }
    }

    m_fogDisabled = false;
    return ok;
}

bool VisualModsEngine::AreMinimapShaderPatchesActive() const {
    return m_minimapGridCodePatch.isPatched ||
           m_minimapUniformCodePatch.isPatched ||
           m_minimapBoundCodePatch.isPatched;
}

bool VisualModsEngine::ApplyMinimapShaderPatches() {
    if (!m_reader.IsAttached()) return false;

    uintptr_t modBase = m_moduleBase;
    if (modBase == 0) {
        ModuleInfo mainMod;
        if (ResolveMainModule(m_reader.AttachedPid(), const_cast<IMemoryReader&>(m_reader), mainMod)) {
            modBase = mainMod.base;
            m_moduleBase = mainMod.base;
            m_moduleSize = mainMod.size;
        }
    }

    if (m_minimapGridCodePatch.address == 0 && modBase != 0) {
        m_minimapGridCodePatch.address = modBase + kPoe2MinimapGridFillRva;
    }
    if (m_minimapUniformCodePatch.address == 0 && modBase != 0) {
        m_minimapUniformCodePatch.address = modBase + kPoe2MinimapUniformRva;
    }
    if (m_minimapBoundCodePatch.address == 0 && modBase != 0) {
        m_minimapBoundCodePatch.address = modBase + kPoe2MinimapBoundRva;
    }

    auto applyPatch = [this](CodePatchRecord& rec) -> bool {
        if (rec.address == 0) return false;
        if (rec.isPatched) return true;

        std::vector<uint8_t> probe(rec.patchedBytes.size());
        if (m_reader.Read(rec.address, probe.data(), probe.size())) {
            if (probe == rec.patchedBytes) {
                rec.isPatched = true;
                return true;
            }
            if (rec.originalBytes.empty() || probe == rec.originalBytes) {
                rec.originalBytes = probe;
            }
        }

        if (WriteWithProtect(rec.address, rec.patchedBytes.data(), rec.patchedBytes.size())) {
            rec.isPatched = true;
            return true;
        }
        return false;
    };

    bool ok1 = applyPatch(m_minimapGridCodePatch);
    bool ok2 = applyPatch(m_minimapUniformCodePatch);
    bool ok3 = applyPatch(m_minimapBoundCodePatch);

    if (ok1 || ok2 || ok3) {
        std::cout << "[VisualMods] Da ap dung Bo 3 Minimap Shader Patches (GPU Shader & CPU Grid bao hoa)!" << std::endl;
    }
    return (ok1 && ok2 && ok3);
}

bool VisualModsEngine::RestoreMinimapShaderPatches() {
    auto restorePatch = [this](CodePatchRecord& rec) -> bool {
        if (rec.address == 0) {
            rec.isPatched = false;
            return true;
        }
        if (!rec.originalBytes.empty()) {
            if (WriteWithProtect(rec.address, rec.originalBytes.data(), rec.originalBytes.size())) {
                rec.isPatched = false;
                return true;
            }
            return false;
        }
        rec.isPatched = false;
        return true;
    };

    bool ok1 = restorePatch(m_minimapGridCodePatch);
    bool ok2 = restorePatch(m_minimapUniformCodePatch);
    bool ok3 = restorePatch(m_minimapBoundCodePatch);

    m_minimapGridCodePatch.isPatched = false;
    m_minimapUniformCodePatch.isPatched = false;
    m_minimapBoundCodePatch.isPatched = false;

    if (ok1 && ok2 && ok3) {
        std::cout << "[VisualMods] Da hoan nguyen Bo 3 Minimap Shader Patches ve byte goc!" << std::endl;
    }
    return (ok1 && ok2 && ok3);
}

bool VisualModsEngine::RevealEntireMinimap() {
    if (!m_reader.IsAttached()) return false;

    uintptr_t modBase = m_moduleBase;
    if (modBase == 0) {
        ModuleInfo mainMod;
        if (ResolveMainModule(m_reader.AttachedPid(), const_cast<IMemoryReader&>(m_reader), mainMod)) {
            modBase = mainMod.base;
            m_moduleBase = mainMod.base;
            m_moduleSize = mainMod.size;
        }
    }
    if (modBase == 0) return false;

    // 1. Đọc InGameState từ modBase + kPoe2InGameStateStaticRva (0x4430108)
    uintptr_t inGameState = 0;
    if (!m_reader.ReadValue<uintptr_t>(modBase + kPoe2InGameStateStaticRva, inGameState) || inGameState < 0x10000) {
        return false;
    }

    // 2. Đọc AreaInstance từ InGameState + 0x290 (kPoe2AreaInstanceOffset)
    uintptr_t areaInstance = 0;
    if (!m_reader.ReadValue<uintptr_t>(inGameState + kPoe2AreaInstanceOffset, areaInstance) || areaInstance < 0x10000) {
        if (!m_reader.ReadValue<uintptr_t>(inGameState + 0x2A0, areaInstance) || areaInstance < 0x10000) {
            return false;
        }
    }

    // 3. Đọc pExpl (+0x9d0), pTerr (+0x9b8), và pColl (+0x9a0) từ AreaInstance
    uintptr_t pExpl = 0;
    uintptr_t pExplEnd = 0;
    uintptr_t pTerr = 0;
    uintptr_t pColl = 0;
    if (!m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2ExplorationBufferOffset, pExpl)) return false;
    if (!m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2ExplorationBufferOffset + 8, pExplEnd)) return false;
    if (!m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2TerrainBufferOffset, pTerr)) return false;
    m_reader.ReadValue<uintptr_t>(areaInstance + kPoe2CollisionBufferOffset, pColl);

    if (pExpl < 0x10000 || pExplEnd <= pExpl) return false;

    const size_t sz = static_cast<size_t>(pExplEnd - pExpl);

    // 4. Kiểm tra tính hợp lệ: sz > 1000 && sz <= 16 * 1024 * 1024 && pTerr >= 0x10000
    if (sz <= 1000 || sz > 16 * 1024 * 1024 || pTerr < 0x10000) {
        return false;
    }

    // 5. Đọc từng khối chunkSize = 256 * 1024 từ pTerr và ghi sang pExpl (0x9d0) và pColl (0x9a0)
    constexpr size_t kChunkSize = 256 * 1024;
    std::vector<uint8_t> chunk(kChunkSize);
    for (size_t offset = 0; offset < sz; offset += kChunkSize) {
        const size_t toCopy = (std::min)(kChunkSize, sz - offset);
        if (!m_reader.Read(pTerr + offset, chunk.data(), toCopy)) {
            return false;
        }
        if (!m_reader.Write(pExpl + offset, chunk.data(), toCopy)) {
            return false;
        }
        if (pColl >= 0x10000) {
            m_reader.Write(pColl + offset, chunk.data(), toCopy);
        }
    }

    m_lastRevealedAreaInstance = areaInstance;
    m_lastRevealCheckTime = std::chrono::steady_clock::now();

    // Bão hòa cả GPU DirectX Shader Pipeline (Doc 43)
    ApplyMinimapShaderPatches();

    if (m_onMinimapRevealed) {
        m_onMinimapRevealed();
    }

    std::cout << "[VisualMods] RevealEntireMinimap: Da bao hoa " << sz
              << " bytes tu TerrainBuffer (+0x9b8) sang ExplorationBuffer (+0x9d0) (pExpl=0x"
              << std::hex << pExpl << ", pTerr=0x" << pTerr << ")" << std::dec << std::endl;
    return true;
}

bool VisualModsEngine::StepMinimapZoom(int delta) {
    if (delta == 0) return true;

    // Tìm cửa sổ game POE2
    HWND poe = FindWindowW(L"POEWindowClass", nullptr);
    if (!poe) poe = FindWindowW(nullptr, L"Path of Exile 2");
    if (!poe) poe = FindWindowW(nullptr, L"Path of Exile");
    if (!poe) poe = FindWindowW(L"POEC2_MainWindow", nullptr);
    if (!poe) return false;

    // Focus Interlock (Rule 8): Chỉ gửi input khi game window đang foreground
    HWND fg = GetForegroundWindow();
    if (fg != poe && !IsChild(poe, fg)) {
        return false;
    }

    const WORD vk = (delta > 0) ? VK_ADD : VK_SUBTRACT;
    const int count = (std::min)(std::abs(delta), 10);

    for (int i = 0; i < count; ++i) {
        INPUT inputs[2] = {};
        inputs[0].type = INPUT_KEYBOARD;
        inputs[0].ki.wVk = vk;
        inputs[0].ki.wScan = static_cast<WORD>(MapVirtualKeyW(vk, MAPVK_VK_TO_VSC));
        inputs[0].ki.dwFlags = 0;

        inputs[1].type = INPUT_KEYBOARD;
        inputs[1].ki.wVk = vk;
        inputs[1].ki.wScan = inputs[0].ki.wScan;
        inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;

        UINT sent = SendInput(2, inputs, sizeof(INPUT));
        if (sent != 2) {
            return false;
        }
        if (i + 1 < count) {
            Sleep(15);
        }
    }
    return true;
}

void VisualModsEngine::PanicRestoreAll() {
    RestoreZoomCodePatch();
    RestoreMinimapShaderPatches();
    if (m_zoomActive) {
        RestoreCamera();
    }
    if (m_fogDisabled || m_fogCodePatch.isPatched) {
        RestoreFog();
    }
}

void VisualModsEngine::LoadFromOffsetsStore(const OffsetsStore& store, uintptr_t moduleBase, size_t moduleSize) {
    if (moduleBase != 0) {
        m_moduleBase = moduleBase;
        m_moduleSize = moduleSize;
    } else if (m_moduleBase == 0 && m_reader.IsAttached()) {
        ModuleInfo mainMod;
        if (ResolveMainModule(m_reader.AttachedPid(), m_reader, mainMod)) {
            m_moduleBase = mainMod.base;
            m_moduleSize = mainMod.size;
        }
    }

    const uintptr_t effBase = (moduleBase != 0) ? moduleBase : m_moduleBase;
    // INV-OFFSET-01: không nạp camera_addr / fog_density_addr heap tuyệt đối.
    if (store.Has("camera_rva") && effBase != 0) {
        SetCameraAddress(effBase + store.Get("camera_rva"));
    }

    if (store.Has("fog_density_rva") && effBase != 0) {
        SetFogAddress(effBase + store.Get("fog_density_rva"));
    }
}

bool VisualModsEngine::AutoDetect(uint32_t pid, OffsetsStore* store) {
    if (!m_reader.IsAttached()) return false;
    if (pid == 0) pid = m_reader.AttachedPid();
    if (pid == 0) pid = FindPoeProcessId();

    ModuleInfo mainMod;
    const bool hasMod = ResolveMainModule(pid, m_reader, mainMod);
    const uintptr_t modBase = hasMod ? mainMod.base : 0;
    const size_t modSize = hasMod ? mainMod.size : 0;
    if (hasMod) {
        m_moduleBase = mainMod.base;
        m_moduleSize = mainMod.size;
    }

    if (m_cameraAddr != 0 && !CameraLooksValid(modBase, modSize)) {
        SetCameraAddress(0);
    }
    if (m_fogDensityAddr != 0 && !LooksLikeFogAt(m_reader, m_fogDensityAddr)) {
        SetFogAddress(0);
    }

    bool foundAny = false;

    // 1. POE2 InGameState Camera chain:
    // Đọc inGameState = *(uintptr_t*)(modBase + kPoe2InGameStateStaticRva).
    // Nếu inGameState >= 0x10000, đọc camPtr = *(uintptr_t*)(inGameState + kPoe2CameraInGameStateOffset).
    // Nếu camPtr >= 0x10000 và CameraLooksValid() xác nhận ma trận chiếu hợp lệ tại +0x1A0, gán ngay SetCameraAddress(camPtr).
    if (hasMod && modBase != 0 && m_cameraAddr == 0) {
        uintptr_t inGameState = 0;
        if (m_reader.ReadValue<uintptr_t>(modBase + kPoe2InGameStateStaticRva, inGameState) &&
            inGameState >= 0x10000) {
            uintptr_t camPtr = 0;
            if (m_reader.ReadValue<uintptr_t>(inGameState + kPoe2CameraInGameStateOffset, camPtr) &&
                camPtr >= 0x10000) {
                float m00 = 0.0f, m11 = 0.0f;
                if (m_reader.ReadValue<float>(camPtr + kPoe2CameraMatrixOffset, m00) &&
                    m_reader.ReadValue<float>(camPtr + kPoe2CameraMatrixOffset + 0x14, m11) &&
                    m00 >= 0.5f && m00 <= 4.0f && m11 >= 0.5f && m11 <= 4.0f) {
                    SetCameraAddress(camPtr);
                    m_isPoe2Camera = true;
                    foundAny = true;
                    std::cout << "[VisualMods] AutoDetect: Phat hien POE2 Camera qua InGameState static RVA @ 0x"
                              << std::hex << camPtr << std::dec << " (m00=" << m00 << ", m11=" << m11 << ")" << std::endl;
                }
            }
        }
    }

    // 2. Quét AOB Wheel Clamp bằng kPoe2RealZoomClampPattern (hoặc kiểm tra modBase + kPoe2RealZoomClampRva)
    // Vị trí cần patch là lệnh minss xmm1, [rip+disp] (8 byte bắt đầu tại offset 12 của pattern).
    // Gán địa chỉ vào m_zoomCodePatch.address.
    if (hasMod && modBase != 0 && m_zoomCodePatch.address == 0) {
        auto realPat = AobPattern::Parse(kPoe2RealZoomClampPattern);
        uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, realPat, 4 * 1024 * 1024);
        if (hit != 0) {
            const uintptr_t clampAddr = hit + 12;
            m_zoomCodePatch.address = clampAddr;
            m_zoomCodePatch.name = "POE2_RealZoomClamp_minss";
            if (m_zoomCodePatch.originalBytes.size() != 8) {
                m_zoomCodePatch.originalBytes.resize(8);
                m_reader.Read(clampAddr, m_zoomCodePatch.originalBytes.data(), 8);
            }
            uint8_t probe[4] = {};
            if (m_reader.Read(clampAddr, probe, 4)) {
                if (probe[0] == 0x90 && probe[1] == 0x90) {
                    m_zoomCodePatch.isPatched = true;
                }
            }
            uintptr_t floatTarget = AobScanner::ResolveRipTarget(m_reader, clampAddr, 4);
            if (floatTarget != 0) {
                m_maxZoomFloatAddr = floatTarget;
                float val = 0.0f;
                if (m_reader.ReadValue<float>(floatTarget, val) && val > 0.0f && val <= 50.0f) {
                    m_origMaxZoomFloat = val;
                    m_origMaxZoomFloatSaved = true;
                }
            }
            foundAny = true;
            std::cout << "[VisualMods] AutoDetect: Tim thay POE2 Real Zoom Clamp AOB tai 0x"
                      << std::hex << hit << " -> minss @ 0x" << clampAddr << std::dec << std::endl;
        } else {
            const uintptr_t rvaClamp = modBase + kPoe2RealZoomClampRva;
            uint8_t probe[4] = {};
            if (m_reader.Read(rvaClamp, probe, 4)) {
                if ((probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) ||
                    (probe[0] == 0x90 && probe[1] == 0x90)) {
                    m_zoomCodePatch.address = rvaClamp;
                    m_zoomCodePatch.name = "POE2_RealZoomClamp_Rva";
                    if (m_zoomCodePatch.originalBytes.size() != 8) {
                        m_zoomCodePatch.originalBytes.resize(8);
                        m_reader.Read(rvaClamp, m_zoomCodePatch.originalBytes.data(), 8);
                    }
                    if (probe[0] == 0x90 && probe[1] == 0x90) {
                        m_zoomCodePatch.isPatched = true;
                    }
                    uintptr_t floatTarget = AobScanner::ResolveRipTarget(m_reader, rvaClamp, 4);
                    if (floatTarget != 0) {
                        m_maxZoomFloatAddr = floatTarget;
                    }
                    foundAny = true;
                    std::cout << "[VisualMods] AutoDetect: Tim thay POE2 Real Zoom Clamp qua RVA @ 0x"
                              << std::hex << rvaClamp << std::dec << std::endl;
                }
            }
        }
    }

    // 3. POE2 NATIVE AOB SCANNER Fallback: Quét Zoom Clamp SSE trong .text
    // Mẫu 1: F3 0F 5D 0D ? ? ? ? F3 0F 11 8B 54 03 00 00
    // Mẫu 2: F3 0F 5D 0D ? ? ? ? F3 0F 11 89 54 03 00 00
    if (hasMod && mainMod.base != 0 && (m_zoomCodePatch.address == 0 || m_maxZoomFloatAddr == 0)) {
        const std::string zoomPatterns[] = {
            "F3 0F 5D 0D ? ? ? ? F3 0F 11 8B 54 03 00 00",
            "F3 0F 5D 0D ? ? ? ? F3 0F 11 89 54 03 00 00"
        };
        for (const auto& patStr : zoomPatterns) {
            auto pat = AobPattern::Parse(patStr);
            auto hits = AobScanner::ScanModuleHits(m_reader, mainMod, pat, 4 * 1024 * 1024, 8);
            for (uintptr_t hit : hits) {
                if (m_zoomCodePatch.address == 0) {
                    m_zoomCodePatch.address = hit;
                    m_zoomCodePatch.name = "POE2_ZoomClamp_SSE";
                    m_zoomCodePatch.originalBytes.resize(8);
                    m_reader.Read(hit, m_zoomCodePatch.originalBytes.data(), 8);

                    uintptr_t floatTarget = AobScanner::ResolveRipTarget(m_reader, hit, 4);
                    if (floatTarget != 0) {
                        m_maxZoomFloatAddr = floatTarget;
                        float val = 0.0f;
                        if (m_reader.ReadValue<float>(floatTarget, val)) {
                            if (val > 0.0f && val <= 50.0f) {
                                m_origMaxZoomFloat = val;
                                m_origMaxZoomFloatSaved = true;
                            }
                        }
                        std::cout << "[VisualMods] Tim thay POE2 Zoom Clamp SSE tai 0x" << std::hex << hit
                                  << " -> MaxZoom float (.rdata) @ 0x" << floatTarget
                                  << " (orig=" << std::dec << m_origMaxZoomFloat << "f)" << std::endl;
                    }
                    foundAny = true;
                } else if (hit != m_zoomCodePatch.address) {
                    AddZoomClampAddress(hit);
                    foundAny = true;
                }
            }
            if (m_zoomCodePatch.address != 0) break;
        }
    }

    if (hasMod && mainMod.base != 0) {
        auto tryAddVerifiedClamp = [&](uintptr_t addr) {
            uint8_t probe[4] = {};
            if (m_reader.Read(addr, probe, 4) &&
                probe[0] == 0xF3 && probe[1] == 0x0F && probe[2] == 0x5D && probe[3] == 0x0D) {
                if (m_zoomCodePatch.address == 0) {
                    m_zoomCodePatch.address = addr;
                    m_zoomCodePatch.name = "POE2_ZoomClamp_SSE";
                    m_zoomCodePatch.originalBytes.resize(8);
                    m_reader.Read(addr, m_zoomCodePatch.originalBytes.data(), 8);
                    const uintptr_t floatTarget = AobScanner::ResolveRipTarget(m_reader, addr, 4);
                    if (floatTarget != 0) {
                        m_maxZoomFloatAddr = floatTarget;
                        float val = 0.0f;
                        if (m_reader.ReadValue<float>(floatTarget, val) && val > 0.0f && val <= 50.0f) {
                            m_origMaxZoomFloat = val;
                            m_origMaxZoomFloatSaved = true;
                        }
                    }
                    foundAny = true;
                } else if (m_zoomCodePatch.address != addr) {
                    AddZoomClampAddress(addr);
                    foundAny = true;
                }
            }
        };
        tryAddVerifiedClamp(mainMod.base + kPoe2ZoomClampRva1);
        tryAddVerifiedClamp(mainMod.base + kPoe2ZoomClampRva2);
    }

    // 2. POE2 NATIVE AOB SCANNER: Quét Atlas / Map Fog SSE trong .text
    // Mẫu: F3 0F 59 51 ? F3 0F 58 C1 F3 0F 58 C2 C3 (live RVA +0x19b777)
    if (hasMod && mainMod.base != 0 && m_fogCodePatch.address == 0) {
        auto fogPat = AobPattern::Parse("F3 0F 59 51 ? F3 0F 58 C1 F3 0F 58 C2 C3");
        uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, fogPat, 4 * 1024 * 1024);
        if (hit != 0) {
            m_fogCodePatch.address = hit;
            m_fogCodePatch.name = "POE2_AtlasFog_SSE";
            m_fogCodePatch.originalBytes.resize(5);
            m_reader.Read(hit, m_fogCodePatch.originalBytes.data(), 5);
            std::cout << "[VisualMods] Tim thay POE2 Atlas Fog SSE tai 0x" << std::hex << hit << std::dec << std::endl;
            foundAny = true;
        }
    }

    // 2c. POE2 NATIVE AOB SCANNER / RVA: Khởi tạo và quét Minimap Shader Code Patches (Doc 43)
    if (hasMod && modBase != 0) {
        if (m_minimapGridCodePatch.address == 0) {
            auto fillPat = AobPattern::Parse(kPoe2MinimapGridFillPattern);
            uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, fillPat, 4 * 1024 * 1024);
            if (hit != 0) {
                m_minimapGridCodePatch.address = hit + 13;
                std::cout << "[VisualMods] Tim thay Minimap Grid Fill SSE tai 0x" << std::hex << hit << " -> 0x" << m_minimapGridCodePatch.address << std::dec << std::endl;
            } else {
                m_minimapGridCodePatch.address = modBase + kPoe2MinimapGridFillRva;
            }
            m_minimapGridCodePatch.name = "POE2_Minimap_GridFill";
            m_minimapGridCodePatch.originalBytes = { 0x44, 0x38, 0x59, 0x61, 0x75, 0x1F };
            m_minimapGridCodePatch.patchedBytes  = { 0xEB, 0x23, 0x90, 0x90, 0x90, 0x90 };
        }
        if (m_minimapUniformCodePatch.address == 0) {
            auto uniformPat = AobPattern::Parse(kPoe2MinimapUniformPattern);
            uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, uniformPat, 4 * 1024 * 1024);
            if (hit != 0) {
                m_minimapUniformCodePatch.address = hit + 5;
                std::cout << "[VisualMods] Tim thay Minimap Uniform SSE tai 0x" << std::hex << hit << " -> 0x" << m_minimapUniformCodePatch.address << std::dec << std::endl;
            } else {
                m_minimapUniformCodePatch.address = modBase + kPoe2MinimapUniformRva;
            }
            m_minimapUniformCodePatch.name = "POE2_Minimap_VisibilityUniform";
            m_minimapUniformCodePatch.originalBytes = { 0x74, 0x05 };
            m_minimapUniformCodePatch.patchedBytes  = { 0x90, 0x90 };
        }
        if (m_minimapBoundCodePatch.address == 0) {
            auto boundPat = AobPattern::Parse(kPoe2MinimapBoundPattern);
            uintptr_t hit = AobScanner::ScanModule(m_reader, mainMod, boundPat, 4 * 1024 * 1024);
            if (hit != 0) {
                m_minimapBoundCodePatch.address = hit + 7;
                std::cout << "[VisualMods] Tim thay Minimap Bound SSE tai 0x" << std::hex << hit << " -> 0x" << m_minimapBoundCodePatch.address << std::dec << std::endl;
            } else {
                m_minimapBoundCodePatch.address = modBase + kPoe2MinimapBoundRva;
            }
            m_minimapBoundCodePatch.name = "POE2_Minimap_CyanBound";
            m_minimapBoundCodePatch.originalBytes = { 0x0F, 0x97, 0xC0 };
            m_minimapBoundCodePatch.patchedBytes  = { 0x30, 0xC0, 0x90 };
        }

        auto checkPatchState = [&](CodePatchRecord& rec) {
            if (rec.address != 0 && !rec.patchedBytes.empty()) {
                std::vector<uint8_t> probe(rec.patchedBytes.size());
                if (m_reader.Read(rec.address, probe.data(), probe.size())) {
                    if (probe == rec.patchedBytes) {
                        rec.isPatched = true;
                    }
                }
            }
        };
        checkPatchState(m_minimapGridCodePatch);
        checkPatchState(m_minimapUniformCodePatch);
        checkPatchState(m_minimapBoundCodePatch);
        foundAny = true;
    }

    // 3. POE2 CAMERA SCAN THEO VTABLE:
    // kPoe2CameraVtableRva = 0x35A24C0 -> targetVtable = modBase + 0x35A24C0
    const uintptr_t poe2Vtable = CameraVtableAddress();
    if (poe2Vtable != 0 && m_cameraAddr == 0) {
        auto scanPoe2CameraByVtable = [&](uintptr_t base, size_t size) -> bool {
            if (size < 0x530 || size > (128u << 20)) return true;
            std::vector<uint8_t> buf(1024 * 1024);
            for (size_t off = 0; off + 8 <= size; off += (buf.size() > 8 ? buf.size() - 8 : buf.size())) {
                const size_t n = (std::min<size_t>)(buf.size(), size - off);
                if (!m_reader.Read(base + off, buf.data(), n)) continue;
                for (size_t i = 0; i + 8 <= n; i += 8) {
                    uint64_t vt = 0;
                    std::memcpy(&vt, buf.data() + i, 8);
                    if (vt == poe2Vtable) {
                        const uintptr_t cand = base + off + i;
                        SetCameraAddress(cand);
                        m_isPoe2Camera = true;
                        float zVal = 1.0f;
                        if (m_reader.ReadValue<float>(cand + kPoe2CameraZoomOffset, zVal)) {
                            m_origPoe2Zoom = (std::isnormal(zVal) && zVal > 0.1f && zVal <= 10.0f) ? zVal : 1.0f;
                        } else {
                            m_origPoe2Zoom = 1.0f;
                        }
                        m_origCameraSaved = true;
                        foundAny = true;
                        std::cout << "[VisualMods] Tim thay POE2 Camera qua VTABLE @ 0x"
                                  << std::hex << cand << " (vtable=0x" << vt
                                  << ") origZoom=" << std::dec << m_origPoe2Zoom << "f" << std::endl;
                        return false;
                    }
                }
            }
            return true;
        };

        m_reader.ForEachHeapRegion(scanPoe2CameraByVtable);
        if (m_cameraAddr == 0) {
            m_reader.ForEachReadableRegion(scanPoe2CameraByVtable);
        }
    }

    if (hasMod && mainMod.base != 0 && m_cameraAddr == 0) {
        const CameraAobSpec camSpecs[] = {
            // Singleton .data (build cu): lea rcx,[rip]; movss xmm0,[rcx+2C]; movss xmm1,[rcx+34]
            {"48 8D 0D ? ? ? ? F3 0F 10 41 2C F3 0F 10 49 34 0F 2F C1", false},
            {"48 8D 0D ? ? ? ? F3 0F 10 41 2C", false},
            {"48 8D 0D ? ? ? ? F3 0F 10 41 34", false},
            // Heap camera (build 11/09/2026): mov r64, [rip]; movss [reg+2C]/[+34]
            {"48 8B 0D ? ? ? ? F3 0F 10 41 2C", true},
            {"48 8B 05 ? ? ? ? F3 0F 10 40 2C", true},
            {"48 8B 0D ? ? ? ? F3 0F 10 41 34", true},
            {"48 8B 05 ? ? ? ? F3 0F 10 40 34", true},
        };
        for (const auto& spec : camSpecs) {
            if (m_cameraAddr != 0) break;
            auto pattern = AobPattern::Parse(spec.pattern);
            const auto hits = AobScanner::ScanModuleHits(m_reader, mainMod, pattern, 4 * 1024 * 1024, 16);
            for (const uintptr_t hit : hits) {
                uintptr_t target = AobScanner::ResolveRipTarget(m_reader, hit, 3);
                if (spec.derefPointer) {
                    uintptr_t ptr = 0;
                    if (!m_reader.ReadValue<uintptr_t>(target, ptr) || ptr < 0x10000) continue;
                    target = ptr;
                }
                if (LooksLikeCameraAt(m_reader, target, modBase, modSize)) {
                    SetCameraAddress(target);
                    foundAny = true;
                    std::cout << "[VisualMods] Camera AOB '" << spec.pattern << "' -> 0x"
                              << std::hex << target << std::dec << std::endl;
                    break;
                }
            }
        }
    }

    if (hasMod && mainMod.base != 0 && m_fogDensityAddr == 0) {
        auto oldFog = AobPattern::Parse("48 8B 0D ? ? ? ? F3 0F 11 05 ? ? ? ? 48 85 C9 74 ? E8");
        const auto oldHits = AobScanner::ScanModuleHits(m_reader, mainMod, oldFog, 4 * 1024 * 1024, 8);
        for (const uintptr_t hit : oldHits) {
            uintptr_t fogTarget = AobScanner::ResolveRipTarget(m_reader, hit, 3);
            uintptr_t deref = 0;
            uintptr_t cand = fogTarget;
            if (m_reader.ReadValue<uintptr_t>(fogTarget, deref) && deref >= 0x10000
                && LooksLikeFogAt(m_reader, deref)) {
                cand = deref;
            }
            if (LooksLikeFogAt(m_reader, cand)) {
                SetFogAddress(cand);
                foundAny = true;
                std::cout << "[VisualMods] Fog AOB (legacy) -> 0x" << std::hex << cand << std::dec << std::endl;
                break;
            }
        }
    }

    if (hasMod && mainMod.base != 0 && m_fogDensityAddr == 0) {
        auto storeRip = AobPattern::Parse("F3 0F 11 05 ? ? ? ?");
        const auto hits = AobScanner::ScanModuleHits(m_reader, mainMod, storeRip, 4 * 1024 * 1024, 128);
        for (const uintptr_t hit : hits) {
            const uintptr_t tgt = AobScanner::ResolveRipTarget(m_reader, hit, 4);
            if (LooksLikeFogAt(m_reader, tgt)) {
                SetFogAddress(tgt);
                foundAny = true;
                std::cout << "[VisualMods] Fog RIP movss [rip] -> 0x" << std::hex << tgt
                          << std::dec << std::endl;
                break;
            }
        }
    }

    if (m_cameraAddr == 0) {
        auto scanCameraStruct = [&](uintptr_t base, size_t size) -> bool {
            if (size < 0x50 || size > (128u << 20)) return true;
            std::vector<uint8_t> buf(1024 * 1024);
            for (size_t off = 0; off + 0x50 <= size; off += (buf.size() > 0x50 ? buf.size() - 0x50 : buf.size())) {
                const size_t n = (std::min<size_t>)(buf.size(), size - off);
                if (!m_reader.Read(base + off, buf.data(), n)) {
                    continue;
                }
                for (size_t i = 0; i + 0x50 <= n; i += 8) {
                    uint64_t vtable = 0;
                    float cur = 0, minD = 0, maxD = 0, fov = 0, zNear = 0, zFar = 0;
                    std::memcpy(&vtable, buf.data() + i, 8);
                    std::memcpy(&cur, buf.data() + i + 0x2C, 4);
                    std::memcpy(&minD, buf.data() + i + 0x30, 4);
                    std::memcpy(&maxD, buf.data() + i + 0x34, 4);
                    std::memcpy(&fov, buf.data() + i + 0x38, 4);
                    std::memcpy(&zNear, buf.data() + i + 0x3C, 4);
                    std::memcpy(&zFar, buf.data() + i + 0x40, 4);
                    if (!LooksLikeCameraFields(vtable, cur, minD, maxD, fov, zNear, zFar, modBase, modSize, false)) {
                        continue;
                    }
                    const uintptr_t cand = base + off + i;
                    SetCameraAddress(cand);
                    foundAny = true;
                    std::cout << "[VisualMods] Camera structural @ 0x" << std::hex << cand
                              << std::dec << " min=" << minD << " max=" << maxD
                              << " fov=" << fov << " zFar=" << zFar << std::endl;
                    return false;
                }
            }
            return true;
        };

        m_reader.ForEachHeapRegion(scanCameraStruct);
        if (m_cameraAddr == 0) {
            m_reader.ForEachReadableRegion(scanCameraStruct);
        }
    }

    if (m_fogDensityAddr == 0 && m_fogCodePatch.address == 0 && !m_isPoe2Camera) {
        auto scanFogStruct = [&](uintptr_t base, size_t size) -> bool {
            if (size < 16 || size > (128u << 20)) return true;
            std::vector<uint8_t> buf(1024 * 1024);
            for (size_t off = 0; off + 16 <= size; off += (buf.size() > 16 ? buf.size() - 16 : buf.size())) {
                const size_t n = (std::min<size_t>)(buf.size(), size - off);
                if (!m_reader.Read(base + off, buf.data(), n)) continue;
                for (size_t i = 0; i + 16 <= n; i += 4) {
                    float density = 0, start = 0, end = 0, falloff = 0;
                    std::memcpy(&density, buf.data() + i, 4);
                    std::memcpy(&start, buf.data() + i + 4, 4);
                    std::memcpy(&end, buf.data() + i + 8, 4);
                    std::memcpy(&falloff, buf.data() + i + 12, 4);
                    if (!LooksLikeFogFields(density, start, end, falloff)) continue;
                    if (i >= 0x38) {
                        uint64_t vt = 0;
                        float c = 0, mn = 0, mx = 0, fv = 0, zn = 0, zf = 0;
                        std::memcpy(&vt, buf.data() + i - 0x38, 8);
                        std::memcpy(&c, buf.data() + i - 0x38 + 0x2C, 4);
                        std::memcpy(&mn, buf.data() + i - 0x38 + 0x30, 4);
                        std::memcpy(&mx, buf.data() + i - 0x38 + 0x34, 4);
                        std::memcpy(&fv, buf.data() + i - 0x38 + 0x38, 4);
                        std::memcpy(&zn, buf.data() + i - 0x38 + 0x3C, 4);
                        std::memcpy(&zf, buf.data() + i - 0x38 + 0x40, 4);
                        if (LooksLikeCameraFields(vt, c, mn, mx, fv, zn, zf, modBase, modSize, false)) {
                            continue;
                        }
                    }
                    const uintptr_t cand = base + off + i;
                    SetFogAddress(cand);
                    foundAny = true;
                    std::cout << "[VisualMods] Fog structural @ 0x" << std::hex << cand
                              << std::dec << std::endl;
                    return false;
                }
            }
            return true;
        };
        m_reader.ForEachHeapRegion(scanFogStruct);
        if (m_fogDensityAddr == 0) {
            m_reader.ForEachReadableRegion(scanFogStruct);
        }
    }

    if (foundAny && store) {
        wchar_t exePathW[MAX_PATH] = {};
        GetModuleFileNameW(nullptr, exePathW, MAX_PATH);
        char exeDir[MAX_PATH] = {};
        WideCharToMultiByte(CP_UTF8, 0, exePathW, -1, exeDir, sizeof(exeDir), nullptr, nullptr);
        std::string dir = exeDir;
        auto slash = dir.find_last_of("\\/");
        std::string baseDir = (slash != std::string::npos) ? dir.substr(0, slash) : ".";
        store->Save(baseDir + "\\offsets.toml");
    }

    if (m_cameraAddr == 0 && m_maxZoomFloatAddr == 0 && m_zoomCodePatch.address == 0) {
        std::cout << "[VisualMods] AutoDetect: chua tim thay CameraInstance / Zoom Clamp "
                     "(vao map in-game roi bam Do lai)." << std::endl;
    }
    if (m_fogDensityAddr == 0 && m_fogCodePatch.address == 0) {
        std::cout << "[VisualMods] AutoDetect: chua tim thay FogConstants / Atlas Fog." << std::endl;
    }
    if (m_minimapGridCodePatch.address == 0) {
        std::cout << "[VisualMods] AutoDetect: chua tim thay Minimap Shader Patches." << std::endl;
    }

    return (m_cameraAddr != 0 || m_fogDensityAddr != 0 || m_maxZoomFloatAddr != 0 ||
            m_zoomCodePatch.address != 0 || m_fogCodePatch.address != 0 ||
            m_minimapGridCodePatch.address != 0);
}
