#pragma once
// ── CS2 External C++ WebRadar — Win32 Utilities ──────────────────────────────
// Process discovery, module enumeration, window detection, admin check.

#include <cstdint>
#include <string>
#include <vector>
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>

#include "module.h"

namespace win32 {

// ── Process discovery ───────────────────────────────────────────────────────
// Returns process ID of the first matching process, or 0 if not found.
inline DWORD find_process(const wchar_t* name) {
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32W entry{};
    entry.dwSize = sizeof(entry);
    DWORD pid = 0;

    if (Process32FirstW(snap, &entry)) {
        do {
            if (_wcsicmp(entry.szExeFile, name) == 0) {
                pid = entry.th32ProcessID;
                break;
            }
        } while (Process32NextW(snap, &entry));
    }

    CloseHandle(snap);
    return pid;
}

// ── Open handle with PROCESS_VM_READ | PROCESS_QUERY_INFORMATION ────────────
inline HANDLE open_process(DWORD pid) {
    return OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
}

// ── Module resolution ──────────────────────────────────────────────────────
// Finds a module by name in the given process. Returns base address + size.
inline Module find_module(HANDLE process, const wchar_t* module_name) {
    Module mod;
    if (!process) return mod;

    mod.process = process;

    // Use EnumProcessModules for 64-bit target
    HMODULE hMods[1024];
    DWORD cbNeeded;
    if (EnumProcessModules(process, hMods, sizeof(hMods), &cbNeeded)) {
        int count = cbNeeded / sizeof(HMODULE);
        for (int i = 0; i < count; i++) {
            wchar_t modName[MAX_PATH];
            if (GetModuleFileNameExW(process, hMods[i], modName, MAX_PATH)) {
                const wchar_t* basename = wcsrchr(modName, L'\\');
                if (!basename) basename = modName;
                else basename++;

                if (_wcsicmp(basename, module_name) == 0) {
                    mod.base = reinterpret_cast<std::uintptr_t>(hMods[i]);
                    // Get module size
                    MODULEINFO mi;
                    if (GetModuleInformation(process, hMods[i], &mi, sizeof(mi))) {
                        mod.size = mi.SizeOfImage;
                    }
                    return mod;
                }
            }
        }
    }
    return mod;
}

// ── Fallback: find module via CreateToolhelp32Snapshot (when EnumProcessModules fails) ─
inline Module find_module_snapshot(DWORD pid, const wchar_t* module_name) {
    Module mod;
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
    if (snap == INVALID_HANDLE_VALUE) return mod;

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

    if (Module32FirstW(snap, &entry)) {
        do {
            if (_wcsicmp(entry.szModule, module_name) == 0) {
                mod.process = open_process(pid);
                mod.base = reinterpret_cast<std::uintptr_t>(entry.modBaseAddr);
                mod.size = entry.modBaseSize;
                break;
            }
        } while (Module32NextW(snap, &entry));
    }

    CloseHandle(snap);
    return mod;
}

// ── Window detection ────────────────────────────────────────────────────────
inline HWND find_window(const wchar_t* window_class, const wchar_t* window_title) {
    return FindWindowW(window_class, window_title);
}

inline DWORD get_window_pid(HWND hwnd) {
    DWORD pid = 0;
    GetWindowThreadProcessId(hwnd, &pid);
    return pid;
}

inline bool is_window_foreground(HWND hwnd) {
    return GetForegroundWindow() == hwnd;
}

// ── Admin check ────────────────────────────────────────────────────────────
inline bool is_admin() {
    BOOL isAdmin = FALSE;
    HANDLE token = NULL;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
        TOKEN_ELEVATION elevation;
        DWORD size = sizeof(TOKEN_ELEVATION);
        if (GetTokenInformation(token, TokenElevation, &elevation, size, &size)) {
            isAdmin = elevation.TokenIsElevated;
        }
        CloseHandle(token);
    }
    return isAdmin != FALSE;
}

// ── Window rectangle ───────────────────────────────────────────────────────
inline RECT get_client_rect(HWND hwnd) {
    RECT rc{};
    GetClientRect(hwnd, &rc);
    POINT tl{0, 0};
    ClientToScreen(hwnd, &tl);
    OffsetRect(&rc, tl.x, tl.y);
    return rc;
}

} // namespace win32
