#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <tlhelp32.h>

#include <cstdint>
#include <functional>
#include <string>
#include <vector>

// ==========================================================
// IMemoryReader - Giao diện trừu tượng tầng đọc/ghi bộ nhớ game
// C++23 Standalone Visual Tool - Poe2VisualTool
// ==========================================================

class IMemoryReader {
public:
    using RegionFn = std::function<bool(uintptr_t, size_t)>;

    virtual ~IMemoryReader() = default;

    virtual const char* BackendName() const = 0;

    virtual bool Attach(uint32_t pid) = 0;
    virtual void Detach() = 0;

    virtual bool IsAttached() const { return m_pid != 0; }
    uint32_t AttachedPid() const { return m_pid; }

    // Đọc mảng byte thô từ không gian địa chỉ của tiến trình
    virtual bool Read(uintptr_t address, void* buffer, size_t size) = 0;

    // Liệt kê các region memory readable (phục vụ quét pattern)
    virtual bool ForEachReadableRegion(const RegionFn& fn) = 0;

    // Liệt kê các region heap động riêng tư
    virtual bool ForEachHeapRegion(const RegionFn& fn) {
        return ForEachReadableRegion(fn);
    }

    // Đọc 1 giá trị kiểu T tại địa chỉ
    template <typename T>
    bool ReadValue(uintptr_t address, T& outValue) {
        return Read(address, &outValue, sizeof(T));
    }

    // Ghi mảng byte thô vào không gian địa chỉ của tiến trình
    virtual bool Write(uintptr_t /*address*/, const void* /*buffer*/, size_t /*size*/) {
        return false;
    }

    // Ghi 1 giá trị kiểu T tại địa chỉ
    template <typename T>
    bool WriteValue(uintptr_t address, const T& value) {
        return Write(address, &value, sizeof(T));
    }

    // Giải chuỗi con trỏ nhiều cấp (pointer chain):
    // base -> [base + off0] -> [.. + off1] -> ... -> giá trị cuối
    bool DerefPointerChain(uintptr_t base, const std::vector<uintptr_t>& offsets,
                           uintptr_t& outAddress) {
        uintptr_t current = base;
        for (size_t i = 0; i < offsets.size(); ++i) {
            if (!ReadValue<uintptr_t>(current, current)) return false;
            if (current == 0) return false;
            current += offsets[i];
        }
        outAddress = current;
        return true;
    }

protected:
    uint32_t m_pid = 0;
};

// Tìm PID của tiến trình theo tên file exe (không phân biệt hoa thường)
inline uint32_t FindProcessId(const std::wstring& processName) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32W entry{};
    entry.dwSize = sizeof(entry);

    uint32_t foundPid = 0;
    if (Process32FirstW(snapshot, &entry)) {
        do {
            if (_wcsicmp(entry.szExeFile, processName.c_str()) == 0) {
                foundPid = entry.th32ProcessID;
                break;
            }
        } while (Process32NextW(snapshot, &entry));
    }
    CloseHandle(snapshot);
    return foundPid;
}

// Tự động tìm PID và tên tiến trình POE2 (hỗ trợ cả Standalone lẫn Steam, 64-bit)
inline uint32_t FindPoeProcessId(std::wstring* outName = nullptr) {
    const std::wstring candidateNames[] = {
        L"PathOfExile.exe",
        L"PathOfExileSteam.exe",
        L"PathOfExile_x64.exe",
        L"PathOfExile_x64Steam.exe",
        L"PathOfExile2.exe"
    };
    for (const auto& name : candidateNames) {
        uint32_t pid = FindProcessId(name);
        if (pid != 0) {
            if (outName) *outName = name;
            return pid;
        }
    }
    return 0;
}
