Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Performance
Imports Nexamas.UI.Virtualization

Namespace Nexamas.UI.DiagnosticsDashboard

    ''' <summary>
    ''' Read-only diagnostics dashboard foundation builder.
    ''' </summary>
    ''' <remarks>
    ''' This builder only joins existing MASPerformanceSystem, layout-owner, and VirtualizationSystem facts.
    ''' It does not record counters, execute benchmarks, walk controls, create forms, render, allocate bitmaps,
    ''' schedule frames, mutate UI, or expose a public telemetry API.
    ''' </remarks>
    Friend NotInheritable Class MASDiagnosticsDashboardBuilder

        Friend Const OfficialDashboardName As String = "Nexamas UI Diagnostics Dashboard Foundation"

        Private Sub New()
        End Sub

        Friend Shared Function CreateCurrent(Optional layoutSnapshot As MASDiagnosticsDashboardLayoutSnapshot = Nothing,
                                             Optional virtualizationSnapshot As MASVirtualizationDiagnosticsSnapshot = Nothing,
                                             Optional baselineBenchmarkReport As MASPerformanceBaselineBenchmarkReport = Nothing) As MASDiagnosticsDashboardSnapshot
            Return CreateSnapshot(MASPerformanceSystem.CreateSnapshot(), layoutSnapshot, virtualizationSnapshot, baselineBenchmarkReport)
        End Function

        Friend Shared Function CreateSnapshot(performanceSnapshot As MASPerformanceSnapshot,
                                              layoutSnapshot As MASDiagnosticsDashboardLayoutSnapshot,
                                              virtualizationSnapshot As MASVirtualizationDiagnosticsSnapshot) As MASDiagnosticsDashboardSnapshot
            Return CreateSnapshot(performanceSnapshot, layoutSnapshot, virtualizationSnapshot, Nothing)
        End Function

        Friend Shared Function CreateSnapshot(performanceSnapshot As MASPerformanceSnapshot,
                                              layoutSnapshot As MASDiagnosticsDashboardLayoutSnapshot,
                                              virtualizationSnapshot As MASVirtualizationDiagnosticsSnapshot,
                                              baselineBenchmarkReport As MASPerformanceBaselineBenchmarkReport) As MASDiagnosticsDashboardSnapshot
            Dim performance As MASPerformanceSnapshot = If(performanceSnapshot, MASPerformanceSystem.CreateSnapshot())
            Dim layoutFacts As MASDiagnosticsDashboardLayoutSnapshot = If(layoutSnapshot, MASDiagnosticsDashboardLayoutSnapshot.Empty)
            Dim baselineReference As MASDiagnosticsDashboardBaselineReference = MASDiagnosticsDashboardBaselineReference.FromReport(baselineBenchmarkReport)
            Dim metrics As New List(Of MASDiagnosticsDashboardMetric)()

            metrics.Add(RenderTimeMetric(performance))
            metrics.Add(RenderStageMetric(performance))
            metrics.Add(LayoutPassMetric(performance, layoutFacts))
            metrics.Add(ElementCountMetric(layoutFacts))
            metrics.Add(SlowFramesMetric(performance))
            metrics.Add(InvalidationMetric(performance))
            AddVirtualizationMetrics(metrics, performance, virtualizationSnapshot)
            AddBaselineBenchmarkMetrics(metrics, baselineReference)

            Return New MASDiagnosticsDashboardSnapshot(metrics.ToArray(), OfficialDashboardName)
        End Function

        Private Shared Function RenderTimeMetric(performance As MASPerformanceSnapshot) As MASDiagnosticsDashboardMetric
            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.RenderTime,
                "Render time",
                performance.LastFrameElapsedMs,
                "ms",
                "PerformanceSystem.Frame",
                performance.FrameCompletions > 0L,
                performance.LastFrameElapsedMs >= MASPerformanceSystem.FrameBudget.WarningMs,
                "Last completed frame duration from the official PerformanceSystem snapshot.")
        End Function

        Private Shared Function RenderStageMetric(performance As MASPerformanceSnapshot) As MASDiagnosticsDashboardMetric
            Dim source As String = "PerformanceSystem.RenderStage"
            If Not String.IsNullOrWhiteSpace(performance.LastRenderStageName) Then
                source &= ":" & performance.LastRenderStageName
            End If

            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.RenderStageTime,
                "Render stage time",
                performance.LastRenderStageElapsedMs,
                "ms",
                source,
                performance.RenderStageSamples > 0L,
                performance.LastRenderStageElapsedMs >= MASPerformanceSystem.RenderStageBudget.WarningMs,
                "Last measured render-stage duration from the official PerformanceSystem snapshot.")
        End Function

        Private Shared Function LayoutPassMetric(performance As MASPerformanceSnapshot,
                                                 layoutFacts As MASDiagnosticsDashboardLayoutSnapshot) As MASDiagnosticsDashboardMetric
            Dim value As Double = CDbl(If(layoutFacts.FactsAvailable, layoutFacts.LayoutPassCount, performance.ConsumerLayoutRefreshes))
            Dim source As String = If(layoutFacts.FactsAvailable, "LayoutOwner:" & layoutFacts.OwnerName, "PerformanceSystem.ConsumerLayoutRefreshes")

            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.LayoutPasses,
                "Layout passes",
                value,
                "passes",
                source,
                layoutFacts.FactsAvailable OrElse performance.ConsumerLayoutRefreshes > 0L,
                False,
                "Read-only layout pass count supplied by the layout owner, with PerformanceSystem layout pressure as fallback only after a recorded layout refresh exists.")
        End Function

        Private Shared Function ElementCountMetric(layoutFacts As MASDiagnosticsDashboardLayoutSnapshot) As MASDiagnosticsDashboardMetric
            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.ElementCount,
                "Element count",
                CDbl(layoutFacts.ElementCount),
                "elements",
                If(layoutFacts.FactsAvailable, "LayoutOwner:" & layoutFacts.OwnerName, "LayoutOwner"),
                layoutFacts.FactsAvailable,
                False,
                "Read-only element count supplied by the owning application/layout surface.")
        End Function

        Private Shared Function SlowFramesMetric(performance As MASPerformanceSnapshot) As MASDiagnosticsDashboardMetric
            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.SlowFrames,
                "Slow frames",
                CDbl(performance.SlowFrames),
                "frames",
                "PerformanceSystem.Frame",
                True,
                performance.SlowFrames > 0L,
                "Aggregate slow-frame count from the official PerformanceSystem snapshot.")
        End Function

        Private Shared Function InvalidationMetric(performance As MASPerformanceSnapshot) As MASDiagnosticsDashboardMetric
            Return New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.InvalidationRequests,
                "Invalidation requests",
                CDbl(performance.InvalidateRequests),
                "requests",
                "PerformanceSystem.Invalidation",
                True,
                False,
                "Aggregate invalidation pressure from the official PerformanceSystem snapshot.")
        End Function

        Private Shared Sub AddVirtualizationMetrics(metrics As List(Of MASDiagnosticsDashboardMetric),
                                                    performance As MASPerformanceSnapshot,
                                                    virtualizationSnapshot As MASVirtualizationDiagnosticsSnapshot)
            Dim hasVirtualizationSnapshot As Boolean = virtualizationSnapshot IsNot Nothing
            Dim itemCount As Integer = If(hasVirtualizationSnapshot, virtualizationSnapshot.ItemCount, performance.LastVirtualizationItemCount)
            Dim realizedCount As Integer = If(hasVirtualizationSnapshot, virtualizationSnapshot.RealizedCount, performance.LastVirtualizationRealizedCount)
            Dim measurementCount As Integer = If(hasVirtualizationSnapshot, virtualizationSnapshot.MeasurementCount, performance.LastVirtualizationMeasurementCount)
            Dim source As String = If(hasVirtualizationSnapshot, "VirtualizationSystem.DiagnosticsSnapshot", "PerformanceSystem.VirtualizationSnapshot")
            Dim available As Boolean = hasVirtualizationSnapshot OrElse performance.VirtualizationPlanUpdates > 0L
            Dim ratio As Double = 0.0R

            If itemCount > 0 Then
                ratio = CDbl(Math.Max(0, realizedCount)) / CDbl(itemCount)
            End If

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.VirtualizedItemCount,
                "Virtualized items",
                CDbl(itemCount),
                "items",
                source,
                available,
                False,
                "Total virtualized item count from VirtualizationSystem or the PerformanceSystem virtualization snapshot."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.VirtualizedRealizedCount,
                "Realized items",
                CDbl(realizedCount),
                "items",
                source,
                available,
                False,
                "Currently realized item count from VirtualizationSystem or the PerformanceSystem virtualization snapshot."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.VirtualizationRealizationRatio,
                "Realization ratio",
                ratio,
                "ratio",
                source,
                available AndAlso itemCount > 0,
                itemCount > 0 AndAlso ratio > 0.35R,
                "Realized item count divided by total virtualized item count; high ratios can flag virtualization pressure."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.VirtualizationMeasurementCount,
                "Virtualization measurements",
                CDbl(measurementCount),
                "measurements",
                source,
                available,
                False,
                "Measurement cache size/revision pressure exposed as a read-only dashboard row."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.VirtualizationMeasurementCacheRequests,
                "Virtualization measurement cache requests",
                CDbl(performance.VirtualizationMeasurementCacheHits + performance.VirtualizationMeasurementCacheMisses),
                "requests",
                "PerformanceSystem.VirtualizationMeasurementCache",
                True,
                False,
                "Read-only virtualization measurement cache request pressure from PerformanceSystem."))
        End Sub

        Private Shared Sub AddBaselineBenchmarkMetrics(metrics As List(Of MASDiagnosticsDashboardMetric),
                                                       baselineReference As MASDiagnosticsDashboardBaselineReference)
            Dim baseline As MASDiagnosticsDashboardBaselineReference = If(baselineReference, MASDiagnosticsDashboardBaselineReference.Unavailable)
            Dim source As String = If(baseline.IsAvailable, "PerformanceSystem.BaselinePerformanceBenchmarks:" & baseline.BaselineId, "PerformanceSystem.BaselinePerformanceBenchmarks")
            Dim readyValue As Double = If(baseline.ReadyForRegressionComparison, 1.0R, 0.0R)

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.BaselineBenchmarkReadiness,
                "Baseline benchmark readiness",
                readyValue,
                "ready",
                source,
                baseline.IsAvailable,
                baseline.HasRegressionRiskWarning,
                "Read-only readiness flag from the already-built Baseline Performance Benchmarks report."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.BaselineBenchmarkEntryCount,
                "Baseline benchmark entries",
                CDbl(baseline.EntryCount),
                "entries",
                source,
                baseline.IsAvailable,
                baseline.IsAvailable AndAlso Not baseline.HasRequiredCoverage,
                "Number of official baseline benchmark rows available for dashboard context."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.BaselineBenchmarkReadyEntryCount,
                "Baseline benchmark ready entries",
                CDbl(baseline.ReadyEntryCount),
                "entries",
                source,
                baseline.IsAvailable,
                baseline.IsAvailable AndAlso baseline.ReadyEntryCount < baseline.RequiredBenchmarkCount,
                "Number of baseline benchmark rows ready for future regression comparison."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.BaselineBenchmarkWarningCount,
                "Baseline benchmark warnings",
                CDbl(baseline.WarningCount),
                "warnings",
                source,
                baseline.IsAvailable,
                baseline.WarningCount > 0,
                "Warning rows from the PerformanceSystem-owned baseline benchmark report."))

            metrics.Add(New MASDiagnosticsDashboardMetric(
                MASDiagnosticsDashboardMetricKind.BaselineBenchmarkFailedCount,
                "Baseline benchmark failures",
                CDbl(baseline.FailedCount),
                "failures",
                source,
                baseline.IsAvailable,
                baseline.FailedCount > 0,
                "Failed rows from the PerformanceSystem-owned baseline benchmark report."))
        End Sub

    End Class

End Namespace
