#pragma once

#include <cstdint>
#include <string>
#include <optional>
#include <tuple>

#ifndef member_at
#define member_at(T, offset, name) \
	__forceinline auto &name() \
	{ \
		return *reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(this) + offset); \
	} \
	__forceinline auto &name() const \
	{ \
		return *reinterpret_cast<const T *>(reinterpret_cast<uintptr_t>(this) + offset); \
	}
#endif

class FeatureManager
{
public:
	static inline size_t m_map_offset{};
	member_at(uintptr_t, m_map_offset, m_feature_map);
};

union str_holder
{
	struct
	{
		const char* str;
		uintptr_t pad[2];
		size_t length;
	} obj;

	const char str[16];
};

uintptr_t get_current_process_handle();
std::optional<std::tuple<uintptr_t, uintptr_t>> get_section_info(std::string_view name);
std::optional<uintptr_t> sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern);
uint64_t hook_is_feature_available(uintptr_t rcx, str_holder* guid);
uint64_t* hook_map_find(uintptr_t* rcx, uintptr_t rdx, str_holder* str);
void hook_bitset_init(uintptr_t rcx, uintptr_t rdx);
uint64_t hook_is_user_feature_set(int expected, int feature);
FeatureManager* hook_feature_manager_init(FeatureManager* rcx);
void hook();
