#include "HealthTelemetry.h"

#include <iostream>

namespace
{
int gFailures = 0;

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

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

void TestRuntimeEventQueueMetrics()
{
	HealthTelemetry telemetry;
	telemetry.RecordRuntimeEventQueueMetrics("runtime-events", 3, 64, 2, 12.5);

	const HealthTelemetry::RuntimeEventMetricsSnapshot metrics = telemetry.GetRuntimeEventMetricsSnapshot();
	Expect(metrics.queue.queueName == "runtime-events", "queue metrics store queue name");
	Expect(metrics.queue.depth == 3, "queue metrics store depth");
	Expect(metrics.queue.capacity == 64, "queue metrics store capacity");
	Expect(metrics.queue.droppedCount == 2, "queue metrics store dropped count");
	Expect(metrics.queue.oldestEventAgeMilliseconds == 12.5, "queue metrics store oldest event age");
}

void TestRuntimeEventDispatchStats()
{
	HealthTelemetry telemetry;
	telemetry.RecordRuntimeEventDispatchStats(2, 5, 1, 0.75);
	telemetry.RecordRuntimeEventDispatchStats(3, 6, 0, 0.25);

	const HealthTelemetry::Snapshot snapshot = telemetry.GetSnapshot();
	Expect(snapshot.runtimeEvents.dispatch.dispatchCallCount == 2, "dispatch stats count dispatch calls");
	Expect(snapshot.runtimeEvents.dispatch.dispatchedEventCount == 5, "dispatch stats accumulate dispatched events");
	Expect(snapshot.runtimeEvents.dispatch.handlerInvocationCount == 11, "dispatch stats accumulate handler invocations");
	Expect(snapshot.runtimeEvents.dispatch.handlerFailureCount == 1, "dispatch stats accumulate handler failures");
	Expect(snapshot.runtimeEvents.dispatch.lastDispatchDurationMilliseconds == 0.25, "dispatch stats store latest duration");
	Expect(snapshot.runtimeEvents.dispatch.maxDispatchDurationMilliseconds == 0.75, "dispatch stats store max duration");
}

void TestRuntimeEventTryRecord()
{
	HealthTelemetry telemetry;
	Expect(telemetry.TryRecordRuntimeEventQueueMetrics("runtime-events", 1, 4, 0, -5.0), "try queue metrics succeeds when uncontended");
	Expect(telemetry.TryRecordRuntimeEventDispatchStats(1, 2, 0, -1.0), "try dispatch stats succeeds when uncontended");

	const HealthTelemetry::RuntimeEventMetricsSnapshot metrics = telemetry.GetRuntimeEventMetricsSnapshot();
	Expect(metrics.queue.oldestEventAgeMilliseconds == 0.0, "queue age is clamped to non-negative values");
	Expect(metrics.dispatch.lastDispatchDurationMilliseconds == 0.0, "dispatch duration is clamped to non-negative values");
}

void TestPersistenceWriteHealth()
{
	HealthTelemetry telemetry;
	telemetry.RecordPersistenceWriteResult(false, "runtime-state", "runtime/runtime_state.json", "UpdateLayerParameter",
		"disk full", true);

	HealthTelemetry::PersistenceSnapshot persistence = telemetry.GetPersistenceSnapshot();
	Expect(persistence.writeFailureCount == 1, "persistence health counts write failures");
	Expect(!persistence.lastWriteSucceeded, "persistence health records failed write state");
	Expect(persistence.unsavedChanges, "persistence health reports unsaved changes after failure");
	Expect(persistence.newerRequestPending, "persistence health records pending newer request");
	Expect(persistence.lastTargetKind == "runtime-state", "persistence health records target kind");
	Expect(persistence.lastReason == "UpdateLayerParameter", "persistence health records reason");
	Expect(persistence.lastErrorMessage == "disk full", "persistence health records error message");

	Expect(telemetry.TryRecordPersistenceWriteResult(true, "runtime-state", "runtime/runtime_state.json", "flush", "", false),
		"try persistence health succeeds when uncontended");
	persistence = telemetry.GetPersistenceSnapshot();
	Expect(persistence.writeSuccessCount == 1, "persistence health counts write successes");
	Expect(persistence.lastWriteSucceeded, "persistence health records successful write state");
	Expect(!persistence.unsavedChanges, "persistence health clears unsaved changes after latest successful write with no pending request");
}
}

int main()
{
	TestRuntimeEventQueueMetrics();
	TestRuntimeEventDispatchStats();
	TestRuntimeEventTryRecord();
	TestPersistenceWriteHealth();

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

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