Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Diagnostics
Imports System.Linq

Namespace Nexamas.UI.Virtualization

    ''' <summary>
    ''' Deterministic benchmark suite for MASVirtualizedItemsSystem. The suite validates 1k/10k/100k item counts, fast scroll,
    ''' scroll-to-index, selection-range independence, resize planning, and automatic invalidation through the same controller
    ''' contracts used by controls. It does not create UI, render, access files, or depend on wall-clock thresholds.
    ''' </summary>
    Friend NotInheritable Class MASVirtualizationBenchmarkSuite

        Private Shared ReadOnly DefaultScenarios As IReadOnlyList(Of MASVirtualizationBenchmarkScenario) =
            New ReadOnlyCollection(Of MASVirtualizationBenchmarkScenario)(New MASVirtualizationBenchmarkScenario() {
                New MASVirtualizationBenchmarkScenario("items-1000", 1000, 24.0F, 240.0F, 900, 3),
                New MASVirtualizationBenchmarkScenario("items-10000", 10000, 24.0F, 240.0F, 9000, 3),
                New MASVirtualizationBenchmarkScenario("items-100000", 100000, 20.0F, 320.0F, 50000, 2),
                New MASVirtualizationBenchmarkScenario("fast-scroll", 100000, 20.0F, 320.0F, 99000, 2),
                New MASVirtualizationBenchmarkScenario("scroll-to-index", 100000, 20.0F, 320.0F, 75000, 2),
                New MASVirtualizationBenchmarkScenario("resize", 10000, 24.0F, 640.0F, 5000, 3),
                New MASVirtualizationBenchmarkScenario("theme-dpi-invalidation", 10000, 24.0F, 240.0F, 4000, 3)
            })

        Private Sub New()
        End Sub

        Friend Shared Function RunDefault() As IReadOnlyList(Of MASVirtualizationBenchmarkResult)
            Return Run(DefaultScenarios)
        End Function

        Friend Shared Function BuildDefaultSummary() As MASVirtualizationBenchmarkSummary
            Return Summarize(RunDefault())
        End Function

        Friend Shared Function Summarize(results As IEnumerable(Of MASVirtualizationBenchmarkResult)) As MASVirtualizationBenchmarkSummary
            Return New MASVirtualizationBenchmarkSummary(results)
        End Function

        Friend Shared Function Run(scenarios As IEnumerable(Of MASVirtualizationBenchmarkScenario)) As IReadOnlyList(Of MASVirtualizationBenchmarkResult)
            Dim results = New List(Of MASVirtualizationBenchmarkResult)()
            For Each scenario In If(scenarios, Enumerable.Empty(Of MASVirtualizationBenchmarkScenario)()).Where(Function(item) item IsNot Nothing)
                results.Add(RunOne(scenario))
            Next

            Return New ReadOnlyCollection(Of MASVirtualizationBenchmarkResult)(results)
        End Function

        Private Shared Function RunOne(scenario As MASVirtualizationBenchmarkScenario) As MASVirtualizationBenchmarkResult
            If scenario Is Nothing OrElse Not scenario.IsValid Then
                Return New MASVirtualizationBenchmarkResult(scenario, 0, 0, 0, 0, False, False, Nothing)
            End If

            Dim options = New MASVirtualizationOptions(scenario.ItemCount,
                                                       scenario.EstimatedItemExtentPx,
                                                       scenario.OverscanItemCount,
                                                       MASVirtualizationAxis.Vertical,
                                                       scenario.ExtentStrategy)
            Dim controller = New MASVirtualizedItemsController(options)
            Dim autoInvalidation = New MASVirtualizationAutoInvalidationCoordinator()
            Dim benchmarkTimer As Global.System.Diagnostics.Stopwatch = Global.System.Diagnostics.Stopwatch.StartNew()

            controller.RecordMeasuredExtent(0, scenario.EstimatedItemExtentPx * 1.5F)
            controller.RecordMeasuredExtent(Math.Max(0, scenario.TargetIndex \ 2), scenario.EstimatedItemExtentPx * 1.25F)
            controller.RecordMeasuredExtent(Math.Min(scenario.ItemCount - 1, scenario.TargetIndex), scenario.EstimatedItemExtentPx * 1.75F)

            controller.Update(New MASVirtualizationViewport(0.0F, scenario.ViewportExtentPx))

            Dim request = controller.CreateScrollToIndexRequest(scenario.TargetIndex,
                                                                New MASVirtualizationViewport(0.0F, scenario.ViewportExtentPx),
                                                                MASVirtualizationAlignment.Start)
            Dim plan = controller.Update(New MASVirtualizationViewport(request.TargetOffsetPx, scenario.ViewportExtentPx))

            If scenario.Id = "fast-scroll" Then
                Dim stepExtent = scenario.EstimatedItemExtentPx * 333.0F
                For stepIndex = 1 To 8
                    controller.Update(New MASVirtualizationViewport(stepExtent * CSng(stepIndex), scenario.ViewportExtentPx))
                Next
                request = controller.CreateScrollToIndexRequest(scenario.TargetIndex,
                                                                New MASVirtualizationViewport(0.0F, scenario.ViewportExtentPx),
                                                                MASVirtualizationAlignment.Start)
                plan = controller.Update(New MASVirtualizationViewport(request.TargetOffsetPx, scenario.ViewportExtentPx))
            ElseIf scenario.Id = "resize" Then
                plan = controller.Update(New MASVirtualizationViewport(request.TargetOffsetPx, scenario.ViewportExtentPx * 0.5F))
                plan = controller.Update(New MASVirtualizationViewport(request.TargetOffsetPx, scenario.ViewportExtentPx))
            ElseIf scenario.Id = "theme-dpi-invalidation" Then
                Dim baselineStamp = MASVirtualizationEnvironmentStampBuilder.Create() _
                    .WithThemeRevision(1) _
                    .WithDpiRevision(1) _
                    .WithDensityRevision(1) _
                    .WithFontRevision(1) _
                    .WithLocalizationRevision(1) _
                    .WithRtlRevision(1) _
                    .WithItemCollectionRevision(1) _
                    .WithControlSizeRevision(1) _
                    .WithViewportExtentPx(scenario.ViewportExtentPx) _
                    .Build()
                Dim changedThemeStamp = MASVirtualizationEnvironmentStampBuilder.FromStamp(baselineStamp) _
                    .WithThemeRevision(2) _
                    .Build()
                autoInvalidation.Evaluate(baselineStamp, controller)
                autoInvalidation.Evaluate(changedThemeStamp, controller)
                request = controller.CreateScrollToIndexRequest(scenario.TargetIndex,
                                                                New MASVirtualizationViewport(0.0F, scenario.ViewportExtentPx),
                                                                MASVirtualizationAlignment.Start)
                plan = controller.Update(New MASVirtualizationViewport(request.TargetOffsetPx, scenario.ViewportExtentPx))
            End If

            Dim selection = MASVirtualizationSelectionState.Empty().SelectRange(Math.Max(0, scenario.TargetIndex - 5), scenario.TargetIndex).Toggle(Math.Min(scenario.ItemCount - 1, scenario.TargetIndex + 10))
            If Not selection.Contains(scenario.TargetIndex) Then
                benchmarkTimer.Stop()
                Return New MASVirtualizationBenchmarkResult(scenario, plan.RealizedCount, controller.DiagnosticsSnapshot.MeasurementCount, controller.DiagnosticsSnapshot.MeasurementRevision, benchmarkTimer.ElapsedTicks, False, False, controller.DiagnosticsSnapshot)
            End If

            benchmarkTimer.Stop()
            Dim diagnostics = controller.DiagnosticsSnapshot
            Dim scrollCorrect = request IsNot Nothing AndAlso request.Index = Math.Min(scenario.ItemCount - 1, scenario.TargetIndex)
            Dim containsTarget = plan IsNot Nothing AndAlso plan.Range IsNot Nothing AndAlso plan.Range.Contains(Math.Min(scenario.ItemCount - 1, scenario.TargetIndex))

            Return New MASVirtualizationBenchmarkResult(scenario,
                                                        If(plan IsNot Nothing, plan.RealizedCount, 0),
                                                        diagnostics.MeasurementCount,
                                                        diagnostics.MeasurementRevision,
                                                        benchmarkTimer.ElapsedTicks,
                                                        scrollCorrect,
                                                        containsTarget,
                                                        diagnostics)
        End Function

    End Class

End Namespace
