Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Friend Enum MASDashboardGridKeyboardResizeCommand
        Unknown = 0
        IncreaseSpanColumns = 1
        DecreaseSpanColumns = 2
        IncreaseSpanRows = 3
        DecreaseSpanRows = 4
        ResetToSingleSpan = 5
    End Enum

    ''' <summary>
    ''' Friend-only keyboard/a11y threshold snapshot for DashboardGrid widget resize.
    ''' It proves bounded span changes, hosted-widget state, readable resize text, and
    ''' bounded realized widget-window behavior without opening a public keyboard API.
    ''' </summary>
    Friend NotInheritable Class MASDashboardGridKeyboardResizeThresholdSnapshot
        Friend Sub New(version As Integer,
                       evidenceKey As String,
                       selectedWidgetKey As String,
                       totalWidgets As Integer,
                       viewportCapacity As Integer,
                       realizedWidgetCount As Integer,
                       hostedWidgetCount As Integer,
                       selectedSpanColumns As Integer,
                       selectedSpanRows As Integer,
                       minSpanColumns As Integer,
                       maxSpanColumns As Integer,
                       minSpanRows As Integer,
                       maxSpanRows As Integer,
                       supportsIncreaseDecrease As Boolean,
                       description As String)
            Me.Version = Math.Max(1, version)
            Me.EvidenceKey = Normalize(evidenceKey)
            Me.SelectedWidgetKey = Normalize(selectedWidgetKey)
            Me.TotalWidgets = Math.Max(0, totalWidgets)
            Me.ViewportCapacity = Math.Max(1, viewportCapacity)
            Me.RealizedWidgetCount = Math.Max(0, realizedWidgetCount)
            Me.HostedWidgetCount = Math.Max(0, hostedWidgetCount)
            Me.SelectedSpanColumns = Math.Max(1, selectedSpanColumns)
            Me.SelectedSpanRows = Math.Max(1, selectedSpanRows)
            Me.MinSpanColumns = Math.Max(1, minSpanColumns)
            Me.MaxSpanColumns = Math.Max(Me.MinSpanColumns, maxSpanColumns)
            Me.MinSpanRows = Math.Max(1, minSpanRows)
            Me.MaxSpanRows = Math.Max(Me.MinSpanRows, maxSpanRows)
            Me.SupportsIncreaseDecrease = supportsIncreaseDecrease
            Me.Description = Normalize(description)
        End Sub

        Friend ReadOnly Property Version As Integer
        Friend ReadOnly Property EvidenceKey As String
        Friend ReadOnly Property SelectedWidgetKey As String
        Friend ReadOnly Property TotalWidgets As Integer
        Friend ReadOnly Property ViewportCapacity As Integer
        Friend ReadOnly Property RealizedWidgetCount As Integer
        Friend ReadOnly Property HostedWidgetCount As Integer
        Friend ReadOnly Property SelectedSpanColumns As Integer
        Friend ReadOnly Property SelectedSpanRows As Integer
        Friend ReadOnly Property MinSpanColumns As Integer
        Friend ReadOnly Property MaxSpanColumns As Integer
        Friend ReadOnly Property MinSpanRows As Integer
        Friend ReadOnly Property MaxSpanRows As Integer
        Friend ReadOnly Property SupportsIncreaseDecrease As Boolean
        Friend ReadOnly Property Description As String

        Friend ReadOnly Property HasReadableResizeDescription As Boolean
            Get
                Return Description.Length >= 16 AndAlso
                       Description.IndexOf("span", StringComparison.OrdinalIgnoreCase) >= 0 AndAlso
                       Description.IndexOf("keyboard", StringComparison.OrdinalIgnoreCase) >= 0
            End Get
        End Property

        Friend ReadOnly Property HasBoundedSpanThresholds As Boolean
            Get
                Return SelectedSpanColumns >= MinSpanColumns AndAlso
                       SelectedSpanColumns <= MaxSpanColumns AndAlso
                       SelectedSpanRows >= MinSpanRows AndAlso
                       SelectedSpanRows <= MaxSpanRows AndAlso
                       MaxSpanColumns <= DashboardGridTokens.MaxSpanColumns AndAlso
                       MaxSpanRows <= DashboardGridTokens.MaxSpanRows
            End Get
        End Property

        Friend ReadOnly Property UsesBoundedWidgetWindow As Boolean
            Get
                Return RealizedWidgetCount > 0 AndAlso
                       RealizedWidgetCount <= ViewportCapacity AndAlso
                       ViewportCapacity <= DashboardGridTokens.MaxVisibleWidgets AndAlso
                       TotalWidgets > RealizedWidgetCount
            End Get
        End Property

        Friend ReadOnly Property IsProductionThresholdEvidence As Boolean
            Get
                Return Version > 0 AndAlso
                       EvidenceKey.Length > 0 AndAlso
                       SelectedWidgetKey.Length > 0 AndAlso
                       TotalWidgets >= DashboardGridTokens.MaxWidgets AndAlso
                       HostedWidgetCount >= 1 AndAlso
                       SupportsIncreaseDecrease AndAlso
                       HasReadableResizeDescription AndAlso
                       HasBoundedSpanThresholds AndAlso
                       UsesBoundedWidgetWindow
            End Get
        End Property

        Private Shared Function Normalize(value As String) As String
            If value Is Nothing Then Return String.Empty
            Dim text As String = value.Trim()
            Do While text.Contains("  ")
                text = text.Replace("  ", " ")
            Loop
            Return text
        End Function
    End Class

    Partial Public NotInheritable Class MASDashboardGrid

#Region "Friend keyboard resize thresholds"

        Friend Function CreateKeyboardResizeThresholdSnapshot() As MASDashboardGridKeyboardResizeThresholdSnapshot
            Dim selected As DashboardWidgetState = Nothing
            If _selectedIndex >= 0 AndAlso _selectedIndex < _widgets.Count Then selected = _widgets(_selectedIndex)
            Dim widgetKey As String = If(selected Is Nothing, String.Empty, selected.Key)
            Dim windowSnapshot As MASDashboardGridWidgetWindowSnapshot = CreateWidgetWindowSnapshot(Math.Max(1, Math.Min(_lastVisibleCount, DashboardGridTokens.MaxVisibleWidgets)))
            Dim hostedSnapshot As MASHostedContentContractSnapshot = CreateHostedWidgetContentSnapshot()
            Dim spanColumns As Integer = If(selected Is Nothing, 1, selected.SpanColumns)
            Dim spanRows As Integer = If(selected Is Nothing, 1, selected.SpanRows)
            Dim description As String = "DashboardGrid keyboard resize thresholds: selected widget span " & spanColumns.ToString(System.Globalization.CultureInfo.InvariantCulture) & "×" & spanRows.ToString(System.Globalization.CultureInfo.InvariantCulture) & ", bounded by MaxSpanColumns/MaxSpanRows."
            Return New MASDashboardGridKeyboardResizeThresholdSnapshot(
                1,
                "DashboardGrid.KeyboardResizeThresholds",
                widgetKey,
                _widgets.Count,
                windowSnapshot.RequestedViewportCapacity,
                windowSnapshot.RealizedWidgetCount,
                If(hostedSnapshot Is Nothing, 0, hostedSnapshot.HostedSlotCount),
                spanColumns,
                spanRows,
                1,
                DashboardGridTokens.MaxSpanColumns,
                1,
                DashboardGridTokens.MaxSpanRows,
                supportsIncreaseDecrease:=True,
                description:=description)
        End Function

        Friend Function ApplyKeyboardResizeCommand(command As MASDashboardGridKeyboardResizeCommand) As Boolean
            If _selectedIndex < 0 OrElse _selectedIndex >= _widgets.Count Then Return False
            Dim widget As DashboardWidgetState = _widgets(_selectedIndex)
            If widget Is Nothing Then Return False
            Dim newColumns As Integer = widget.SpanColumns
            Dim newRows As Integer = widget.SpanRows

            Select Case command
                Case MASDashboardGridKeyboardResizeCommand.IncreaseSpanColumns
                    newColumns += 1
                Case MASDashboardGridKeyboardResizeCommand.DecreaseSpanColumns
                    newColumns -= 1
                Case MASDashboardGridKeyboardResizeCommand.IncreaseSpanRows
                    newRows += 1
                Case MASDashboardGridKeyboardResizeCommand.DecreaseSpanRows
                    newRows -= 1
                Case MASDashboardGridKeyboardResizeCommand.ResetToSingleSpan
                    newColumns = 1
                    newRows = 1
                Case Else
                    Return False
            End Select

            newColumns = MASDashboardGridPolicy.ClampSpan(newColumns, DashboardGridTokens.MaxSpanColumns)
            newRows = MASDashboardGridPolicy.ClampSpan(newRows, DashboardGridTokens.MaxSpanRows)
            If widget.SpanColumns = newColumns AndAlso widget.SpanRows = newRows Then Return False
            Return ResizeWidget(widget.Key, newColumns, newRows)
        End Function

        Friend Function HasKeyboardResizeThresholdsForTests() As Boolean
            If _widgets.Count < DashboardGridTokens.MaxWidgets Then
                ClearWidgets()
                For index As Integer = 0 To DashboardGridTokens.MaxWidgets - 1
                    AddWidget("dash-threshold-" & index.ToString(System.Globalization.CultureInfo.InvariantCulture),
                              "Threshold " & index.ToString(System.Globalization.CultureInfo.InvariantCulture),
                              index.ToString(System.Globalization.CultureInfo.InvariantCulture),
                              "Keyboard threshold proof",
                              1,
                              1)
                Next
            End If

            Dim selectedKey As String = "dash-threshold-10"
            If FindWidgetIndex(selectedKey) < 0 Then selectedKey = If(_widgets.Count > 0, _widgets(0).Key, String.Empty)
            If selectedKey.Length = 0 OrElse Not SelectWidget(selectedKey) Then Return False
            If Not SetDiagnosticWidgetViewportCapacity(6) Then Return False

            Dim child As MASControlBase = MASButton.Create("Hosted dashboard threshold")
            If Not HostWidgetContent(selectedKey, child) Then Return False
            PlaceHostedWidgetContent(selectedKey, New SKRect(0.0F, 0.0F, 180.0F, 96.0F), 1.0F)

            Dim initial As MASDashboardGridKeyboardResizeThresholdSnapshot = CreateKeyboardResizeThresholdSnapshot()
            If initial Is Nothing OrElse Not initial.IsProductionThresholdEvidence Then Return False

            If Not ApplyKeyboardResizeCommand(MASDashboardGridKeyboardResizeCommand.IncreaseSpanColumns) Then Return False
            Dim afterColumn As MASDashboardGridKeyboardResizeThresholdSnapshot = CreateKeyboardResizeThresholdSnapshot()
            If afterColumn Is Nothing OrElse Not afterColumn.IsProductionThresholdEvidence OrElse afterColumn.SelectedSpanColumns <= initial.SelectedSpanColumns Then Return False

            If Not ApplyKeyboardResizeCommand(MASDashboardGridKeyboardResizeCommand.IncreaseSpanRows) Then Return False
            Dim afterRow As MASDashboardGridKeyboardResizeThresholdSnapshot = CreateKeyboardResizeThresholdSnapshot()
            If afterRow Is Nothing OrElse Not afterRow.IsProductionThresholdEvidence OrElse afterRow.SelectedSpanRows <= afterColumn.SelectedSpanRows Then Return False

            If Not ApplyKeyboardResizeCommand(MASDashboardGridKeyboardResizeCommand.ResetToSingleSpan) Then Return False
            Dim resetSnapshot As MASDashboardGridKeyboardResizeThresholdSnapshot = CreateKeyboardResizeThresholdSnapshot()
            Dim removed As Boolean = UnhostWidgetContent(selectedKey, disposeChild:=True)
            Return removed AndAlso
                   resetSnapshot IsNot Nothing AndAlso
                   resetSnapshot.IsProductionThresholdEvidence AndAlso
                   resetSnapshot.SelectedSpanColumns = 1 AndAlso
                   resetSnapshot.SelectedSpanRows = 1
        End Function

#End Region

    End Class

End Namespace
