#include "Steam.h"
#include <windows.h>
#include <tlhelp32.h>
#include <cstdio>
#include "../../Menu/Menu.h"


// 嵌入的 Steam 覆盖层文件数据（定义在各 .h 中）
extern unsigned int gameoverlayui_exe_len;
extern unsigned char gameoverlayui_exe[];
extern unsigned int gameoverlayui64_exe_len;
extern unsigned char gameoverlayui64_exe[];
extern unsigned int GameOverlayRenderer_dll_len;
extern unsigned char GameOverlayRenderer_dll[];
extern unsigned int GameOverlayRenderer64_dll_len;
extern unsigned char GameOverlayRenderer64_dll[];

// 单例
Steam* Steam::Get()
{
	static Steam instance;
	return &instance;
}

Steam::Steam() = default;
Steam::~Steam() = default;

const std::string& Steam::GetSteamPath() const {
	// 每次调用都从注册表查询 Steam 安装路径
	HKEY hKey;
	if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Valve\\Steam", 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) {
		char path[MAX_PATH];
		DWORD size = sizeof(path);
		if (RegQueryValueExA(hKey, "InstallPath", nullptr, nullptr,
			reinterpret_cast<BYTE*>(path), &size) == ERROR_SUCCESS)
		{
			m_SteamPath = path;
			RegCloseKey(hKey);
			printf("[Steam] > install path: %s\n", m_SteamPath.c_str());
			return m_SteamPath;
		}
		RegCloseKey(hKey);
	}

	// 回退：当前用户注册表
	if (RegOpenKeyExA(HKEY_CURRENT_USER,
		"SOFTWARE\\Valve\\Steam", 0,
		KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS)
	{
		char path[MAX_PATH];
		DWORD size = sizeof(path);
		if (RegQueryValueExA(hKey, "SteamPath", nullptr, nullptr,
			reinterpret_cast<BYTE*>(path), &size) == ERROR_SUCCESS)
		{
			m_SteamPath = path;
			RegCloseKey(hKey);
			printf("[Steam] > install path: %s\n", m_SteamPath.c_str());
			return m_SteamPath;
		}
		RegCloseKey(hKey);
	}

	m_SteamPath.clear();
	printf("[Steam] > warn: could not find steam install path\n");
	return m_SteamPath;
}

bool Steam::IsProcessRunning(const wchar_t* exeName) const {
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
		return false;

	PROCESSENTRY32W pe32;
	pe32.dwSize = sizeof(pe32);

	bool found = false;
	if (Process32FirstW(hSnapshot, &pe32))
	{
		do
		{
			if (_wcsicmp(pe32.szExeFile, exeName) == 0)
			{
				found = true;
				break;
			}
		} while (Process32NextW(hSnapshot, &pe32));
	}

	CloseHandle(hSnapshot);
	return found;
}

bool Steam::TerminateProcessByName(const wchar_t* exeName) const {
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
		return false;

	PROCESSENTRY32W pe32;
	pe32.dwSize = sizeof(pe32);

	bool killed = false;
	if (Process32FirstW(hSnapshot, &pe32))
	{
		do
		{
			if (_wcsicmp(pe32.szExeFile, exeName) == 0)
			{
				HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID);
				if (hProcess)
				{
					TerminateProcess(hProcess, 0);
					CloseHandle(hProcess);
					killed = true;
				}
			}
		} while (Process32NextW(hSnapshot, &pe32));
	}

	CloseHandle(hSnapshot);
	return killed;
}

bool Steam::IsSteamRunning() {
	return IsProcessRunning(L"steam.exe");
}

bool Steam::StartSteam() {
	const std::string& steamPath = GetSteamPath();
	if (steamPath.empty())
	{
		printf("[Steam] > err: steam path unknown, cannot start\n");
		return false;
	}

	std::string exePath = steamPath + "\\steam.exe";

	HINSTANCE result = ShellExecuteA(
		nullptr, "open", exePath.c_str(), nullptr, nullptr, SW_SHOW
	);

	if (reinterpret_cast<INT_PTR>(result) > 32)
	{
		printf("[Steam] > started: %s\n", exePath.c_str());
		return true;
	}

	printf("[Steam] > err: failed to start (code %d)\n",
		static_cast<int>(reinterpret_cast<INT_PTR>(result)));
	return false;
}

bool Steam::KillSteam() {
	auto Log = Menu::Get();
	if (!IsSteamRunning())
	{
		printf("[Steam] > steam not running\n");
		Log->AddLog("[Steam] > steam not running");
		return false;
	}

	if (TerminateProcessByName(L"steam.exe"))
	{
		printf("[Steam] > steam killed\n");
		Log->AddLog("[Steam] > steam killed");
		return true;
	}

	printf("[Steam] > err: failed to kill steam\n");
	Log->AddLog("[Steam] > err: failed to kill steam");
	return false;
}

// ─── 写入嵌入文件到磁盘的辅助函数 ────────────────────────────

static bool WriteEmbeddedFile(const std::string& dir, const char* name, const file& f)
{
	std::string fullPath = dir + "\\" + name;

	HANDLE hFile = CreateFileA(
		fullPath.c_str(),
		GENERIC_WRITE,
		0,
		nullptr,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		nullptr
	);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("[Steam] > err: cannot create file %s (0x%lx)\n", fullPath.c_str(), GetLastError());
		return false;
	}

	DWORD written = 0;
	const BOOL ok = WriteFile(hFile, f.file, f.len, &written, nullptr);
	CloseHandle(hFile);

	if (!ok || written != f.len)
	{
		printf("[Steam] > err: write failed for %s (wrote %lu/%u)\n", fullPath.c_str(), written, f.len);
		return false;
	}

	printf("[Steam] > replaced: %s (%u bytes)\n", fullPath.c_str(), f.len);
	return true;
}

// ─── 替换 Steam 覆盖层文件 ──────────────────────────────────

bool Steam::ReplaceOverlayFiles()
{
	auto Log = Menu::Get();
	const std::string& steamPath = GetSteamPath();
	if (steamPath.empty())
	{
		printf("[Steam] > err: steam path unknown, cannot replace overlay files\n");
		Log->AddLog("[Steam] > err: steam path unknown, cannot replace overlay files");
		return false;
	}

	printf("[Steam] > replacing overlay files in: %s\n", steamPath.c_str());

	bool allOk = true;

	allOk &= WriteEmbeddedFile(steamPath, "gameoverlayui.exe", gameoverlayui());
	allOk &= WriteEmbeddedFile(steamPath, "GameOverlayRenderer.dll", GameOverlayRenderer());
	allOk &= WriteEmbeddedFile(steamPath, "gameoverlayui64.exe", gameoverlayui64());
	allOk &= WriteEmbeddedFile(steamPath, "GameOverlayRenderer64.dll", GameOverlayRenderer64());

	if (allOk) {
		printf("[Steam] > all overlay files replaced successfully\n");
		Log->AddLog("[Steam] > all overlay files replaced successfully");
	}
	else {
		printf("[Steam] > warn: some overlay files failed to replace\n");
		Log->AddLog("[Steam] > warn: some overlay files failed to replace");
	}
		

	return allOk;
}

