#ifndef __OPENGL_COMPOSITE_H__
#define __OPENGL_COMPOSITE_H__

#include <windows.h>
#include <objbase.h>

#include "RenderFrameState.h"

#include <filesystem>
#include <memory>
#include <string>

class RenderEngine;
class RuntimeCoordinator;
class RuntimeEventDispatcher;
class RuntimeSnapshotProvider;
class RuntimeServices;
class RuntimeStore;
class RuntimeUpdateController;
class ShaderBuildQueue;
class VideoBackend;


class OpenGLComposite
{
public:
	OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC);
	~OpenGLComposite();

	bool InitDeckLink();
	bool InitVideoIO();
	bool Start();
	bool Stop();
	bool ReloadShader(bool preserveFeedbackState = false);
	std::string GetRuntimeStateJson() const;
	bool AddLayer(const std::string& shaderId, std::string& error);
	bool RemoveLayer(const std::string& layerId, std::string& error);
	bool MoveLayer(const std::string& layerId, int direction, std::string& error);
	bool MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error);
	bool SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error);
	bool SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error);
	bool UpdateLayerParameterJson(const std::string& layerId, const std::string& parameterId, const std::string& valueJson, std::string& error);
	bool UpdateLayerParameterByControlKeyJson(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error);
	bool ResetLayerParameters(const std::string& layerId, std::string& error);
	bool SaveStackPreset(const std::string& presetName, std::string& error);
	bool LoadStackPreset(const std::string& presetName, std::string& error);
	bool RequestScreenshot(std::string& error);
	unsigned short GetControlServerPort() const;
	unsigned short GetOscPort() const;
	std::string GetOscBindAddress() const;
	std::string GetControlUrl() const;
	std::string GetDocsUrl() const;
	std::string GetOscAddress() const;

	void resizeGL(WORD width, WORD height);
	void paintGL(bool force = false);

private:
	void resizeWindow(int width, int height);
	bool CheckOpenGLExtensions();

	HWND									hGLWnd;
	HDC										hGLDC;
	HGLRC									hGLRC;

	std::unique_ptr<RuntimeStore>			mRuntimeStore;
	std::unique_ptr<RuntimeCoordinator>		mRuntimeCoordinator;
	std::unique_ptr<RuntimeSnapshotProvider>	mRuntimeSnapshotProvider;
	std::unique_ptr<RuntimeEventDispatcher>	mRuntimeEventDispatcher;
	std::unique_ptr<RenderEngine>			mRenderEngine;
	std::unique_ptr<ShaderBuildQueue>		mShaderBuildQueue;
	std::unique_ptr<RuntimeServices>		mRuntimeServices;
	std::unique_ptr<RuntimeUpdateController> mRuntimeUpdateController;
	std::unique_ptr<VideoBackend>			mVideoBackend;

	bool InitOpenGLState();
	void renderEffect();
	RenderFrameInput BuildRenderFrameInput() const;
	void RenderFrame(const RenderFrameInput& frameInput);
	std::filesystem::path BuildScreenshotPath() const;
};

#endif		// __OPENGL_COMPOSITE_H__
