#include "crashReport.h"

#include <string>
#include <iostream>
#include <ctime>

#include <dbghelp.h>

std::wstring get_temp_path()
{
	auto temp_key = L"TEMP";
	DWORD buffer_size = GetEnvironmentVariableW(temp_key, NULL, 0);
	if (buffer_size == 0)
	{
		int e = GetLastError();
		if (e == ERROR_ENVVAR_NOT_FOUND) {
			std::cout << "Environment variable TEMP not found.\n";
		}
		else {
			std::cout << "Unknown error while getting environment variable: " << e << " \n";
		}
	}
	std::wstring buffer;
	buffer.resize(buffer_size);
	GetEnvironmentVariableW(temp_key, &buffer[0], buffer_size);
	buffer.pop_back(); // remove \0 for concat
	return buffer + L"\\cenos\\";
}

std::wstring get_formatted_time()
{
	/*
	format has to correspond format in 
	ReportingService::submitIssue
	which currently is in 
	\cenos - ui\src\kernel\services\network\reportingService.ts
	*/
	auto time_format = L"%Y-%m-%d-%H%M%S";
	static int counter = 0;

	counter = (counter + 1) % 10;

	time_t t = time(nullptr);
#pragma warning( disable: 4996)
	wchar_t buffer[128];
	size_t formatted_time_size = std::wcsftime(buffer, 128, time_format, std::localtime(&t));
	return std::wstring(buffer) + L"-" + std::to_wstring(counter);
}

std::wstring write_dump_file(MINIDUMP_EXCEPTION_INFORMATION *expParam)
{
	BOOL bMiniDumpSuccessful;

	/* probably excessive right now to add these
	to_wstring(GetCurrentProcessId())
	to_wstring(GetCurrentThreadId())
	*/
	auto temp_path = get_temp_path();
	auto time = get_formatted_time();

	CreateDirectoryW(temp_path.c_str(), NULL);

	std::wstring file_name = temp_path + time + L".dmp";

	HANDLE hDumpFile = CreateFileW(file_name.c_str(), GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

	bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
		hDumpFile, MiniDumpWithDataSegs, expParam, NULL, NULL);
	CloseHandle(hDumpFile);

	if (bMiniDumpSuccessful)
		return file_name;
	else
		return L"";
}

LONG WINAPI generate_dump_file(EXCEPTION_POINTERS* pExceptionPointers)
{
	MINIDUMP_EXCEPTION_INFORMATION ExpParam;
	ExpParam.ThreadId = GetCurrentThreadId();
	ExpParam.ExceptionPointers = pExceptionPointers;
	ExpParam.ClientPointers = TRUE;
	std::wstring fileName = write_dump_file(&ExpParam);

	if (fileName.empty()) {
		std::wcout << L"Cannot write dump\n";
	}
	else {
		std::wcout << L"Crash dump written to: " << fileName << L"\n";
	}
	return EXCEPTION_EXECUTE_HANDLER;
}
