#pragma once

#include "GLExtensions.h"
#include "ShaderTypes.h"

#include <windows.h>

#include <gl/gl.h>
#include <map>
#include <string>
#include <vector>

struct RuntimeRenderState;

class TemporalHistoryBuffers
{
public:
	struct Slot
	{
		GLuint texture = 0;
		GLuint framebuffer = 0;
	};

	struct Ring
	{
		std::vector<Slot> slots;
		std::size_t nextWriteIndex = 0;
		std::size_t filledCount = 0;
		unsigned effectiveLength = 0;
		TemporalHistorySource historySource = TemporalHistorySource::None;
	};

	bool ValidateTextureUnitBudget(const std::vector<RuntimeRenderState>& layerStates, unsigned historyCap, std::string& error) const;
	bool EnsureResources(const std::vector<RuntimeRenderState>& layerStates, unsigned historyCap, unsigned frameWidth, unsigned frameHeight, std::string& error);
	bool CreateRing(Ring& ring, unsigned effectiveLength, TemporalHistorySource historySource, unsigned frameWidth, unsigned frameHeight, std::string& error);
	void DestroyRing(Ring& ring);
	void DestroyResources();
	void ResetState();
	void PushFramebuffer(GLuint sourceFramebuffer, Ring& ring, unsigned frameWidth, unsigned frameHeight);
	void PushSourceFramebuffer(GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight);
	void PushPreLayerFramebuffer(const std::string& layerId, GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight);
	void BindSamplers(const RuntimeRenderState& state, GLuint currentSourceTexture, unsigned historyCap);
	std::vector<GLuint> ResolveSourceHistoryTextures(GLuint fallbackTexture, unsigned historyCap) const;
	std::vector<GLuint> ResolveTemporalHistoryTextures(const RuntimeRenderState& state, GLuint fallbackTexture, unsigned historyCap) const;
	GLuint ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const;
	unsigned SourceAvailableCount() const;
	unsigned AvailableCountForLayer(const std::string& layerId) const;

private:
	Ring sourceHistoryRing;
	std::map<std::string, Ring> preLayerHistoryByLayerId;
	bool mNeedsReset = true;
};
