#include "RuntimeControlCommand.h"

namespace RenderCadenceCompositor
{
namespace
{
const JsonValue* RequireObjectField(const JsonValue& root, const char* fieldName, std::string& error)
{
	const JsonValue* field = root.find(fieldName);
	if (!field)
		error = std::string("Request field '") + fieldName + "' is required.";
	return field;
}

bool RequireStringField(const JsonValue& root, const char* fieldName, std::string& value, std::string& error)
{
	const JsonValue* field = RequireObjectField(root, fieldName, error);
	if (!field)
		return false;
	if (!field->isString() || field->asString().empty())
	{
		error = std::string("Request field '") + fieldName + "' must be a non-empty string.";
		return false;
	}
	value = field->asString();
	return true;
}

bool RequireBoolField(const JsonValue& root, const char* fieldName, bool& value, std::string& error)
{
	const JsonValue* field = RequireObjectField(root, fieldName, error);
	if (!field)
		return false;
	if (!field->isBoolean())
	{
		error = std::string("Request field '") + fieldName + "' must be a boolean.";
		return false;
	}
	value = field->asBoolean();
	return true;
}

bool RequireIntegerField(const JsonValue& root, const char* fieldName, int& value, std::string& error)
{
	const JsonValue* field = RequireObjectField(root, fieldName, error);
	if (!field)
		return false;
	if (!field->isNumber())
	{
		error = std::string("Request field '") + fieldName + "' must be a number.";
		return false;
	}
	value = static_cast<int>(field->asNumber());
	return true;
}
}

bool ParseRuntimeControlCommand(
	const std::string& path,
	const std::string& body,
	RuntimeControlCommand& command,
	std::string& error)
{
	command = RuntimeControlCommand();

	JsonValue root;
	std::string parseError;
	if (!ParseJson(body.empty() ? "{}" : body, root, parseError) || !root.isObject())
	{
		error = parseError.empty() ? "Request body must be a JSON object." : parseError;
		return false;
	}

	if (path == "/api/layers/add")
	{
		command.type = RuntimeControlCommandType::AddLayer;
		return RequireStringField(root, "shaderId", command.shaderId, error);
	}
	if (path == "/api/layers/remove")
	{
		command.type = RuntimeControlCommandType::RemoveLayer;
		return RequireStringField(root, "layerId", command.layerId, error);
	}
	if (path == "/api/layers/reorder")
	{
		command.type = RuntimeControlCommandType::ReorderLayer;
		return RequireStringField(root, "layerId", command.layerId, error)
			&& RequireIntegerField(root, "targetIndex", command.targetIndex, error);
	}
	if (path == "/api/layers/set-bypass")
	{
		command.type = RuntimeControlCommandType::SetLayerBypass;
		return RequireStringField(root, "layerId", command.layerId, error)
			&& RequireBoolField(root, "bypass", command.bypass, error);
	}
	if (path == "/api/layers/set-shader")
	{
		command.type = RuntimeControlCommandType::SetLayerShader;
		return RequireStringField(root, "layerId", command.layerId, error)
			&& RequireStringField(root, "shaderId", command.shaderId, error);
	}
	if (path == "/api/layers/update-parameter")
	{
		command.type = RuntimeControlCommandType::UpdateLayerParameter;
		const JsonValue* value = nullptr;
		if (!RequireStringField(root, "layerId", command.layerId, error)
			|| !RequireStringField(root, "parameterId", command.parameterId, error))
		{
			return false;
		}
		value = RequireObjectField(root, "value", error);
		if (!value)
			return false;
		command.value = *value;
		return true;
	}
	if (path == "/api/layers/reset-parameters")
	{
		command.type = RuntimeControlCommandType::ResetLayerParameters;
		return RequireStringField(root, "layerId", command.layerId, error);
	}
	if (path == "/api/reload")
	{
		command.type = RuntimeControlCommandType::ReloadShaders;
		return true;
	}

	command.type = RuntimeControlCommandType::Unsupported;
	error = "Endpoint is not implemented in RenderCadenceCompositor yet.";
	return false;
}
}
