Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Host
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Components
Imports SkiaSharp

Namespace Nexamas.UI.Application

    Partial Public NotInheritable Class MASApplicationSurfaceLayoutBuilder
        Private Shared Function CreateRegionPage(buildAction As Action(Of MASApplicationLayoutPageBuilder)) As MASApplicationLayoutPageBuilder
            If buildAction Is Nothing Then Throw New ArgumentNullException(NameOf(buildAction))

            Dim page As New MASApplicationLayoutPageBuilder()
            page.Padding(MASLayoutSpacing.None).Spacing(MASLayoutSpacing.Small)
            buildAction.Invoke(page)
            Return page
        End Function

        Private Shared Sub CollectPageControls(page As MASApplicationLayoutPageBuilder,
                                               target As IList(Of MASControlBase))
            If page Is Nothing OrElse target Is Nothing Then Return
            page.CollectControls(target)
        End Sub

        Private Function ResolveCommandBodyGap(profile As MASSizeProfile) As Single
            Return ScaleGap(_commandBodyGap, profile)
        End Function

        Private Function ResolveBodyFooterGap(profile As MASSizeProfile) As Single
            Return ScaleGap(_bodyFooterGap, profile)
        End Function

        Private Function ResolveColumnGap(profile As MASSizeProfile) As Single
            Return ScaleGap(_columnGap, profile)
        End Function

        Private Function ResolveSidebarFooterGap(profile As MASSizeProfile) As Single
            Return ScaleGap(_sidebarFooterGap, profile)
        End Function

        Private Shared Function ScaleGap(value As Single,
                                         profile As MASSizeProfile) As Single
            Return SafeNonNegative(value) * MASSizeProfile.Normalize(profile).GapScale
        End Function

        Private Sub ApplyAllRegionGaps(baseGap As Single)
            Dim safeGap As Single = SafeNonNegative(baseGap)
            _commandBodyGap = safeGap
            _bodyFooterGap = safeGap
            _columnGap = safeGap
            _sidebarFooterGap = safeGap
        End Sub

        Private Sub ApplyRhythm(outerPadding As MASLayoutSpacing,
                                commandBodyGap As MASLayoutSpacing,
                                bodyFooterGap As MASLayoutSpacing,
                                columnGap As MASLayoutSpacing,
                                sidebarFooterGap As MASLayoutSpacing)
            _outerPadding = MASLayoutSpacingResolver.ResolveInsetBase(outerPadding)
            _commandBodyGap = MASLayoutSpacingResolver.ResolveBase(commandBodyGap)
            _bodyFooterGap = MASLayoutSpacingResolver.ResolveBase(bodyFooterGap)
            _columnGap = MASLayoutSpacingResolver.ResolveBase(columnGap)
            _sidebarFooterGap = MASLayoutSpacingResolver.ResolveBase(sidebarFooterGap)
        End Sub

        Private Function ResolveOuterPadding(profile As MASSizeProfile) As MASLayoutInset
            Dim safeProfile As MASSizeProfile = MASSizeProfile.Normalize(profile)
            Dim topPadding As Single = _outerPadding.Top * safeProfile.GapScale

            If _standardChromeShell IsNot Nothing Then
                ' StandardContentTopLogical already contains the MAS-owned breathing gap below
                ' the application chrome. Keep the application-surface top edge from adding a
                ' second independent page gap while preserving side/bottom padding normally.
                topPadding = 0.0F
            End If

            Return New MASLayoutInset(_outerPadding.Left * safeProfile.GapScale,
                                      topPadding,
                                      _outerPadding.Right * safeProfile.GapScale,
                                      _outerPadding.Bottom * safeProfile.GapScale)
        End Function

        Private Shared Function ResolveSidebarWidth(size As MASApplicationSurfaceSideSize,
                                                    profile As MASSizeProfile) As Single
            Dim baseWidth As Single
            Select Case NormalizeSidebarSize(size)
                Case MASApplicationSurfaceSideSize.Compact
                    baseWidth = MASApplicationLayoutSizeTokens.ApplicationSurfaceSideCompactWidth
                Case MASApplicationSurfaceSideSize.Wide
                    baseWidth = MASApplicationLayoutSizeTokens.ApplicationSurfaceSideWideWidth
                Case Else
                    baseWidth = MASApplicationLayoutSizeTokens.ApplicationSurfaceSideDefaultWidth
            End Select

            Return baseWidth * MASSizeProfile.Normalize(profile).WidthScale
        End Function

        Private Shared Function ResolveBarHeight(size As MASApplicationSurfaceBarSize,
                                                 profile As MASSizeProfile) As Single
            Dim baseHeight As Single
            Select Case NormalizeBarSize(size)
                Case MASApplicationSurfaceBarSize.Compact
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceBarCompactHeight
                Case MASApplicationSurfaceBarSize.Large
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceBarLargeHeight
                Case Else
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceBarDefaultHeight
            End Select

            Return baseHeight * MASSizeProfile.Normalize(profile).HeightScale
        End Function

        Private Shared Function ResolveFooterHeight(size As MASApplicationSurfaceBarSize,
                                                    profile As MASSizeProfile) As Single
            Dim baseHeight As Single
            Select Case NormalizeBarSize(size)
                Case MASApplicationSurfaceBarSize.Compact
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceFooterCompactHeight
                Case MASApplicationSurfaceBarSize.Large
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceFooterLargeHeight
                Case Else
                    baseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceFooterDefaultHeight
            End Select

            Return baseHeight * MASSizeProfile.Normalize(profile).HeightScale
        End Function

        Private Function ResolveCommandBarHeight(size As MASApplicationSurfaceBarSize,
                                                 profile As MASSizeProfile) As Single
            Dim baseHeight As Single = ResolveBarHeight(size, profile)
            If Not IsCommandBackgroundVisible() Then Return baseHeight

            Dim surfaceBaseHeight As Single
            Select Case NormalizeBarSize(size)
                Case MASApplicationSurfaceBarSize.Compact
                    surfaceBaseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceCommandBackgroundCompactHeight
                Case MASApplicationSurfaceBarSize.Large
                    surfaceBaseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceCommandBackgroundLargeHeight
                Case Else
                    surfaceBaseHeight = MASApplicationLayoutSizeTokens.ApplicationSurfaceCommandBackgroundDefaultHeight
            End Select

            Return Math.Max(baseHeight, surfaceBaseHeight * MASSizeProfile.Normalize(profile).HeightScale)
        End Function

        Private Function ShouldPlaceCommandBarInMainArea() As Boolean
            If _commandBarPage Is Nothing Then Return False

            Select Case NormalizeCommandBarPlacement(_commandBarPlacement)
                Case MASApplicationSurfaceCommandBarPlacement.FullApplicationSurfaceTop
                    Return False
                Case MASApplicationSurfaceCommandBarPlacement.MainAreaTop
                    Return True
                Case Else
                    Return (_sidebarPage IsNot Nothing OrElse _sidebarFooterPage IsNot Nothing)
            End Select
        End Function

        Private Function ShouldPlaceFooterInMainArea() As Boolean
            If _footerPage Is Nothing Then Return False
            Return NormalizeFooterPlacement(_footerPlacement) = MASApplicationSurfaceFooterPlacement.MainAreaBottom
        End Function

        Private Shared Function MoveTop(bounds As SKRect, delta As Single) As SKRect
            Dim top As Single = Math.Min(bounds.Bottom, bounds.Top + Math.Max(0.0F, delta))
            Return New SKRect(bounds.Left, top, bounds.Right, bounds.Bottom)
        End Function

        Private Shared Function MoveBottom(bounds As SKRect, delta As Single) As SKRect
            Dim bottom As Single = Math.Max(bounds.Top, bounds.Bottom - Math.Max(0.0F, delta))
            Return New SKRect(bounds.Left, bounds.Top, bounds.Right, bottom)
        End Function

        Private Shared Function NormalizeRhythm(value As MASApplicationSurfaceRhythm) As MASApplicationSurfaceRhythm
            If [Enum].IsDefined(GetType(MASApplicationSurfaceRhythm), value) Then Return value
            Return MASApplicationSurfaceRhythm.Comfortable
        End Function

        Private Shared Function NormalizeCommandBarPlacement(value As MASApplicationSurfaceCommandBarPlacement) As MASApplicationSurfaceCommandBarPlacement
            If [Enum].IsDefined(GetType(MASApplicationSurfaceCommandBarPlacement), value) Then Return value
            Return MASApplicationSurfaceCommandBarPlacement.Auto
        End Function

        Private Shared Function NormalizeFooterPlacement(value As MASApplicationSurfaceFooterPlacement) As MASApplicationSurfaceFooterPlacement
            If [Enum].IsDefined(GetType(MASApplicationSurfaceFooterPlacement), value) Then Return value
            Return MASApplicationSurfaceFooterPlacement.FullApplicationSurfaceBottom
        End Function

        Private Shared Function NormalizeSidebarSize(size As MASApplicationSurfaceSideSize) As MASApplicationSurfaceSideSize
            If [Enum].IsDefined(GetType(MASApplicationSurfaceSideSize), size) Then Return size
            Return MASApplicationSurfaceSideSize.[Default]
        End Function

        Private Shared Function NormalizeBarSize(size As MASApplicationSurfaceBarSize) As MASApplicationSurfaceBarSize
            If [Enum].IsDefined(GetType(MASApplicationSurfaceBarSize), size) Then Return size
            Return MASApplicationSurfaceBarSize.[Default]
        End Function

        Friend Shared Function SafeNonNegative(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value < 0.0F Then Return 0.0F
            Return value
        End Function
    End Class

End Namespace
