#pragma once

#include "RenderCadenceClock.h"
#include "../runtime/RuntimeShaderArtifact.h"
#include "RuntimeShaderRenderer.h"

#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <mutex>
#include <string>
#include <thread>

class SystemFrameExchange;

class RenderThread
{
public:
	struct Config
	{
		unsigned width = 1920;
		unsigned height = 1080;
		double frameDurationMilliseconds = 1000.0 / 59.94;
		std::size_t pboDepth = 6;
	};

	struct Metrics
	{
		uint64_t renderedFrames = 0;
		uint64_t completedReadbacks = 0;
		uint64_t acquireMisses = 0;
		uint64_t pboQueueMisses = 0;
		uint64_t clockOverruns = 0;
		uint64_t skippedFrames = 0;
		uint64_t shaderBuildsCommitted = 0;
		uint64_t shaderBuildFailures = 0;
	};

	RenderThread(SystemFrameExchange& frameExchange, Config config);
	RenderThread(const RenderThread&) = delete;
	RenderThread& operator=(const RenderThread&) = delete;
	~RenderThread();

	bool Start(std::string& error);
	void Stop();
	void SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact);

	Metrics GetMetrics() const;
	bool IsRunning() const { return mRunning.load(std::memory_order_acquire); }

private:
	void ThreadMain();
	void SignalStarted();
	void SignalStartupFailure(const std::string& error);
	void CountRendered();
	void CountCompleted();
	void CountAcquireMiss();
	void TryCommitReadyRuntimeShader(RuntimeShaderRenderer& runtimeShaderRenderer);
	bool TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact);

	SystemFrameExchange& mFrameExchange;
	Config mConfig;
	std::thread mThread;
	std::atomic<bool> mStopping{ false };
	std::atomic<bool> mRunning{ false };

	mutable std::mutex mStartupMutex;
	std::condition_variable mStartupCondition;
	bool mStarted = false;
	std::string mStartupError;

	std::atomic<uint64_t> mRenderedFrames{ 0 };
	std::atomic<uint64_t> mCompletedReadbacks{ 0 };
	std::atomic<uint64_t> mAcquireMisses{ 0 };
	std::atomic<uint64_t> mPboQueueMisses{ 0 };
	std::atomic<uint64_t> mClockOverruns{ 0 };
	std::atomic<uint64_t> mSkippedFrames{ 0 };
	std::atomic<uint64_t> mShaderBuildsCommitted{ 0 };
	std::atomic<uint64_t> mShaderBuildFailures{ 0 };

	std::mutex mShaderArtifactMutex;
	bool mHasPendingShaderArtifact = false;
	RuntimeShaderArtifact mPendingShaderArtifact;
};
