#pragma once

#include "RuntimeShaderProgram.h"
#include "RuntimeLayerModel.h"

#include <windows.h>

#include <atomic>
#include <condition_variable>
#include <deque>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

class HiddenGlWindow;

class RuntimeShaderPrepareWorker
{
public:
	RuntimeShaderPrepareWorker() = default;
	RuntimeShaderPrepareWorker(const RuntimeShaderPrepareWorker&) = delete;
	RuntimeShaderPrepareWorker& operator=(const RuntimeShaderPrepareWorker&) = delete;
	~RuntimeShaderPrepareWorker();

	bool Start(std::unique_ptr<HiddenGlWindow> sharedWindow, std::string& error);
	void Stop();

	void Submit(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers);
	bool TryConsume(RuntimePreparedShaderProgram& preparedProgram);

private:
	struct PrepareRequest
	{
		std::string layerId;
		std::string shaderId;
		std::string passId;
		std::string sourceFingerprint;
		RuntimeShaderArtifact artifact;
		RuntimeShaderPassArtifact passArtifact;
	};

	void ThreadMain();
	static std::string Fingerprint(const RuntimeShaderArtifact& artifact);

	std::unique_ptr<HiddenGlWindow> mWindow;
	std::mutex mMutex;
	std::condition_variable mCondition;
	std::deque<PrepareRequest> mRequests;
	std::deque<RuntimePreparedShaderProgram> mCompleted;
	std::condition_variable mStartupCondition;
	std::thread mThread;
	std::atomic<bool> mStopping{ false };
	std::atomic<bool> mStarted{ false };
	bool mStartupReady = false;
	std::string mStartupError;
};
