#include "RuntimeStateLayerModel.h"

#include <iostream>

namespace
{
int gFailures = 0;

void Expect(bool condition, const char* message)
{
	if (condition)
		return;

	std::cerr << "FAIL: " << message << "\n";
	++gFailures;
}

void TestLayerPrecedence()
{
	Expect(RuntimeStateLayerCompositionPrecedence(RuntimeStateLayerKind::BasePersisted) == 0,
		"base persisted state is the first composition layer");
	Expect(RuntimeStateLayerCompositionPrecedence(RuntimeStateLayerKind::CommittedLive) == 1,
		"committed live state overlays persisted state");
	Expect(RuntimeStateLayerCompositionPrecedence(RuntimeStateLayerKind::TransientAutomation) == 2,
		"transient automation overlays committed state");
	Expect(!RuntimeStateLayerParticipatesInParameterComposition(RuntimeStateLayerKind::RenderLocal),
		"render-local state does not participate in parameter composition");
	Expect(!RuntimeStateLayerParticipatesInParameterComposition(RuntimeStateLayerKind::HealthConfig),
		"health/config state does not participate in parameter composition");
}

void TestFieldClassification()
{
	Expect(ClassifyRuntimeStateField(RuntimeStateField::PersistedLayerStack) == RuntimeStateLayerKind::BasePersisted,
		"layer stack is base persisted state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::PersistedParameterValues) == RuntimeStateLayerKind::BasePersisted,
		"saved parameters are base persisted state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::CommittedSessionParameterValues) == RuntimeStateLayerKind::CommittedLive,
		"session parameter values are committed live state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::RuntimeCompileReloadFlags) == RuntimeStateLayerKind::CommittedLive,
		"compile/reload flags are committed session coordination state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::TransientOscOverlay) == RuntimeStateLayerKind::TransientAutomation,
		"OSC overlays are transient automation state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::TransientAutomationCommitState) == RuntimeStateLayerKind::TransientAutomation,
		"overlay commit generations are transient automation state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::RenderLocalTemporalHistory) == RuntimeStateLayerKind::RenderLocal,
		"temporal history is render-local state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::RenderLocalFeedbackState) == RuntimeStateLayerKind::RenderLocal,
		"feedback state is render-local state");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::RuntimeConfiguration) == RuntimeStateLayerKind::HealthConfig,
		"runtime configuration is outside parameter composition");
	Expect(ClassifyRuntimeStateField(RuntimeStateField::HealthTelemetry) == RuntimeStateLayerKind::HealthConfig,
		"health telemetry is outside parameter composition");
}

void TestInventoriesStayInSyncWithEnums()
{
	const std::vector<RuntimeStateLayerDescriptor> layers = GetRuntimeStateLayerInventory();
	Expect(layers.size() == 5, "layer inventory names all Phase 5 state categories");

	const std::vector<RuntimeStateFieldDescriptor> fields = GetRuntimeStateFieldInventory();
	Expect(fields.size() == 14, "field inventory names current state categories");
	for (const RuntimeStateFieldDescriptor& field : fields)
	{
		Expect(field.layerKind == ClassifyRuntimeStateField(field.field),
			"field inventory layer kind matches classifier");
		Expect(field.name != nullptr && field.name[0] != '\0', "field inventory has a display name");
		Expect(field.currentOwner != nullptr && field.currentOwner[0] != '\0', "field inventory has an owner");
	}
}
}

int main()
{
	TestLayerPrecedence();
	TestFieldClassification();
	TestInventoriesStayInSyncWithEnums();

	if (gFailures != 0)
	{
		std::cerr << gFailures << " RuntimeStateLayerModel test failure(s).\n";
		return 1;
	}

	std::cout << "RuntimeStateLayerModel tests passed.\n";
	return 0;
}

