#pragma once
#include <ws2tcpip.h>
#include <thread>
#include "theo.h"
#include "utils.hpp"

// if you change this, make sure 
// to change it in the client also...
#define PACKET_DATA_SIZE 0x1000

// max symbol string size... if you 
// change this update the client also...
#define PACKET_SYMBOL_SIZE 0x1000

namespace theo
{
	enum class theo_packet_type
	{
		init,
		alloc_memory,
		resolve_symbol,
		copy_memory,
		disconnect
	};

	enum class theo_file_type
	{
		demo_drv,
		demo_dll,
		demo_imgui
	};

#pragma pack(push, 1)
	typedef struct _theo_data
	{
		theo_packet_type type;

		union
		{
			theo_file_type file;
			std::uintptr_t entry_point;

			struct
			{
				void* addr;
				std::size_t alloc_size;
				std::uint32_t prot;
			} alloc;

			struct
			{
				void* dest_addr;
				std::size_t size;
				std::uint8_t data[PACKET_DATA_SIZE];
			} copy_memory;

			struct
			{
				std::uintptr_t symbol_addr;
				std::size_t symbol_size;
				char symbol[PACKET_SYMBOL_SIZE];
			} resolve;
		};
	} theo_data, * ptheo_data;
#pragma pack(pop)

	class client
	{
	public:
		explicit client(SOCKET client_socket);
		~client();

	private:
		void handler() const;
		void* wrapper_memcpy(void* dest, const void* src, std::size_t size) const;
		void* wrapper_alloc(std::size_t size, std::uint32_t prot) const;
		std::uintptr_t wrapper_resolve_symbol(const char* symbol_name) const;

		const SOCKET client_socket;
		std::thread handler_thread;
	};

	inline std::map<SOCKET, std::shared_ptr<client>> connections;
	inline std::map<theo_file_type, std::vector<lnk::obj_buffer_t>> lib_files;
}