#pragma once

#include "GLExtensions.h"
#include "RuntimeShaderProgram.h"
#include "RuntimeTextTextureCache.h"
#include "RuntimeShaderArtifact.h"

#include <cstdint>
#include <string>
#include <vector>

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

	bool CommitPreparedProgram(RuntimePreparedShaderProgram& preparedProgram, std::string& error);
	bool HasProgram() const { return mProgram != 0; }
	void UpdateArtifactState(const RuntimeShaderArtifact& artifact);
	void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint sourceTexture = 0, GLuint layerInputTexture = 0);
	void ShutdownGl();

	static bool BuildPreparedProgram(
		const std::string& layerId,
		const std::string& sourceFingerprint,
		const RuntimeShaderArtifact& artifact,
		RuntimePreparedShaderProgram& preparedProgram);
	static bool BuildPreparedPassProgram(
		const std::string& layerId,
		const std::string& sourceFingerprint,
		const RuntimeShaderArtifact& artifact,
		const RuntimeShaderPassArtifact& passArtifact,
		RuntimePreparedShaderProgram& preparedProgram);

private:
	bool EnsureStaticGlResources(std::string& error);
	static bool CompileShader(GLenum shaderType, const char* source, GLuint& shader, std::string& error);
	static bool BuildProgram(const std::string& fragmentShaderSource, GLuint& program, GLuint& vertexShader, GLuint& fragmentShader, std::string& error);
	static void AssignSamplerUniforms(GLuint program);
	void UpdateGlobalParams(uint64_t frameIndex, unsigned width, unsigned height);
	void BindRuntimeTextures(GLuint sourceTexture, GLuint layerInputTexture);
	void DestroyProgram();
	void DestroyStaticGlResources();

	RuntimeShaderArtifact mArtifact;
	RuntimeTextTextureCache mTextTextures;
	GLuint mProgram = 0;
	GLuint mVertexShader = 0;
	GLuint mFragmentShader = 0;
	GLuint mVertexArray = 0;
	GLuint mGlobalParamsBuffer = 0;
	GLsizeiptr mGlobalParamsBufferSize = 0;
	GLuint mFallbackSourceTexture = 0;
	std::vector<unsigned char> mGlobalParamsScratch;
};
