Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.General
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Shared Media footer geometry resolver for file/status/zoom regions.
    ''' The footer degrades progressively: metadata, zoom, menu, then icon are dropped
    ''' before the whole footer is removed by the container resolver.
    ''' </summary>
    Friend NotInheritable Class MASMediaFooterLayoutResolver
        Private Sub New()
        End Sub

        Friend Shared Function Resolve(footerRect As SKRect,
                                       dpi As Single,
                                       Optional chromeScale As Single = 1.0F) As MASMediaFooterLayoutPlan
            dpi = PixelSnap.SafeDpi(dpi)
            Dim unit As Single = ResolveChromeUnitPx(dpi, chromeScale)
            Dim plan As New MASMediaFooterLayoutPlan With {
                .IconChip = SKRect.Empty,
                .IconGlyph = SKRect.Empty,
                .ZoomBadge = SKRect.Empty,
                .MenuButton = SKRect.Empty,
                .MenuGlyph = SKRect.Empty,
                .MenuSeparator = SKRect.Empty,
                .InfoLine = SKRect.Empty,
                .TitleText = SKRect.Empty,
                .MetadataText = SKRect.Empty
            }

            If footerRect.Width <= 1.0F OrElse footerRect.Height <= 1.0F Then Return plan

            Dim widthDip As Single = footerRect.Width / unit
            Dim scale As Single = ResolveScale(footerRect, dpi, chromeScale)
            Dim sideInset As Single = Math.Min(MediaFooterTokens.SideInsetDip * unit * scale,
                                               Math.Max(4.0F * unit, footerRect.Width * 0.07F))
            Dim cursorLeft As Single = footerRect.Left + sideInset
            Dim cursorRight As Single = footerRect.Right - sideInset

            If widthDip >= MediaFooterTokens.IconVisibleWidthDip Then
                Dim iconChipSize As Single = Math.Min(MediaFooterTokens.IconChipSizeDip * unit * scale,
                                                      Math.Max(1.0F, footerRect.Height - 8.0F * unit))
                If iconChipSize > 1.0F Then
                    plan.IconChip = PixelSnap.SnapRectHalf(New SKRect(cursorLeft,
                                                                     footerRect.MidY - iconChipSize / 2.0F,
                                                                     cursorLeft + iconChipSize,
                                                                     footerRect.MidY + iconChipSize / 2.0F))
                    Dim iconInset As Single = Math.Max(3.0F * unit, MediaFooterTokens.IconInsetDip * unit * scale)
                    plan.IconGlyph = PixelSnap.InsetAll(plan.IconChip, iconInset)
                    cursorLeft = plan.IconChip.Right + MediaFooterTokens.TextGapDip * unit * scale
                End If
            End If

            Dim showMenu As Boolean = widthDip >= MediaFooterTokens.MenuVisibleWidthDip
            Dim showZoom As Boolean = widthDip >= MediaFooterTokens.ZoomBadgeVisibleWidthDip

            If showMenu Then
                Dim menuWidth As Single = Math.Min(MediaFooterTokens.MenuButtonWidthDip * unit * scale,
                                                   Math.Max(1.0F, footerRect.Width * 0.18F))
                Dim menuHeight As Single = Math.Min(MediaFooterTokens.MenuButtonHeightDip * unit * scale,
                                                    Math.Max(1.0F, footerRect.Height - 6.0F * unit))
                If menuWidth > 1.0F AndAlso menuHeight > 1.0F Then
                    plan.MenuButton = PixelSnap.SnapRectHalf(New SKRect(cursorRight - menuWidth,
                                                                       footerRect.MidY - menuHeight / 2.0F,
                                                                       cursorRight,
                                                                       footerRect.MidY + menuHeight / 2.0F))
                    Dim menuGlyphSize As Single = Math.Min(MediaFooterTokens.MenuGlyphSizeDip * unit * scale,
                                                           Math.Max(1.0F, plan.MenuButton.Height * 0.58F))
                    plan.MenuGlyph = PixelSnap.SnapRectHalf(New SKRect(plan.MenuButton.MidX - menuGlyphSize / 2.0F,
                                                                      plan.MenuButton.MidY - menuGlyphSize / 2.0F,
                                                                      plan.MenuButton.MidX + menuGlyphSize / 2.0F,
                                                                      plan.MenuButton.MidY + menuGlyphSize / 2.0F))
                    cursorRight = plan.MenuButton.Left

                    plan.MenuSeparator = New SKRect(cursorRight,
                                                   footerRect.Top + MediaFooterTokens.SeparatorInsetDip * unit * scale,
                                                   cursorRight,
                                                   footerRect.Bottom - MediaFooterTokens.SeparatorInsetDip * unit * scale)
                End If
            End If

            If showZoom Then
                Dim zoomWidth As Single = Math.Min(MediaFooterTokens.ZoomBadgeWidthDip * unit * scale,
                                                   Math.Max(1.0F, footerRect.Width * 0.24F))
                Dim zoomHeight As Single = Math.Min(MediaFooterTokens.ZoomBadgeHeightDip * unit * scale,
                                                    Math.Max(1.0F, footerRect.Height - 8.0F * unit))
                Dim zoomGap As Single = MediaFooterTokens.ZoomBadgeToMenuGapDip * unit * scale
                If zoomWidth > 1.0F AndAlso zoomHeight > 1.0F AndAlso cursorRight - zoomGap - zoomWidth > cursorLeft Then
                    plan.ZoomBadge = PixelSnap.SnapRectHalf(New SKRect(cursorRight - zoomGap - zoomWidth,
                                                                      footerRect.MidY - zoomHeight / 2.0F,
                                                                      cursorRight - zoomGap,
                                                                      footerRect.MidY + zoomHeight / 2.0F))
                    cursorRight = plan.ZoomBadge.Left
                End If
            End If

            Dim textRight As Single = cursorRight - MediaFooterTokens.MetadataGapDip * unit * scale
            If textRight <= cursorLeft + MediaFooterTokens.MinimumTextWidthDip * unit Then Return plan

            Dim lineHeight As Single = Math.Min(MediaFooterTokens.InfoLineHeightDip * unit * scale,
                                                Math.Max(1.0F, footerRect.Height - 6.0F * unit))
            plan.InfoLine = PixelSnap.SnapRectHalf(New SKRect(cursorLeft,
                                                             footerRect.MidY - lineHeight / 2.0F,
                                                             textRight,
                                                             footerRect.MidY + lineHeight / 2.0F))

            Dim showMetadata As Boolean = widthDip >= MediaFooterTokens.MetadataVisibleWidthDip AndAlso plan.InfoLine.Width >= 190.0F * unit
            If showMetadata Then
                Dim preferredTitleWidth As Single = Math.Min(plan.InfoLine.Width * MediaFooterTokens.TitleMaxWidthRatio,
                                                             Math.Max(MediaFooterTokens.TitleMinWidthDip * unit * scale, plan.InfoLine.Width * 0.34F))
                preferredTitleWidth = Math.Min(preferredTitleWidth, plan.InfoLine.Width)
                Dim titleRight As Single = plan.InfoLine.Left + preferredTitleWidth
                plan.TitleText = New SKRect(plan.InfoLine.Left,
                                            plan.InfoLine.Top,
                                            titleRight,
                                            plan.InfoLine.Bottom)
                plan.MetadataText = New SKRect(Math.Min(plan.InfoLine.Right, titleRight + MediaFooterTokens.MetadataGapDip * unit * scale),
                                               plan.InfoLine.Top,
                                               plan.InfoLine.Right,
                                               plan.InfoLine.Bottom)
            Else
                plan.TitleText = plan.InfoLine
                plan.MetadataText = SKRect.Empty
            End If

            Return plan
        End Function

        Friend Shared Function ResolveVisualSurfaceRect(footerRect As SKRect,
                                                        previewFrameRect As SKRect,
                                                        contentRect As SKRect,
                                                        dpi As Single,
                                                        Optional chromeScale As Single = 1.0F) As SKRect
            dpi = PixelSnap.SafeDpi(dpi)
            Dim unit As Single = ResolveChromeUnitPx(dpi, chromeScale)
            Dim visualFooterRect As SKRect = footerRect
            If contentRect.Width <= 1.0F OrElse contentRect.Height <= 1.0F Then Return visualFooterRect
            If footerRect.Width <= 1.0F OrElse footerRect.Height <= 1.0F Then Return visualFooterRect

            Dim seamGap As Single = footerRect.Top - contentRect.Bottom
            If seamGap <= 0.5F Then Return visualFooterRect

            Dim maxAbsorb As Single = System.Math.Max(0.0F, MediaFooterTokens.FooterVisualSeamAbsorbMaxDip * unit)
            If seamGap > maxAbsorb Then Return visualFooterRect

            visualFooterRect.Top = System.Math.Max(previewFrameRect.Top, footerRect.Top - seamGap)
            Return visualFooterRect
        End Function

        Private Shared Function ResolveScale(footerRect As SKRect,
                                             dpi As Single,
                                             chromeScale As Single) As Single
            dpi = PixelSnap.SafeDpi(dpi)
            Dim unit As Single = ResolveChromeUnitPx(dpi, chromeScale)
            Dim heightScale As Single = footerRect.Height / Math.Max(1.0F, MediaFooterTokens.HeightDip * unit)
            Dim widthScale As Single = Math.Min(1.0F, Math.Max(0.78F, footerRect.Width / (MediaContainerTokens.CompactWidthBreakpointDip * unit)))
            Dim scale As Single = Math.Min(1.0F, Math.Min(heightScale, widthScale))
            If Single.IsNaN(scale) OrElse Single.IsInfinity(scale) OrElse scale <= 0.0F Then scale = 1.0F
            Return Math.Max(0.72F, scale)
        End Function

        Private Shared Function ResolveChromeUnitPx(dpi As Single,
                                                    chromeScale As Single) As Single
            Dim safeDpi As Single = PixelSnap.SafeDpi(dpi)
            Return safeDpi * SanitizeChromeScale(chromeScale)
        End Function

        Private Shared Function SanitizeChromeScale(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value <= 0.0F Then Return 1.0F
            Return Math.Min(1.24F, Math.Max(0.72F, value))
        End Function
    End Class

End Namespace
