Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Diagnostics

Namespace Nexamas.UI.Virtualization

    ''' <summary>
    ''' Proves that virtualization-backed controls report input/render fallback failures through
    ''' stable runtime-fault diagnostics and that strict mode converts swallowed failures to test
    ''' failures. The proof is synthetic by design: it validates the official diagnostic boundary
    ''' without constructing UI controls or adding a parallel rendering/input path.
    ''' </summary>
    Friend NotInheritable Class MASVirtualizationConsumerDiagnosticsGate

        Private Shared ReadOnly RequiredContexts As String() = {
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseMove,
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseDown,
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseUp,
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseWheel,
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseLeave,
            MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseCancel,
            MASVirtualizationConsumerDiagnosticContexts.DropDownResolveContext,
            MASVirtualizationConsumerDiagnosticContexts.DropDownCreateScroll,
            MASVirtualizationConsumerDiagnosticContexts.DropDownRequestInvalidate,
            MASVirtualizationConsumerDiagnosticContexts.DropDownRestoreScrollOffset,
            MASVirtualizationConsumerDiagnosticContexts.DropDownEnsureSelectedVisible
        }

        Private Shared ReadOnly RequiredDiagnosticCodes As MASVirtualizationConsumerDiagnosticCode() = {
            MASVirtualizationConsumerDiagnosticCode.TileBoxPointerMoveFallback,
            MASVirtualizationConsumerDiagnosticCode.TileBoxPointerDownFallback,
            MASVirtualizationConsumerDiagnosticCode.TileBoxPointerUpFallback,
            MASVirtualizationConsumerDiagnosticCode.TileBoxWheelFallback,
            MASVirtualizationConsumerDiagnosticCode.TileBoxPointerLeaveFallback,
            MASVirtualizationConsumerDiagnosticCode.TileBoxPointerCancelFallback,
            MASVirtualizationConsumerDiagnosticCode.DropDownContextProviderFallback,
            MASVirtualizationConsumerDiagnosticCode.DropDownScrollFactoryFallback,
            MASVirtualizationConsumerDiagnosticCode.DropDownInvalidateFallback,
            MASVirtualizationConsumerDiagnosticCode.DropDownRestoreScrollOffsetFallback,
            MASVirtualizationConsumerDiagnosticCode.DropDownEnsureSelectedVisibleFallback
        }

        Private Sub New()
        End Sub

        Friend Shared Function EvaluateCriticalConsumers() As MASVirtualizationConsumerDiagnosticsReport
            Dim previousThrowOnAny As Boolean = MASExceptionSilencer.ThrowOnSwallowedException
            Dim previousThrowOnLifecycle As Boolean = MASExceptionSilencer.ThrowOnLifecycleBreakingException
            Dim previousTraceRepeated As Boolean = MASExceptionSilencer.TraceRepeatedBoundaryExceptions

            Try
                MASExceptionSilencer.ConfigureStrictness(False, False, True)
                MASRuntimeFaultChannel.ResetForTests()
                MASVirtualizationConsumerFaultDiagnostics.ResetForTests()

                PublishSyntheticConsumerFaults()
                Dim strictModeThrows As Boolean = ProbeStrictModeThrow()

                Dim snapshot As IReadOnlyList(Of MASRuntimeFaultRecord) = MASRuntimeFaultChannel.GetRecentFaultsSnapshot()
                Dim publishedContexts As List(Of String) = ExtractPublishedRequiredContexts(snapshot)
                Dim publishedCodes As List(Of String) = ExtractPublishedRequiredCodes(snapshot)
                Dim hasRenderFallback As Boolean = HasCategory(snapshot, MASExceptionHandlingCategory.RenderFallback)
                Dim hasInputBoundary As Boolean = HasCategory(snapshot, MASExceptionHandlingCategory.InputBoundary)
                Dim structuredFaultReport As MASVirtualizationConsumerFaultDiagnosticReport = MASVirtualizationConsumerFaultDiagnostics.GetReport()

                Return New MASVirtualizationConsumerDiagnosticsReport(
                    RequiredContexts,
                    publishedContexts,
                    RequiredDiagnosticCodeNames(),
                    publishedCodes,
                    strictModeThrows,
                    hasRenderFallback,
                    hasInputBoundary,
                    structuredFaultReport)
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASVirtualizationConsumerDiagnosticsGate.EvaluateCriticalConsumers")
                Return New MASVirtualizationConsumerDiagnosticsReport(RequiredContexts, Array.Empty(Of String)(), RequiredDiagnosticCodeNames(), Array.Empty(Of String)(), False, False, False, Nothing)
            Finally
                MASExceptionSilencer.ConfigureStrictness(previousThrowOnAny, previousThrowOnLifecycle, previousTraceRepeated)
            End Try
        End Function

        Private Shared Sub PublishSyntheticConsumerFaults()
            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox hover fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxPointerMoveFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseMove)

            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox mouse-down fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxPointerDownFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseDown)

            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox mouse-up fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxPointerUpFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseUp)

            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox wheel fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxWheelFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseWheel)

            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox leave fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxPointerLeaveFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseLeave)

            MASVirtualizationConsumerFaultBoundary.SwallowRenderFallback(
                New InvalidOperationException("Synthetic TileBox cancel fallback diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.TileBoxPointerCancelFallback,
                "MASTileBox",
                MASVirtualizationConsumerDiagnosticContexts.TileBoxOnMouseCancel)

            MASVirtualizationConsumerFaultBoundary.SwallowRecoverable(
                New InvalidOperationException("Synthetic DropDown context-provider diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.DropDownContextProviderFallback,
                "MASDropDownListFloatContent",
                MASVirtualizationConsumerDiagnosticContexts.DropDownResolveContext)

            MASVirtualizationConsumerFaultBoundary.SwallowInputBoundary(
                New InvalidOperationException("Synthetic DropDown scroll-factory diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.DropDownScrollFactoryFallback,
                "MASDropDownListFloatContent",
                MASVirtualizationConsumerDiagnosticContexts.DropDownCreateScroll)

            MASVirtualizationConsumerFaultBoundary.SwallowInputBoundary(
                New InvalidOperationException("Synthetic DropDown invalidate diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.DropDownInvalidateFallback,
                "MASDropDownListFloatContent",
                MASVirtualizationConsumerDiagnosticContexts.DropDownRequestInvalidate)

            MASVirtualizationConsumerFaultBoundary.SwallowInputBoundary(
                New InvalidOperationException("Synthetic DropDown restore-scroll-offset diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.DropDownRestoreScrollOffsetFallback,
                "MASDropDownListFloatContent",
                MASVirtualizationConsumerDiagnosticContexts.DropDownRestoreScrollOffset)

            MASVirtualizationConsumerFaultBoundary.SwallowInputBoundary(
                New InvalidOperationException("Synthetic DropDown ensure-selected-visible diagnostics probe."),
                MASVirtualizationConsumerDiagnosticCode.DropDownEnsureSelectedVisibleFallback,
                "MASDropDownListFloatContent",
                MASVirtualizationConsumerDiagnosticContexts.DropDownEnsureSelectedVisible)
        End Sub

        Private Shared Function ProbeStrictModeThrow() As Boolean
            Try
                Using scope As New MASRuntimeFaultStrictModeScope(True, False, True)
                    MASVirtualizationConsumerFaultBoundary.SwallowInputBoundary(
                        New InvalidOperationException("Synthetic strict-mode swallowed input-boundary probe."),
                        MASVirtualizationConsumerDiagnosticCode.DropDownInvalidateFallback,
                        "MASDropDownListFloatContent",
                        "MASVirtualizationConsumerDiagnosticsGate.StrictModeProbe")
                End Using
            Catch ex As InvalidOperationException
                Return ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is InvalidOperationException
            End Try

            Return False
        End Function

        Private Shared Function ExtractPublishedRequiredContexts(snapshot As IReadOnlyList(Of MASRuntimeFaultRecord)) As List(Of String)
            Dim result As New List(Of String)()
            If snapshot Is Nothing Then Return result

            For Each record As MASRuntimeFaultRecord In snapshot
                If record Is Nothing Then Continue For
                If ContainsRequiredContext(record.Context) AndAlso Not result.Contains(record.Context) Then
                    result.Add(record.Context)
                End If
            Next

            Return result
        End Function

        Private Shared Function ExtractPublishedRequiredCodes(snapshot As IReadOnlyList(Of MASRuntimeFaultRecord)) As List(Of String)
            Dim result As New List(Of String)()
            If snapshot Is Nothing Then Return result

            For Each record As MASRuntimeFaultRecord In snapshot
                If record Is Nothing Then Continue For
                Dim codeName As String = ExtractConsumerDiagnosticCode(record)
                If ContainsRequiredDiagnosticCode(codeName) AndAlso Not result.Contains(codeName) Then
                    result.Add(codeName)
                End If
            Next

            Return result
        End Function

        Private Shared Function ExtractConsumerDiagnosticCode(record As MASRuntimeFaultRecord) As String
            If record Is Nothing OrElse String.IsNullOrWhiteSpace(record.Context) Then Return String.Empty
            If Not record.Context.StartsWith(MASVirtualizationConsumerFaultDiagnostics.ContextPrefix, StringComparison.Ordinal) Then Return String.Empty
            Return record.Context.Substring(MASVirtualizationConsumerFaultDiagnostics.ContextPrefix.Length)
        End Function

        Private Shared Function ContainsRequiredContext(context As String) As Boolean
            If String.IsNullOrWhiteSpace(context) Then Return False

            For Each requiredContext As String In RequiredContexts
                If String.Equals(context, requiredContext, StringComparison.Ordinal) Then
                    Return True
                End If
            Next

            Return False
        End Function

        Private Shared Function ContainsRequiredDiagnosticCode(codeName As String) As Boolean
            If String.IsNullOrWhiteSpace(codeName) Then Return False

            For Each requiredCode As MASVirtualizationConsumerDiagnosticCode In RequiredDiagnosticCodes
                If String.Equals(codeName, requiredCode.ToString(), StringComparison.Ordinal) Then
                    Return True
                End If
            Next

            Return False
        End Function

        Private Shared Function RequiredDiagnosticCodeNames() As String()
            Dim result(RequiredDiagnosticCodes.Length - 1) As String
            For index As Integer = 0 To RequiredDiagnosticCodes.Length - 1
                result(index) = RequiredDiagnosticCodes(index).ToString()
            Next
            Return result
        End Function

        Private Shared Function HasCategory(snapshot As IReadOnlyList(Of MASRuntimeFaultRecord),
                                           category As MASExceptionHandlingCategory) As Boolean
            If snapshot Is Nothing Then Return False

            For Each record As MASRuntimeFaultRecord In snapshot
                If record IsNot Nothing AndAlso ContainsRequiredContext(record.Context) AndAlso record.Category = category Then
                    Return True
                End If
            Next

            Return False
        End Function

    End Class

End Namespace
