#include "RuntimeServiceLiveBridge.h"

#include "RenderEngine.h"
#include "RuntimeServices.h"

#include <windows.h>

namespace
{
void DrainServiceEvents(RuntimeServices& runtimeServices, RenderEngine& renderEngine)
{
	std::vector<RuntimeServices::AppliedOscUpdate> appliedOscUpdates;
	std::vector<RuntimeServices::CompletedOscCommit> completedOscCommits;

	std::string oscError;
	if (!runtimeServices.ApplyPendingOscUpdates(appliedOscUpdates, oscError) && !oscError.empty())
		OutputDebugStringA(("OSC apply failed: " + oscError + "\n").c_str());
	runtimeServices.ConsumeCompletedOscCommits(completedOscCommits);

	std::vector<RenderEngine::OscOverlayUpdate> overlayUpdates;
	overlayUpdates.reserve(appliedOscUpdates.size());
	for (const RuntimeServices::AppliedOscUpdate& update : appliedOscUpdates)
	{
		overlayUpdates.push_back({ update.routeKey, update.layerKey, update.parameterKey, update.targetValue });
	}

	std::vector<RenderEngine::OscOverlayCommitCompletion> overlayCommitCompletions;
	overlayCommitCompletions.reserve(completedOscCommits.size());
	for (const RuntimeServices::CompletedOscCommit& completedCommit : completedOscCommits)
	{
		overlayCommitCompletions.push_back({ completedCommit.routeKey, completedCommit.generation });
	}

	renderEngine.UpdateOscOverlayState(overlayUpdates, overlayCommitCompletions);
}

void QueueServiceCommitRequests(
	RuntimeServices& runtimeServices,
	const std::vector<RenderEngine::OscOverlayCommitRequest>& commitRequests)
{
	for (const RenderEngine::OscOverlayCommitRequest& commitRequest : commitRequests)
	{
		std::string commitError;
		if (!runtimeServices.QueueOscCommit(
			commitRequest.routeKey,
			commitRequest.layerKey,
			commitRequest.parameterKey,
			commitRequest.value,
			commitRequest.generation,
			commitError) &&
			!commitError.empty())
		{
			OutputDebugStringA(("OSC commit queue failed: " + commitError + "\n").c_str());
		}
	}
}
}

bool RuntimeServiceLiveBridge::PrepareLiveRenderFrameState(
	RuntimeServices& runtimeServices,
	RenderEngine& renderEngine,
	const RenderFrameInput& input,
	RenderFrameState& frameState)
{
	DrainServiceEvents(runtimeServices, renderEngine);

	std::vector<RenderEngine::OscOverlayCommitRequest> commitRequests;
	const bool resolved = renderEngine.ResolveRenderFrameState(input, &commitRequests, frameState);

	QueueServiceCommitRequests(runtimeServices, commitRequests);
	return resolved;
}
