/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include <catch2/catch_all.hpp>

#include "Host/WebResourceLoader.hpp"

#include <filesystem>
#include <fstream>
#include <cstring>

#include "curl/curl.h"

using namespace OpenVulkano;

class TestWebResourceLoader : public WebResourceLoader
{
public:
	std::filesystem::path GetCacheFilePath(const std::string& url)
	{
		return WebResourceLoader::GetCacheFilePath(url);
	}

	Array<char> DownloadResource(const std::string& url)
	{
		return WebResourceLoader::DownloadResource(url);
	}

	std::filesystem::path GetCacheDir()
	{
		return m_cacheDirectory;
	}
};

TEST_CASE("CURL SSL support", "[WebResourceLoader]")
{
	curl_version_info_data* vinfo = curl_version_info(CURLVERSION_NOW);
	REQUIRE(vinfo->features & CURL_VERSION_SSL);
}

TEST_CASE("Constructor/Destructor", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;

	REQUIRE(std::filesystem::exists(loader.GetCacheDir()));
}

TEST_CASE("IsUrl", "[WebResourceLoader]")
{
	REQUIRE(WebResourceLoader::IsUrl("http://example.com"));
	REQUIRE(WebResourceLoader::IsUrl("https://example.com"));
	REQUIRE(WebResourceLoader::IsUrl("ftp://example.com"));
	REQUIRE_FALSE(WebResourceLoader::IsUrl("file://example.com"));
	REQUIRE_FALSE(WebResourceLoader::IsUrl("example.com"));
}

TEST_CASE("GetCacheFilePath", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;

	std::string url = "http://example.com/resource";
	std::filesystem::path cachePath = loader.GetCacheFilePath(url);

	size_t expectedHash = std::hash<std::string> {}(url);
	std::string expectedHashStr = std::to_string(expectedHash);

	REQUIRE(cachePath.filename().string() == expectedHashStr);
	REQUIRE(cachePath.parent_path().filename().string() == "resources");
}

TEST_CASE("DownloadResource from non-ssl uri", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;
	std::string url = "http://neverssl.com";
	Array<char> resourceData = loader.DownloadResource(url);
	REQUIRE(!resourceData.Empty());
	std::filesystem::path cachePath = loader.GetCacheFilePath(url);
	REQUIRE(std::filesystem::exists(cachePath));
	std::filesystem::remove(cachePath);
}

TEST_CASE("DownloadResource with curl", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;
	std::string url = "https://example.com/resource";
	Array<char> resourceData = loader.DownloadResource(url);
	REQUIRE(!resourceData.Empty());
	std::filesystem::path cachePath = loader.GetCacheFilePath(url);
	REQUIRE(std::filesystem::exists(cachePath));
	std::filesystem::remove(cachePath);
}

TEST_CASE("DownloadResource without curl", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;
	std::string url = "https://example.com/resource";
	Array<char> resourceData = loader.DownloadResource(url);

	REQUIRE(!resourceData.Empty());
}

TEST_CASE("GetResource", "[WebResourceLoader]")
{
	TestWebResourceLoader loader;

	std::string url = "https://example.com/resource";

	{
		std::filesystem::path cachePath = loader.GetCacheFilePath(url);
		std::ofstream file(cachePath, std::ios::binary);
		std::string mockContent = "Mock cached content";
		file.write(mockContent.c_str(), mockContent.size());
		file.close();

		Array<char> resource = loader.GetResource(url);

		REQUIRE(!resource.Empty());
		REQUIRE(std::memcmp(resource.Data(), mockContent.c_str(), mockContent.size()) == 0);

		std::filesystem::remove(cachePath);
	}

	{
		std::filesystem::path cachePath = loader.GetCacheFilePath(url);
		std::filesystem::remove(cachePath);

		Array<char> resource = loader.GetResource(url);

		REQUIRE(!resource.Empty());
		REQUIRE(std::filesystem::exists(cachePath));

		std::filesystem::remove(cachePath);
	}
}