#include "RuntimeShaderBridge.h"

#include <chrono>

RuntimeShaderBridge::~RuntimeShaderBridge()
{
	Stop();
}

void RuntimeShaderBridge::Start(const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
{
	Start(std::string(), shaderId, std::move(onArtifactReady), std::move(onError));
}

void RuntimeShaderBridge::Start(const std::string& layerId, const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
{
	Stop();
	if (shaderId.empty())
		return;

	mLayerId = layerId;
	mOnArtifactReady = std::move(onArtifactReady);
	mOnError = std::move(onError);
	mStopping.store(false, std::memory_order_release);
	mFinished.store(false, std::memory_order_release);
	mCompiler.StartShaderBuild(shaderId);
	mThread = std::thread([this]() { ThreadMain(); });
}

void RuntimeShaderBridge::RequestStop()
{
	mStopping.store(true, std::memory_order_release);
}

void RuntimeShaderBridge::Stop()
{
	RequestStop();
	if (mThread.joinable())
		mThread.join();
	mCompiler.Stop();
	mLayerId.clear();
	mOnArtifactReady = ArtifactCallback();
	mOnError = ErrorCallback();
	mFinished.store(true, std::memory_order_release);
}

bool RuntimeShaderBridge::CanStopWithoutWaiting() const
{
	return mFinished.load(std::memory_order_acquire) && !mCompiler.Running();
}

void RuntimeShaderBridge::ThreadMain()
{
	while (!mStopping.load(std::memory_order_acquire))
	{
		RuntimeSlangShaderBuild build;
		if (mCompiler.TryConsume(build))
		{
			if (build.succeeded)
			{
				build.artifact.layerId = mLayerId;
				if (mOnArtifactReady)
					mOnArtifactReady(build.artifact);
			}
			else if (mOnError)
			{
				mOnError(build.message);
			}
			mFinished.store(true, std::memory_order_release);
			return;
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(5));
	}
	mFinished.store(true, std::memory_order_release);
}
