#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

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

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

#include "memory/imemory_reader.hpp"

// ==========================================================
// AobScanner - Quét ký hiệu nhị phân (Array-of-Bytes Scanning)
// ==========================================================

struct AobPattern {
    std::vector<uint8_t> bytes;
    std::vector<bool> wildcard;

    static AobPattern Parse(const std::string& text) {
        AobPattern p;
        size_t i = 0;
        while (i < text.size()) {
            while (i < text.size() && (text[i] == ' ' || text[i] == '\t')) ++i;
            if (i >= text.size()) break;

            if (text[i] == '?') {
                p.bytes.push_back(0);
                p.wildcard.push_back(true);
                ++i;
                continue;
            }

            if (i + 1 >= text.size()) return AobPattern{};
            auto nibble = [](char c) -> int {
                if (c >= '0' && c <= '9') return c - '0';
                if (c >= 'a' && c <= 'f') return c - 'a' + 10;
                if (c >= 'A' && c <= 'F') return c - 'A' + 10;
                return -1;
            };
            const int hi = nibble(text[i]);
            const int lo = nibble(text[i + 1]);
            if (hi < 0 || lo < 0) return AobPattern{};
            p.bytes.push_back(static_cast<uint8_t>((hi << 4) | lo));
            p.wildcard.push_back(false);
            i += 2;
        }
        return p;
    }

    bool Valid() const { return !bytes.empty(); }
    size_t Size() const { return bytes.size(); }
};

struct ModuleInfo {
    std::string name;
    uintptr_t base = 0;
    size_t size = 0;
};

class AobScanner {
public:
    static intptr_t Find(const uint8_t* data, size_t dataSize, const AobPattern& pattern);

    static bool FindModule(uint32_t pid, const std::wstring& moduleName, ModuleInfo& outInfo);

    static uintptr_t ScanModule(IMemoryReader& reader, const ModuleInfo& module,
                                const AobPattern& pattern, size_t chunkSize = 4 * 1024 * 1024);

    static std::vector<uintptr_t> ScanModuleHits(IMemoryReader& reader, const ModuleInfo& module,
                                                const AobPattern& pattern,
                                                size_t chunkSize = 4 * 1024 * 1024,
                                                size_t maxHits = 32);

    static uintptr_t ResolveRipRelative(uintptr_t matchAddress, size_t ripOffset);

    static uintptr_t ResolveRipTarget(IMemoryReader& reader, uintptr_t matchAddress, size_t ripOffset);
};
