#pragma once

#include <mutex>
#include <cstddef>
#include <cstdint>
#include <string>

// HealthTelemetry owns the current operational status snapshot directly, so
// callers can report health without sharing runtime-store state.
class HealthTelemetry
{
public:
	struct SignalStatusSnapshot
	{
		bool hasSignal = false;
		unsigned width = 0;
		unsigned height = 0;
		std::string modeName;
	};

	struct VideoIOStatusSnapshot
	{
		std::string backendName = "decklink";
		std::string modelName;
		bool supportsInternalKeying = false;
		bool supportsExternalKeying = false;
		bool keyerInterfaceAvailable = false;
		bool externalKeyingRequested = false;
		bool externalKeyingActive = false;
		std::string statusMessage;
	};

	struct PerformanceSnapshot
	{
		double frameBudgetMilliseconds = 0.0;
		double renderMilliseconds = 0.0;
		double smoothedRenderMilliseconds = 0.0;
		double completionIntervalMilliseconds = 0.0;
		double smoothedCompletionIntervalMilliseconds = 0.0;
		double maxCompletionIntervalMilliseconds = 0.0;
		uint64_t lateFrameCount = 0;
		uint64_t droppedFrameCount = 0;
		uint64_t flushedFrameCount = 0;
	};

	struct RuntimeEventQueueSnapshot
	{
		std::string queueName = "runtime-events";
		std::size_t depth = 0;
		std::size_t capacity = 0;
		uint64_t droppedCount = 0;
		double oldestEventAgeMilliseconds = 0.0;
	};

	struct RuntimeEventDispatchSnapshot
	{
		uint64_t dispatchCallCount = 0;
		uint64_t dispatchedEventCount = 0;
		uint64_t handlerInvocationCount = 0;
		uint64_t handlerFailureCount = 0;
		double lastDispatchDurationMilliseconds = 0.0;
		double maxDispatchDurationMilliseconds = 0.0;
	};

	struct RuntimeEventMetricsSnapshot
	{
		RuntimeEventQueueSnapshot queue;
		RuntimeEventDispatchSnapshot dispatch;
	};

	struct PersistenceSnapshot
	{
		uint64_t writeSuccessCount = 0;
		uint64_t writeFailureCount = 0;
		bool lastWriteSucceeded = true;
		bool unsavedChanges = false;
		bool newerRequestPending = false;
		std::string lastTargetKind;
		std::string lastTargetPath;
		std::string lastReason;
		std::string lastErrorMessage;
	};

	struct Snapshot
	{
		SignalStatusSnapshot signal;
		VideoIOStatusSnapshot videoIO;
		PerformanceSnapshot performance;
		RuntimeEventMetricsSnapshot runtimeEvents;
		PersistenceSnapshot persistence;
	};

	HealthTelemetry() = default;

	void ReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
	bool TryReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);

	void ReportVideoIOStatus(const std::string& backendName, const std::string& modelName,
		bool supportsInternalKeying, bool supportsExternalKeying, bool keyerInterfaceAvailable,
		bool externalKeyingRequested, bool externalKeyingActive, const std::string& statusMessage);
	bool TryReportVideoIOStatus(const std::string& backendName, const std::string& modelName,
		bool supportsInternalKeying, bool supportsExternalKeying, bool keyerInterfaceAvailable,
		bool externalKeyingRequested, bool externalKeyingActive, const std::string& statusMessage);

	void RecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);
	bool TryRecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);

	void RecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
		double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
	bool TryRecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
		double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);

	void RecordRuntimeEventQueueMetrics(const std::string& queueName, std::size_t depth, std::size_t capacity,
		uint64_t droppedCount, double oldestEventAgeMilliseconds);
	bool TryRecordRuntimeEventQueueMetrics(const std::string& queueName, std::size_t depth, std::size_t capacity,
		uint64_t droppedCount, double oldestEventAgeMilliseconds);

	void RecordRuntimeEventDispatchStats(std::size_t dispatchedEvents, std::size_t handlerInvocations,
		std::size_t handlerFailures, double dispatchDurationMilliseconds);
	bool TryRecordRuntimeEventDispatchStats(std::size_t dispatchedEvents, std::size_t handlerInvocations,
		std::size_t handlerFailures, double dispatchDurationMilliseconds);

	void RecordPersistenceWriteResult(bool succeeded, const std::string& targetKind, const std::string& targetPath,
		const std::string& reason, const std::string& errorMessage, bool newerRequestPending);
	bool TryRecordPersistenceWriteResult(bool succeeded, const std::string& targetKind, const std::string& targetPath,
		const std::string& reason, const std::string& errorMessage, bool newerRequestPending);

	SignalStatusSnapshot GetSignalStatusSnapshot() const;
	VideoIOStatusSnapshot GetVideoIOStatusSnapshot() const;
	PerformanceSnapshot GetPerformanceSnapshot() const;
	RuntimeEventMetricsSnapshot GetRuntimeEventMetricsSnapshot() const;
	PersistenceSnapshot GetPersistenceSnapshot() const;
	Snapshot GetSnapshot() const;

private:
	mutable std::mutex mMutex;
	SignalStatusSnapshot mSignalStatus;
	VideoIOStatusSnapshot mVideoIOStatus;
	PerformanceSnapshot mPerformance;
	RuntimeEventMetricsSnapshot mRuntimeEvents;
	PersistenceSnapshot mPersistence;
};
