Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Text
Imports Nexamas.UI.Diagnostics
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.TextInput
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports SkiaSharp

Namespace Nexamas.UI.Quality

    ''' <summary>
    ''' Phase-8 proof for DPI-07 / DPI-08 / DPI-09 and DPI-R01..DPI-R05.
    ''' Keeps multiline/caret/DPI/cache/diagnostics proof on the official text,
    ''' layout, DPI, theme, and diagnostics routes.
    ''' </summary>
    Friend NotInheritable Class MASDpiTextLargeMultilineCaretPolicyGate
        Friend Const LargeMultilineLineCount As Integer = 100000
        Friend Const ComplexCaretRecipeName As String = "DPI-08.HarfBuzzClusterGraphemeCaretRoundTrip"
        Friend Const DpiPolicyRecipeName As String = "DPI-09.UnifiedDpiScalePolicy"
        Friend Const CacheEvictionRecipeName As String = "DPI-R03.BoundedCacheEviction"
        Friend Const DiagnosticsVisibilityRecipeName As String = "DPI-R05.TextDiagnosticsVisibility"

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Return ProbeLargeWindowedMultilineLayout() AndAlso
                   ProbeComplexCaretRoundTrip() AndAlso
                   ProbeUnifiedDpiScalePolicy() AndAlso
                   ProbeRapidThemeDpiChurnContract() AndAlso
                   ProbeBoundedCacheEvictionContract() AndAlso
                   ProbeFontCustomizationContract() AndAlso
                   ProbeTextDiagnosticsVisibility()
        End Function

        Private Shared Function ProbeLargeWindowedMultilineLayout() As Boolean
            Try
                Dim sb As New StringBuilder(LargeMultilineLineCount * 12)
                For i As Integer = 0 To LargeMultilineLineCount - 1
                    If i > 0 Then sb.Append(ControlChars.Lf)
                    sb.Append("Line ")
                    sb.Append(i.ToString("000000", CultureInfo.InvariantCulture))
                Next

                Dim document As MASTextMultilineDocument = MASTextMultilineDocument.FromText(sb.ToString())
                If document Is Nothing OrElse document.LineCount < LargeMultilineLineCount Then Return False

                Using paint As SKPaint = CreateProofPaint()
                    Dim lineHeight As Single = MASTextLayoutMeasurementGateway.ComputeParagraphLineHeight(paint)
                    If lineHeight <= 0.0F Then Return False

                    Dim targetLine As Integer = LargeMultilineLineCount \ 2
                    Dim caretIndex As Integer = document.GetTextIndexFromLineColumn(targetLine, 0)
                    Dim layout As MASTextParagraphLayout =
                        MASTextParagraphLayout.Create(
                            document:=document,
                            contentR:=New SKRect(0.0F, 0.0F, 420.0F, lineHeight * 16.0F),
                            paint:=paint,
                            verticalScrollOffsetPx:=lineHeight * CSng(targetLine),
                            wordWrap:=False,
                            horizontalScrollOffsetPx:=0.0F,
                            caretIndex:=caretIndex)

                    If layout Is Nothing Then Return False
                    If Not layout.IsWindowed Then Return False
                    If layout.RealizedLineCount <= 0 Then Return False
                    If layout.RealizedLineCount > MASTextParagraphLayout.LargeDocumentMaxRealizedLines Then Return False
                    If layout.TotalLogicalLineCount < LargeMultilineLineCount Then Return False
                    If layout.TotalHeight < lineHeight * CSng(LargeMultilineLineCount - 1) Then Return False
                    If layout.GetLineFromTextIndex(caretIndex) Is Nothing Then Return False
                End Using

                Return True
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASDpiTextLargeMultilineCaretPolicyGate.DPI-07")
                Return False
            End Try
        End Function

        Private Shared Function ProbeComplexCaretRoundTrip() As Boolean
            Try
                Using paint As SKPaint = CreateProofPaint()
                    Dim text As String = "e" & ChrW(&H301) & " مرحبا"
                    Dim xs As Single() = MASShapedText.BuildCaretXs(text, paint, 0.0F, False)
                    If Not ValidateCaretXs(xs, text.Length) Then Return False
                    If Math.Abs(xs(1) - xs(0)) > 0.01F Then Return False
                    If xs(text.Length) <= xs(0) Then Return False

                    Dim rtl As String = "مرحبا"
                    Dim rtlXs As Single() = MASShapedText.BuildCaretXs(rtl, paint, 0.0F, True)
                    If Not ValidateCaretXs(rtlXs, rtl.Length) Then Return False
                    If rtlXs(0) < rtlXs(rtl.Length) Then Return False
                End Using

                Return True
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, ComplexCaretRecipeName)
                Return False
            End Try
        End Function

        Private Shared Function ProbeUnifiedDpiScalePolicy() As Boolean
            Try
                If Math.Abs(PixelSnap.NormalizeDpiScale(0.75F) - 1.0F) > 0.001F Then Return False
                If Math.Abs(MASLayoutDpiResolver.NormalizeScale(0.75F, Nothing) - 1.0F) > 0.001F Then Return False
                If Math.Abs(MASLayoutDpiResolver.NormalizeScale(Single.NaN, Nothing) - 1.0F) > 0.001F Then Return False
                Return True
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, DpiPolicyRecipeName)
                Return False
            End Try
        End Function

        Private Shared Function ProbeRapidThemeDpiChurnContract() As Boolean
            Try
                Return ThemeHost.RapidChurnRetiredSnapshotLimitForProof >= 8
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, "DPI-R01.RapidThemeDpiChurnContract")
                Return False
            End Try
        End Function

        Private Shared Function ProbeBoundedCacheEvictionContract() As Boolean
            Try
                MASShapedText.ClearCache()

                Using paint As SKPaint = CreateProofPaint()
                    For i As Integer = 0 To 128
                        Dim sample As String = "unique-shaped-cache-proof-" & i.ToString(CultureInfo.InvariantCulture) & " مرحبا"
                        Dim width As Single = MASShapedText.MeasureWidth(sample, paint)
                        If Single.IsNaN(width) OrElse Single.IsInfinity(width) OrElse width < 0.0F Then Return False
                    Next

                    Using bitmap As New SKBitmap(480, 96)
                        Using canvas As New SKCanvas(bitmap)
                            For i As Integer = 0 To 64
                                Dim sample As String = "fallback-cache-proof-" & i.ToString(CultureInfo.InvariantCulture) & " 漢字 😀"
                                MASShapedText.Draw(canvas, sample, 8.0F, 48.0F, paint)
                            Next
                        End Using
                    End Using
                End Using

                Dim snapshot As MASTextRenderingCacheSnapshot = MASShapedText.CaptureCacheSnapshot()
                If snapshot Is Nothing Then Return False
                If snapshot.HarfBuzzDrawCacheEntries < 0 Then Return False
                If snapshot.SystemFallbackBitmapCacheEntries < 0 Then Return False
                If snapshot.SystemFallbackMeasureCacheEntries < 0 Then Return False

                Return True
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, CacheEvictionRecipeName)
                Return False
            End Try
        End Function

        Private Shared Function ProbeFontCustomizationContract() As Boolean
            Try
                Dim profile As MASTextInputFontProfile =
                    MASTextInputFontProfile.CreateCustom(
                        defaultFamily:="Segoe UI",
                        latinFamily:="Segoe UI",
                        arabicFamily:="Tahoma",
                        monospaceFamily:="Consolas",
                        preferMonospace:=False)

                If profile Is Nothing Then Return False
                profile.AddFallbacks("Arial", "Noto Sans Arabic")

                Dim clone As MASTextInputFontProfile = profile.Clone()
                If clone Is Nothing Then Return False
                If String.IsNullOrWhiteSpace(clone.ResolveFamilyForText("abc")) Then Return False
                If String.IsNullOrWhiteSpace(clone.ResolveFamilyForText("مرحبا")) Then Return False

                Return True
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, "DPI-R02.FontCustomizationFriendContract")
                Return False
            End Try
        End Function

        Private Shared Function ProbeTextDiagnosticsVisibility() As Boolean
            Dim oldThrowAny As Boolean = MASExceptionSilencer.ThrowOnSwallowedException
            Dim oldThrowLifecycle As Boolean = MASExceptionSilencer.ThrowOnLifecycleBreakingException
            Dim oldTraceRepeated As Boolean = MASExceptionSilencer.TraceRepeatedBoundaryExceptions

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

                MASExceptionSilencer.SwallowTextShapingFallback(
                    New InvalidOperationException("phase8 text diagnostic proof"),
                    DiagnosticsVisibilityRecipeName)

                Dim records As IReadOnlyList(Of MASRuntimeFaultRecord) = MASRuntimeFaultChannel.GetRecentFaultsSnapshot()
                If records Is Nothing OrElse records.Count = 0 Then Return False

                For Each record As MASRuntimeFaultRecord In records
                    If record Is Nothing Then Continue For
                    If record.Category = MASExceptionHandlingCategory.TextShapingFallback AndAlso
                       String.Equals(record.Context, DiagnosticsVisibilityRecipeName, StringComparison.Ordinal) Then
                        Return True
                    End If
                Next

                Return False
            Catch ex As Exception
                MASExceptionSilencer.SwallowDiagnosticOnly(ex, DiagnosticsVisibilityRecipeName)
                Return False
            Finally
                MASExceptionSilencer.ConfigureStrictness(oldThrowAny, oldThrowLifecycle, oldTraceRepeated)
            End Try
        End Function

        Private Shared Function ValidateCaretXs(xs As Single(), expectedTextLength As Integer) As Boolean
            If xs Is Nothing OrElse xs.Length <> expectedTextLength + 1 Then Return False

            For Each value As Single In xs
                If Single.IsNaN(value) OrElse Single.IsInfinity(value) Then Return False
            Next

            Return True
        End Function

        Private Shared Function CreateProofPaint() As SKPaint
            Return New SKPaint With {
                .IsAntialias = True,
                .SubpixelText = True,
                .Typeface = SKTypeface.Default,
                .TextSize = 16.0F,
                .Color = SKColors.Black
            }
        End Function
    End Class

End Namespace
