#include <catch2/catch_all.hpp>

#include "IO/MemMappedFile.hpp"
#include "IO/MemMappedFileWriteHelper.hpp"
#include "IO/AppFolders.hpp"
#include "Base/Logger.hpp"

#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;

TEST_CASE("MemMappedFileWrite")
{
	OpenVulkano::Logger::SetupLogger("", "tests.log");

	auto path = OpenVulkano::AppFolders::GetAppTempDir();
	path += "/MemFileTest.txt";

	std::string data = "Hello World X\n"
	                   "Hello World Y\n"
	                   "Hello World Z\n"
	                   "Hello World W\n"
	                   "Hello World A\n"
	                   "Hello World B\n"
	                   "Hello World C\n"
	                   "Hello World D\n"
	                   "Hello World E\n"
	                   "Hello World F\n"
	                   "Hello World G\n"
	                   "Hello World H\n"
	                   "Hello World I\n"
	                   "Hello World J\n"
	                   "Hello World K\n"
	                   "Hello World L\n"
	                   "Hello World M\n"
	                   "Hello World N\n";


	SECTION("Write to MemMappedFile")
	{
		OpenVulkano::MemMappedFileWriter writer(path, 1024);
		writer.Write(data.data(), data.size());

		REQUIRE(writer.GetOffset() == data.size());
	}

	SECTION("Control Size")
	{
		OpenVulkano::MemMappedFile memFile(path, OpenVulkano::MemMappedFile::READ_ONLY);
		REQUIRE(memFile.Size() == 1024); // The size that comes from the first Test.
	}

	SECTION("Compare String Data for per char")
	{
		OpenVulkano::MemMappedFileWriteHelper memFileHelper(path, OpenVulkano::MemMappedFile::READ_ONLY);
		REQUIRE(memFileHelper.Trim(data.size()));

		std::string testData((char*) memFileHelper.Data());

		for (size_t i = 0; i < data.size(); i++)
		{
			if (data[i] != testData[i])
			{
				REQUIRE(false);
			}
		}

		memFileHelper.Close();
	}

	SECTION("Trim File")
	{
		OpenVulkano::MemMappedFileWriteHelper helper(path,
		                                             OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
		REQUIRE(helper.Trim(100));
		REQUIRE(helper.Size() == 100);

		helper.Close();
	}

	SECTION("Write Data 2")
	{
		OpenVulkano::MemMappedFileWriter writer(path, OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
		writer.Write(data.data(), data.size());
		writer.Write(data.data(), data.size());
		writer.Write(data.data(), data.size());

		REQUIRE(writer.GetOffset() == data.size() * 3);
	}

	SECTION("Compare Data")
	{
		OpenVulkano::MemMappedFileWriteHelper helper(path,
		                                             OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
		REQUIRE(helper.Data() != nullptr);
		std::string testData((char*) helper.Data());
		helper.Close();

		std::ifstream file(path, std::ios::binary);
		std::string streamData;
		std::getline(file, streamData, '\0');
		file.close();

		for (size_t i = 0; i < testData.size(); i++)
		{
			if (streamData[i] != testData[i])
			{
				REQUIRE(false);
			}
		}

		REQUIRE(streamData.size() == testData.size());
	}

	SECTION("Actual Size")
	{
		std::error_code ec;
		std::uintmax_t size = fs::file_size(path, ec);

		REQUIRE(size == 756);
	}
}
