Option Strict On
Option Explicit On

Imports System
Imports System.Drawing
Imports System.Globalization
Imports System.Threading
Imports System.Windows.Forms
Imports Nexamas.UI.Host
Imports Nexamas.UI.Motion
Imports Nexamas.UI.RuntimeEnvironment
Imports Nexamas.UI.Theming
Imports SkiaSharp.Views.Desktop

Namespace Nexamas.UI.Quality

    ''' <summary>
    ''' Runtime proof that Theme/DPI/RTL/Culture mutations during an active Motion runner travel through
    ''' the host runtime-environment coordinator and do not detach, cross-advance, or corrupt the active host clock.
    ''' </summary>
    Friend NotInheritable Class MASThemeDpiRtlMutationDuringMotionGate

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Dim previousMode As MASMotionReducedMotionMode = MASMotionSystem.ReducedMotionMode
            Dim previousUiCulture As CultureInfo = Thread.CurrentThread.CurrentUICulture
            Dim previousCulture As CultureInfo = Thread.CurrentThread.CurrentCulture

            Try
                MASMotionSystem.ReducedMotionMode = MASMotionReducedMotionMode.FullMotion
                Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-US")
                Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")

                Return ProbeRuntimeEnvironmentMutationDuringActiveMotion()
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASThemeDpiRtlMutationDuringMotionGate")
                Return False
            Finally
                MASMotionSystem.ReducedMotionMode = previousMode
                Thread.CurrentThread.CurrentUICulture = previousUiCulture
                Thread.CurrentThread.CurrentCulture = previousCulture
            End Try
        End Function

        Private Shared Function ProbeRuntimeEnvironmentMutationDuringActiveMotion() As Boolean
            ThemeManager.EnsureInitializedCore()

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

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

                        Dim refreshCount As Integer = 0
                        Using coordinator As New MASSkiaHostRuntimeEnvironmentCoordinator(
                            form,
                            sk,
                            themeHost,
                            Sub(reason As String)
                                If Not String.IsNullOrWhiteSpace(reason) Then refreshCount += 1
                            End Sub)

                            Using clock As New MASMotionFrameClock("theme-dpi-rtl-active-motion")
                                Dim owner As New Object()
                                Dim applyCount As Integer = 0
                                Dim requestCount As Integer = 0
                                Dim runner As MASMotionTimelineRunner = Nothing

                                Try
                                    Dim plan As MASMotionTransitionPlan =
                                        MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.PanelReveal, 0.0F, 1.0F, 600000, MASMotionEasing.Linear)

                                    runner = MASMotionSystem.CreateTimelineRunner(
                                        owner:=owner,
                                        consumerName:="theme-dpi-rtl-active-motion",
                                        plan:=plan,
                                        requestFrame:=Sub()
                                                          requestCount += 1
                                                      End Sub,
                                        applyFrame:=Sub(frame As MASMotionFrame)
                                                        applyCount += 1
                                                    End Sub,
                                        motionFrameClock:=clock)

                                    runner.Start()

                                    If clock.ActiveConsumerCount() <> 1 Then Return False
                                    If applyCount <> 1 Then Return False
                                    If requestCount <> 1 Then Return False

                                    themeHost.Ensure(1.25F)
                                    form.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

                                    Thread.CurrentThread.CurrentUICulture = New CultureInfo("ar-SA")
                                    Thread.CurrentThread.CurrentCulture = New CultureInfo("ar-SA")
                                    coordinator.ObserveCurrent("Motion.ThemeDpiRtlMutationDuringMotion")

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

                                    If refreshCount <= 0 Then Return False
                                    If Not stamp.IsRightToLeft Then Return False
                                    If stamp.DpiRevision <= 0 Then Return False

                                    If Not clock.AdvanceScheduledAnimations() Then Return False
                                    If applyCount <= 1 Then Return False
                                    If requestCount <= 1 Then Return False
                                    If clock.ActiveConsumerCount() <> 1 Then Return False

                                    runner.Dispose()
                                    runner = Nothing

                                    Return clock.ActiveConsumerCount() = 0
                                Finally
                                    If runner IsNot Nothing Then runner.Dispose()
                                End Try
                            End Using
                        End Using
                    End Using
                End Using
            End Using
        End Function

    End Class

End Namespace
