#include "VideoMode.h"

#include <algorithm>
#include <cctype>

std::string NormalizeModeToken(const std::string& value)
{
	std::string normalized;
	for (unsigned char ch : value)
	{
		if (std::isalnum(ch))
			normalized.push_back(static_cast<char>(std::tolower(ch)));
	}
	return normalized;
}

double FrameDurationMillisecondsFromRateString(const std::string& rateText, double fallbackRate)
{
	double rate = fallbackRate;
	try
	{
		rate = std::stod(rateText);
	}
	catch (...)
	{
		rate = fallbackRate;
	}

	if (rate <= 0.0)
		rate = fallbackRate;
	return 1000.0 / rate;
}

void VideoFormatDimensions(const std::string& formatName, unsigned& width, unsigned& height)
{
	std::string normalized = formatName;
	std::transform(normalized.begin(), normalized.end(), normalized.begin(), [](unsigned char character) {
		return static_cast<char>(std::tolower(character));
	});

	if (normalized == "720p")
	{
		width = 1280;
		height = 720;
		return;
	}

	if (normalized == "2160p" || normalized == "4k" || normalized == "uhd")
	{
		width = 3840;
		height = 2160;
		return;
	}

	width = 1920;
	height = 1080;
}

bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::string& frameRate, VideoFormat& videoMode)
{
	const std::string formatToken = NormalizeModeToken(videoFormat);
	const std::string frameToken = NormalizeModeToken(frameRate);
	const std::string combinedToken = formatToken + frameToken;

	struct ModeOption
	{
		const char* token;
		const char* formatName;
		const char* frameRate;
		const char* displayName;
	};

	static const ModeOption options[] =
	{
		{ "720p50", "720p", "50", "720p50" },
		{ "hd720p50", "720p", "50", "720p50" },
		{ "720p5994", "720p", "59.94", "720p59.94" },
		{ "hd720p5994", "720p", "59.94", "720p59.94" },
		{ "720p60", "720p", "60", "720p60" },
		{ "hd720p60", "720p", "60", "720p60" },
		{ "1080i50", "1080i", "50", "1080i50" },
		{ "hd1080i50", "1080i", "50", "1080i50" },
		{ "1080i5994", "1080i", "59.94", "1080i59.94" },
		{ "hd1080i5994", "1080i", "59.94", "1080i59.94" },
		{ "1080i60", "1080i", "60", "1080i60" },
		{ "hd1080i60", "1080i", "60", "1080i60" },
		{ "1080p2398", "1080p", "23.98", "1080p23.98" },
		{ "hd1080p2398", "1080p", "23.98", "1080p23.98" },
		{ "1080p24", "1080p", "24", "1080p24" },
		{ "hd1080p24", "1080p", "24", "1080p24" },
		{ "1080p25", "1080p", "25", "1080p25" },
		{ "hd1080p25", "1080p", "25", "1080p25" },
		{ "1080p2997", "1080p", "29.97", "1080p29.97" },
		{ "hd1080p2997", "1080p", "29.97", "1080p29.97" },
		{ "1080p30", "1080p", "30", "1080p30" },
		{ "hd1080p30", "1080p", "30", "1080p30" },
		{ "1080p50", "1080p", "50", "1080p50" },
		{ "hd1080p50", "1080p", "50", "1080p50" },
		{ "1080p5994", "1080p", "59.94", "1080p59.94" },
		{ "hd1080p5994", "1080p", "59.94", "1080p59.94" },
		{ "1080p60", "1080p", "60", "1080p60" },
		{ "hd1080p60", "1080p", "60", "1080p60" },
		{ "2160p2398", "2160p", "23.98", "2160p23.98" },
		{ "4k2160p2398", "2160p", "23.98", "2160p23.98" },
		{ "2160p24", "2160p", "24", "2160p24" },
		{ "4k2160p24", "2160p", "24", "2160p24" },
		{ "2160p25", "2160p", "25", "2160p25" },
		{ "4k2160p25", "2160p", "25", "2160p25" },
		{ "2160p2997", "2160p", "29.97", "2160p29.97" },
		{ "4k2160p2997", "2160p", "29.97", "2160p29.97" },
		{ "2160p30", "2160p", "30", "2160p30" },
		{ "4k2160p30", "2160p", "30", "2160p30" },
		{ "2160p50", "2160p", "50", "2160p50" },
		{ "4k2160p50", "2160p", "50", "2160p50" },
		{ "2160p5994", "2160p", "59.94", "2160p59.94" },
		{ "4k2160p5994", "2160p", "59.94", "2160p59.94" },
		{ "2160p60", "2160p", "60", "2160p60" },
		{ "4k2160p60", "2160p", "60", "2160p60" }
	};

	for (const ModeOption& option : options)
	{
		if (combinedToken == option.token || (frameToken.empty() && formatToken == option.token))
		{
			videoMode.formatName = option.formatName;
			videoMode.frameRate = option.frameRate;
			videoMode.displayName = option.displayName;
			VideoFormatDimensions(videoMode.formatName, videoMode.frameSize.width, videoMode.frameSize.height);
			videoMode.frameDurationMilliseconds = FrameDurationMillisecondsFromRateString(videoMode.frameRate);
			return true;
		}
	}

	return false;
}

bool ResolveConfiguredVideoFormats(
	const std::string& inputVideoFormat,
	const std::string& inputFrameRate,
	const std::string& outputVideoFormat,
	const std::string& outputFrameRate,
	VideoFormatSelection& videoModes,
	std::string& error)
{
	if (!ResolveConfiguredVideoFormat(inputVideoFormat, inputFrameRate, videoModes.input))
	{
		error = "Unsupported inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
			inputVideoFormat + " / " + inputFrameRate;
		return false;
	}

	if (!ResolveConfiguredVideoFormat(outputVideoFormat, outputFrameRate, videoModes.output))
	{
		error = "Unsupported outputVideoFormat/outputFrameRate in config/runtime-host.json: " +
			outputVideoFormat + " / " + outputFrameRate;
		return false;
	}

	return true;
}
