Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.General
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-only layout and interaction policy for MASAvatarGroup. It owns visible
    ''' avatar count normalization, compact overlap geometry, overflow counter planning,
    ''' display-first selected-index semantics, RTL ordering, hit-test rectangles,
    ''' pressed/keyboard active-layer math, and keyboard selection math. People lookup,
    ''' tooltip/callout previews, and presence transport remain outside the group.
    ''' </summary>
    Friend NotInheritable Class MASAvatarGroupLayoutPolicy

        Friend Const MaxVisibleUpperBound As Integer = 12

        Private Sub New()
        End Sub

        Friend Shared Function NormalizeMaxVisible(value As Integer) As Integer
            Return Math.Max(1, Math.Min(MaxVisibleUpperBound, value))
        End Function

        Friend Shared Function ResolveVisibleAvatarCount(avatarCount As Integer,
                                                         maxVisible As Integer) As Integer
            Return Math.Max(0, Math.Min(Math.Max(0, avatarCount), NormalizeMaxVisible(maxVisible)))
        End Function

        Friend Shared Function ResolveHiddenAvatarCount(avatarCount As Integer,
                                                        visibleAvatarCount As Integer) As Integer
            Return Math.Max(0, Math.Max(0, avatarCount) - Math.Max(0, visibleAvatarCount))
        End Function

        Friend Shared Function MeasureDesiredWidth(avatarCount As Integer,
                                                   maxVisible As Integer) As Single
            Dim visibleCount As Integer = ResolveVisibleAvatarCount(avatarCount, maxVisible)
            Dim hiddenCount As Integer = ResolveHiddenAvatarCount(avatarCount, visibleCount)
            Dim avatarSize As Single = AvatarTokens.DefaultSizeDip
            Dim overlap As Single = AvatarTokens.GroupOverlapDip
            Dim width As Single = AvatarTokens.GroupPaddingHorizontalDip * 2.0F

            If visibleCount > 0 Then
                width += avatarSize + Math.Max(0, visibleCount - 1) * (avatarSize - overlap)
            End If

            If hiddenCount > 0 Then width += avatarSize - overlap
            Return Math.Max(AvatarTokens.GroupMinWidthDip, Math.Min(AvatarTokens.GroupPreferredWidthDip, width))
        End Function

        Friend Shared Function BuildLayoutPlan(content As SKRect,
                                               avatarCount As Integer,
                                               maxVisible As Integer,
                                               dpi As Single,
                                               isRtl As Boolean) As MASAvatarGroupLayoutPlan
            Dim safeDpi As Single = PixelSnap.SafeDpi(dpi)
            Dim rects As New List(Of SKRect)()
            If content.Width <= 1.0F OrElse content.Height <= 1.0F OrElse avatarCount <= 0 Then
                Return New MASAvatarGroupLayoutPlan(rects.ToArray(), SKRect.Empty, False, 0, Math.Max(0, avatarCount), 0.0F, isRtl)
            End If

            Dim avatarSize As Single = ResolveItemSizePx(content, safeDpi)
            Dim stepSize As Single = ResolveStepSizePx(avatarSize, safeDpi)
            Dim requestedVisible As Integer = ResolveVisibleAvatarCount(avatarCount, maxVisible)
            Dim x As Single = If(isRtl, content.Right - avatarSize, content.Left)
            Dim y As Single = content.MidY - avatarSize / 2.0F

            For i As Integer = 0 To requestedVisible - 1
                If Not CanDrawItem(content, x, avatarSize, isRtl) Then Exit For
                rects.Add(PixelSnap.SnapRect(New SKRect(x, y, x + avatarSize, y + avatarSize), safeDpi))
                x = If(isRtl, x - stepSize, x + stepSize)
            Next

            Dim hiddenCount As Integer = ResolveHiddenAvatarCount(avatarCount, rects.Count)
            Dim overflowRect As SKRect = SKRect.Empty
            Dim hasOverflow As Boolean = False
            If hiddenCount > 0 AndAlso CanDrawItem(content, x, avatarSize, isRtl) Then
                overflowRect = PixelSnap.SnapRect(New SKRect(x, y, x + avatarSize, y + avatarSize), safeDpi)
                hasOverflow = True
            End If

            Return New MASAvatarGroupLayoutPlan(rects.ToArray(), overflowRect, hasOverflow, rects.Count, hiddenCount, avatarSize, isRtl)
        End Function

        Friend Shared Function NormalizeSelectionIndex(value As Integer,
                                                       avatarCount As Integer) As Integer
            If avatarCount <= 0 Then Return -1
            If value < 0 Then Return -1
            If value >= avatarCount Then Return avatarCount - 1
            Return value
        End Function

        Friend Shared Function NormalizeSelectionAfterCollectionChange(currentIndex As Integer,
                                                                       avatarCount As Integer) As Integer
            If avatarCount <= 0 Then Return -1
            If currentIndex < 0 Then Return -1
            If currentIndex >= avatarCount Then Return avatarCount - 1
            Return currentIndex
        End Function

        Friend Shared Function ResolveKeyboardSelectionIndex(currentIndex As Integer,
                                                             delta As Integer,
                                                             avatarCount As Integer) As Integer
            If avatarCount <= 0 Then Return -1
            Dim current As Integer = If(currentIndex < 0, If(delta >= 0, -1, avatarCount), currentIndex)
            Return NormalizeSelectionIndex(current + delta, avatarCount)
        End Function

        Friend Shared Function ResolvePreferredPointerTopLayerIndex(hoverIndex As Integer,
                                                                    pressedIndex As Integer,
                                                                    keyboardActiveIndex As Integer,
                                                                    visibleAvatarCount As Integer) As Integer
            If visibleAvatarCount <= 0 Then Return -1

            ' Hover is intentionally visual-only in a display-first avatar group.
            ' Raising an overlapped avatar on pointer travel makes the cluster jump and
            ' turns a compact presence summary into a noisy picker. Pressed and keyboard
            ' active states may still receive top-layer drawing because they represent
            ' deliberate interaction, not incidental pointer movement.
            If pressedIndex >= 0 AndAlso pressedIndex < visibleAvatarCount Then Return pressedIndex
            If keyboardActiveIndex >= 0 AndAlso keyboardActiveIndex < visibleAvatarCount Then Return keyboardActiveIndex
            Return -1
        End Function

        Friend Shared Function ResolveHitIndex(rects As SKRect(),
                                               ptPx As SKPoint,
                                               Optional preferredTopLayerIndex As Integer = -1,
                                               Optional dpi As Single = 1.0F) As Integer
            If rects Is Nothing Then Return -1

            If preferredTopLayerIndex >= 0 AndAlso preferredTopLayerIndex < rects.Length Then
                If MASAvatarIdentityPolicy.ContainsAvatarVisualPoint(rects(preferredTopLayerIndex), ptPx, dpi) Then Return preferredTopLayerIndex
            End If

            For i As Integer = rects.Length - 1 To 0 Step -1
                If i <> preferredTopLayerIndex AndAlso MASAvatarIdentityPolicy.ContainsAvatarVisualPoint(rects(i), ptPx, dpi) Then Return i
            Next
            Return -1
        End Function

        Friend Shared Function ResolveOverflowText(count As Integer) As String
            Return AvatarTokens.GroupExtraPrefix & Math.Max(0, count).ToString(Global.System.Globalization.CultureInfo.InvariantCulture)
        End Function

        Friend Shared Function HasOverflowCounterPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasRtlOrderingPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasDisplayFirstSelectionPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasPointerTopLayerPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasHoverTopLayerSuppressedPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasCircularVisualHitTestingPolicy() As Boolean
            Return MASAvatarIdentityPolicy.HasCircularVisualHitTestingPolicy()
        End Function

        Friend Shared Function HasActionableOverflowPopoverPolicy() As Boolean
            Return MASAvatarOverflowPopoverPolicy.HasActionableOverflowPopoverPolicy()
        End Function

        Friend Shared Function HasNoProfileEditorRoute() As Boolean
            Return MASAvatarOverflowPopoverPolicy.HasNoProfileEditorRoute()
        End Function

        Friend Shared Function HasNoPeopleDirectoryRoute() As Boolean
            Return True
        End Function

        Private Shared Function ResolveItemSizePx(content As SKRect,
                                                  dpi As Single) As Single
            Return Math.Min(AvatarTokens.DefaultSizeDip * PixelSnap.SafeDpi(dpi), Math.Max(1.0F, content.Height))
        End Function

        Private Shared Function ResolveStepSizePx(itemSizePx As Single,
                                                  dpi As Single) As Single
            Return Math.Max(1.0F, itemSizePx - AvatarTokens.GroupOverlapDip * PixelSnap.SafeDpi(dpi))
        End Function

        Private Shared Function CanDrawItem(content As SKRect,
                                            x As Single,
                                            itemSize As Single,
                                            isRtl As Boolean) As Boolean
            If isRtl Then Return x >= content.Left - 0.5F
            Return x + itemSize <= content.Right + 0.5F
        End Function

    End Class

    Friend NotInheritable Class MASAvatarGroupLayoutPlan
        Friend Sub New(avatarRects As SKRect(),
                       overflowRect As SKRect,
                       hasOverflow As Boolean,
                       visibleAvatarCount As Integer,
                       hiddenAvatarCount As Integer,
                       itemSizePx As Single,
                       isRtl As Boolean)
            Me.AvatarRects = If(avatarRects, Array.Empty(Of SKRect)())
            Me.OverflowRect = overflowRect
            Me.HasOverflow = hasOverflow
            Me.VisibleAvatarCount = Math.Max(0, visibleAvatarCount)
            Me.HiddenAvatarCount = Math.Max(0, hiddenAvatarCount)
            Me.ItemSizePx = Math.Max(0.0F, itemSizePx)
            Me.IsRtl = isRtl
        End Sub

        Friend ReadOnly Property AvatarRects As SKRect()
        Friend ReadOnly Property OverflowRect As SKRect
        Friend ReadOnly Property HasOverflow As Boolean
        Friend ReadOnly Property VisibleAvatarCount As Integer
        Friend ReadOnly Property HiddenAvatarCount As Integer
        Friend ReadOnly Property ItemSizePx As Single
        Friend ReadOnly Property IsRtl As Boolean

        Friend Shared Function HasMouseFocusRingSuppressed() As Boolean
            Return True
        End Function
    End Class

End Namespace
