Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Globalization
Imports System.Reflection
Imports System.Threading
Imports System.Windows.Forms
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Host
Imports Nexamas.UI.Localization
Imports Nexamas.UI.RuntimeEnvironment
Imports Nexamas.UI.Theming
Imports SkiaSharp
Imports SkiaSharp.Views.Desktop

Namespace Nexamas.UI.Quality

    ''' <summary>
    ''' Phase-4 runtime proof expansion for Application-level live environment changes and
    ''' stress-only contracts.  This gate deliberately reuses the official host runtime-environment
    ''' coordinator, Localization runtime coordinator, Motion/Float runtime gates, dispatcher async
    ''' gate, and retained ControlsLayer scalability policy.  It does not introduce a parallel
    ''' layout, input, cache, or virtualization path.
    ''' </summary>
    Friend NotInheritable Class MASApplicationRuntimeStressProofGate
        Friend Const RuntimeEnvironmentChurnRecipeName As String = "APP-R01.LiveRuntimeEnvironmentChurn"
        Friend Const AsyncDisposeCallbackRecipeName As String = "APP-R02.DisposeAsyncCallbackStress"
        Friend Const DirectControlsBulkMisuseRecipeName As String = "APP-R02.100kDirectControlsMisuseRuntimeFault"

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Return ProbeLiveRuntimeEnvironmentChurn() AndAlso
                   ProbeDisposeAndAsyncCallbackStress() AndAlso
                   Probe100kDirectControlsMisuseRuntimeFault()
        End Function

        Private Shared Function ProbeLiveRuntimeEnvironmentChurn() As Boolean
            Dim previousUiCulture As CultureInfo = Thread.CurrentThread.CurrentUICulture
            Dim previousCulture As CultureInfo = Thread.CurrentThread.CurrentCulture

            Try
                ThemeManager.EnsureInitializedCore()

                Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-US")
                Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
                MASLocalization.UseCurrentThreadCulture("APP-R01.LiveRuntimeEnvironmentChurn.Reset")

                Using form As New Form()
                    Using sk As New SKGLControl()
                        form.Controls.Add(sk)

                        Using themeHost As New ThemeHost()
                            themeHost.Ensure(1.0F)

                            Dim refreshReasons As New List(Of String)()
                            Dim uiPostCount As Integer = 0

                            Using coordinator As New MASSkiaHostRuntimeEnvironmentCoordinator(
                                form,
                                sk,
                                themeHost,
                                Sub(reason As String)
                                    refreshReasons.Add(If(reason, String.Empty))
                                End Sub,
                                postToUiThread:=Function(action As Action) As Boolean
                                                    uiPostCount += 1
                                                    If action IsNot Nothing Then action.Invoke()
                                                    Return True
                                                End Function)

                                themeHost.Ensure(1.25F)
                                form.RightToLeft = RightToLeft.Yes
                                sk.RightToLeft = RightToLeft.Yes

                                Dim replacementFont As Font = Nothing
                                Try
                                    replacementFont = New Font(form.Font.FontFamily, form.Font.SizeInPoints + 1.0F, form.Font.Style, GraphicsUnit.Point)
                                    form.Font = replacementFont
                                Finally
                                    If replacementFont IsNot Nothing Then replacementFont.Dispose()
                                End Try

                                MASLocalization.SetRuntimeCulture("ar-SY", "APP-R01.LocalizationRuntime")
                                coordinator.ObserveCurrent("APP-R01.ManualCacheBoundary")

                                Dim stamp As MASRuntimeEnvironmentStamp =
                                    MASSkiaHostRuntimeEnvironmentCoordinator.BuildCurrentStampForTests(themeHost, form, sk)

                                If refreshReasons.Count < 4 Then Return False
                                If uiPostCount <= 0 Then Return False
                                If Not stamp.IsRightToLeft Then Return False
                                If stamp.DpiRevision <= 0 Then Return False
                                If stamp.FontRevision <= 0 Then Return False
                                If stamp.LocalizationRevision <= 0 Then Return False
                                If stamp.RtlRevision <= 0 Then Return False
                                If String.IsNullOrWhiteSpace(stamp.CultureName) Then Return False
                            End Using
                        End Using
                    End Using
                End Using

                Return MASRuntimeEnvironmentMutationCoordinatorGate.Passes() AndAlso
                       MASLocalizationRuntimeEnvironmentCoordinatorGate.Passes() AndAlso
                       MASDataGridRuntimeCultureIntegrationGate.Passes()
            Catch masCaughtException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(masCaughtException, "MASApplicationRuntimeStressProofGate.APP-R01")
                Return False
            Finally
                Thread.CurrentThread.CurrentUICulture = previousUiCulture
                Thread.CurrentThread.CurrentCulture = previousCulture
                MASLocalization.UseCurrentThreadCulture("APP-R01.LiveRuntimeEnvironmentChurn.Restore")
            End Try
        End Function

        Private Shared Function ProbeDisposeAndAsyncCallbackStress() As Boolean
            Try
                Return MASFloatTransitionDisposeGate.Passes() AndAlso
                       MASOfficialDispatcherAsyncCompletionGate.Passes() AndAlso
                       MASMotionConsumerPressureGate.Passes()
            Catch masCaughtException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(masCaughtException, "MASApplicationRuntimeStressProofGate.APP-R02.DisposeAsync")
                Return False
            End Try
        End Function

        Private Shared Function Probe100kDirectControlsMisuseRuntimeFault() As Boolean
            Try
                Dim invalidationCount As Integer = 0
                Dim layer As New ControlsLayer(Sub()
                                                   invalidationCount += 1
                                               End Sub)

                Dim itemsField As FieldInfo = GetType(ControlsLayer).GetField("_items", BindingFlags.Instance Or BindingFlags.NonPublic)
                If itemsField Is Nothing Then Return False

                Dim items As List(Of MASControlBase) = TryCast(itemsField.GetValue(layer), List(Of MASControlBase))
                If items Is Nothing Then Return False

                For i As Integer = 1 To MASControlsLayerScalabilityPolicy.UnsupportedBulkDirectControlsCount - 1
                    items.Add(Nothing)
                Next

                Dim beforeCount As Integer = items.Count
                Dim misuseFaultThrew As Boolean = False
                Dim failureMessage As String = String.Empty

                Try
                    layer.Add(New StressProbeControl("100k-direct-controls-misuse"))
                Catch expected As InvalidOperationException
                    failureMessage = expected.Message
                    misuseFaultThrew = failureMessage.IndexOf(MASControlsLayerScalabilityPolicy.RetainedDirectControlsMutationBlockedCode, StringComparison.Ordinal) >= 0
                End Try

                Return misuseFaultThrew AndAlso
                       Not String.IsNullOrEmpty(failureMessage) AndAlso
                       items.Count = beforeCount AndAlso
                       invalidationCount = 0
            Catch masCaughtException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(masCaughtException, "MASApplicationRuntimeStressProofGate.APP-R02.100k")
                Return False
            End Try
        End Function

        Private NotInheritable Class StressProbeControl
            Inherits MASControlBase

            Friend Sub New(name As String)
                Me.Name = If(name, String.Empty)
            End Sub

            Protected Overrides Sub Render(canvas As SKCanvas,
                                           ctx As MASThemeContext,
                                           pixelBounds As SKRect)
                ' Phase-4 proof control is never rendered; ControlsLayer must reject 100k direct-control misuse before admission.
            End Sub
        End Class

    End Class

End Namespace
