#pragma once

#include "RuntimeJson.h"
#include "ShaderPackageCatalog.h"
#include "ShaderTypes.h"

#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <vector>

class LayerStackStore
{
public:
	struct LayerPersistentState
	{
		std::string id;
		std::string shaderId;
		bool bypass = false;
		std::map<std::string, ShaderParameterValue> parameterValues;
	};

	struct StoredParameterSnapshot
	{
		std::string layerId;
		ShaderParameterDefinition definition;
		ShaderParameterValue currentValue;
		bool hasCurrentValue = false;
	};

	bool LoadPersistentStateValue(const JsonValue& root);
	JsonValue BuildPersistentStateValue(const ShaderPackageCatalog& shaderCatalog) const;
	void NormalizeLayerIds();
	void EnsureDefaultsForAllLayers(const ShaderPackageCatalog& shaderCatalog);
	void EnsureDefaultLayer(const ShaderPackageCatalog& shaderCatalog);
	void RemoveLayersWithMissingPackages(const ShaderPackageCatalog& shaderCatalog);

	bool CreateLayer(const ShaderPackageCatalog& shaderCatalog, const std::string& shaderId, std::string& error);
	bool DeleteLayer(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 SetLayerBypassState(const std::string& layerId, bool bypassed, std::string& error);
	bool SetLayerShaderSelection(const ShaderPackageCatalog& shaderCatalog, const std::string& layerId, const std::string& shaderId, std::string& error);
	bool SetParameterValue(const std::string& layerId, const std::string& parameterId, const ShaderParameterValue& value, std::string& error);
	bool ResetLayerParameterValues(const ShaderPackageCatalog& shaderCatalog, const std::string& layerId, std::string& error);

	bool HasLayer(const std::string& layerId) const;
	bool TryGetParameterById(const ShaderPackageCatalog& shaderCatalog, const std::string& layerId, const std::string& parameterId, StoredParameterSnapshot& snapshot, std::string& error) const;
	bool TryGetParameterByControlKey(const ShaderPackageCatalog& shaderCatalog, const std::string& layerKey, const std::string& parameterKey, StoredParameterSnapshot& snapshot, std::string& error) const;
	bool ResolveLayerMove(const std::string& layerId, int direction, bool& shouldMove, std::string& error) const;
	bool ResolveLayerMoveToIndex(const std::string& layerId, std::size_t targetIndex, bool& shouldMove, std::string& error) const;

	JsonValue BuildStackPresetValue(const ShaderPackageCatalog& shaderCatalog, const std::string& presetName) const;
	bool LoadStackPresetValue(const ShaderPackageCatalog& shaderCatalog, const JsonValue& root, std::string& error);
	static std::string MakeSafePresetFileStem(const std::string& presetName);

	const std::vector<LayerPersistentState>& Layers() const;
	std::vector<LayerPersistentState>& Layers();
	std::size_t LayerCount() const;
	const LayerPersistentState* FindLayerById(const std::string& layerId) const;
	LayerPersistentState* FindLayerById(const std::string& layerId);

private:
	static ShaderParameterValue DefaultValueForDefinition(const ShaderParameterDefinition& definition);
	static void EnsureLayerDefaults(LayerPersistentState& layerState, const ShaderPackage& shaderPackage);
	static bool DeserializeLayerStack(const ShaderPackageCatalog& shaderCatalog, const JsonValue& layersValue, std::vector<LayerPersistentState>& layers, uint64_t& nextLayerId, std::string& error);
	static std::string GenerateLayerId(std::vector<LayerPersistentState>& layers, uint64_t& nextLayerId);

	std::vector<LayerPersistentState> mLayers;
	uint64_t mNextLayerId = 0;
};
