Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Layout
Imports SkiaSharp

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Public semantic tile-size vocabulary for Gallery layouts. Consumers choose a product intent;
    ''' Nexamas UI resolves the final logical tile width/height from the active MASSizeProfile.
    ''' </summary>
    Public Enum MASApplicationGalleryTileSize
        Compact = 0
        [Default] = 1
        Large = 2
        Preview = 3
        Hero = 4
    End Enum

    ''' <summary>
    ''' Public semantic horizontal alignment choices for galleries whose capped tile columns do not fill
    ''' the whole content workspace. The layout remains slot-based, not coordinate-based.
    ''' </summary>
    Public Enum MASApplicationGalleryAlignment
        Start = 0
        Center = 1
        [End] = 2
    End Enum

    ''' <summary>
    ''' Official semantic gallery builder for tile/icon/card collections. It is not a helper and not
    ''' a product-specific engine: it converts Gallery intent into the native MASLayout TileGrid primitive,
    ''' preserving MASSize profiles, semantic spacing, equal tile sizing, and responsive column wrapping.
    ''' </summary>
    Public NotInheritable Class MASApplicationGalleryLayoutBuilder
        Private ReadOnly _children As New List(Of MASApplicationLayoutControlEntry)()
        Private _gap As Single = MASLayoutSpacingResolver.ResolveBase(MASLayoutSpacing.Small)
        Private _padding As MASLayoutInset = MASLayoutInset.Empty
        Private _tileSize As MASApplicationGalleryTileSize = MASApplicationGalleryTileSize.[Default]
        Private _customTileWidth As Single
        Private _customTileHeight As Single
        Private _minColumns As Integer = 1
        Private _maxColumns As Integer
        Private _alignment As MASApplicationGalleryAlignment = MASApplicationGalleryAlignment.Start

        Friend Sub New()
        End Sub

        ''' <summary>
        ''' Uses a semantic tile size. This is the preferred SDK path for icon galleries, preview grids,
        ''' and card collections because it remains density/profile aware.
        ''' </summary>
        Public Function TileSize(value As MASApplicationGalleryTileSize) As MASApplicationGalleryLayoutBuilder
            _tileSize = NormalizeTileSize(value)
            _customTileWidth = 0.0F
            _customTileHeight = 0.0F
            Return Me
        End Function

        Public Function CompactTiles() As MASApplicationGalleryLayoutBuilder
            Return TileSize(MASApplicationGalleryTileSize.Compact)
        End Function

        Public Function DefaultTiles() As MASApplicationGalleryLayoutBuilder
            Return TileSize(MASApplicationGalleryTileSize.[Default])
        End Function

        Public Function LargeTiles() As MASApplicationGalleryLayoutBuilder
            Return TileSize(MASApplicationGalleryTileSize.Large)
        End Function

        Public Function PreviewTiles() As MASApplicationGalleryLayoutBuilder
            Return TileSize(MASApplicationGalleryTileSize.Preview)
        End Function

        Public Function HeroTiles() As MASApplicationGalleryLayoutBuilder
            Return TileSize(MASApplicationGalleryTileSize.Hero)
        End Function

        ''' <summary>
        ''' Advanced explicit tile-size escape hatch. Prefer TileSize(MASApplicationGalleryTileSize)
        ''' in normal application code so size profiles remain the primary tuning surface.
        ''' </summary>
        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Function TileSize(width As Single, height As Single) As MASApplicationGalleryLayoutBuilder
            _customTileWidth = MASApplicationLayoutPageBuilder.SafeNonNegative(width)
            _customTileHeight = MASApplicationLayoutPageBuilder.SafeNonNegative(height)
            Return Me
        End Function

        Public Function Gap(value As MASLayoutSpacing) As MASApplicationGalleryLayoutBuilder
            _gap = MASLayoutSpacingResolver.ResolveBase(value)
            Return Me
        End Function

        Public Function Spacing(value As MASLayoutSpacing) As MASApplicationGalleryLayoutBuilder
            Return Gap(value)
        End Function

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Function Gap(value As Single) As MASApplicationGalleryLayoutBuilder
            _gap = MASApplicationLayoutPageBuilder.SafeNonNegative(value)
            Return Me
        End Function

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Function Spacing(value As Single) As MASApplicationGalleryLayoutBuilder
            Return Gap(value)
        End Function

        Public Function Padding(value As MASLayoutSpacing) As MASApplicationGalleryLayoutBuilder
            _padding = MASLayoutSpacingResolver.ResolveInsetBase(value)
            Return Me
        End Function

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Function Padding(all As Single) As MASApplicationGalleryLayoutBuilder
            _padding = New MASLayoutInset(all)
            Return Me
        End Function

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Function Padding(left As Single,
                                top As Single,
                                right As Single,
                                bottom As Single) As MASApplicationGalleryLayoutBuilder
            _padding = New MASLayoutInset(left, top, right, bottom)
            Return Me
        End Function

        ''' <summary>
        ''' Sets the preferred minimum number of columns when the workspace has enough width.
        ''' Narrow hosts may still resolve to fewer columns to avoid clipping.
        ''' </summary>
        Public Function MinColumns(value As Integer) As MASApplicationGalleryLayoutBuilder
            _minColumns = Math.Max(1, value)
            If _maxColumns > 0 AndAlso _maxColumns < _minColumns Then _maxColumns = _minColumns
            Return Me
        End Function

        ''' <summary>
        ''' Caps the responsive gallery column count. Use this when a content area should not stretch
        ''' into an unreadably wide row of tiny meaning units.
        ''' </summary>
        Public Function MaxColumns(value As Integer) As MASApplicationGalleryLayoutBuilder
            _maxColumns = Math.Max(0, value)
            If _maxColumns > 0 AndAlso _maxColumns < _minColumns Then _maxColumns = _minColumns
            Return Me
        End Function

        ''' <summary>
        ''' Uses an exact semantic column count when the workspace width allows it, without consumer x/y coordinates.
        ''' </summary>
        Public Function Columns(value As Integer) As MASApplicationGalleryLayoutBuilder
            Dim safe As Integer = Math.Max(1, value)
            _minColumns = safe
            _maxColumns = safe
            Return Me
        End Function

        ''' <summary>
        ''' Lets the gallery use as many columns as fit the available workspace.
        ''' </summary>
        Public Function Wrap() As MASApplicationGalleryLayoutBuilder
            _maxColumns = 0
            Return Me
        End Function

        Public Function AlignStart() As MASApplicationGalleryLayoutBuilder
            _alignment = MASApplicationGalleryAlignment.Start
            Return Me
        End Function

        Public Function AlignCenter() As MASApplicationGalleryLayoutBuilder
            _alignment = MASApplicationGalleryAlignment.Center
            Return Me
        End Function

        Public Function AlignEnd() As MASApplicationGalleryLayoutBuilder
            _alignment = MASApplicationGalleryAlignment.[End]
            Return Me
        End Function

        Public Function Align(value As MASApplicationGalleryAlignment) As MASApplicationGalleryLayoutBuilder
            _alignment = NormalizeAlignment(value)
            Return Me
        End Function

        ''' <summary>
        ''' Adds one tile control. The tile receives a stable Gallery slot; the control itself does not
        ''' receive Width/Height assignments from consumer code.
        ''' </summary>
        Public Function Add(control As MASControlBase,
                            Optional sizeIntent As MASSize = Nothing) As MASApplicationGalleryLayoutBuilder
            If control IsNot Nothing Then
                _children.Add(New MASApplicationLayoutControlEntry(control, sizeIntent, MASLayoutCrossAlignment.Stretch))
            End If

            Return Me
        End Function

        ''' <summary>
        ''' Adds several tile controls in insertion/navigation order.
        ''' </summary>
        Public Function AddRange(ParamArray controls As MASControlBase()) As MASApplicationGalleryLayoutBuilder
            If controls IsNot Nothing Then
                For Each control As MASControlBase In controls
                    Add(control)
                Next
            End If

            Return Me
        End Function

        Friend Function BuildNode(Optional sizeProfile As MASSizeProfile = Nothing) As MASLayoutNode
            Dim profile As MASSizeProfile = MASSizeProfile.Normalize(sizeProfile)
            Dim nodes As New List(Of MASLayoutNode)()
            For Each child As MASApplicationLayoutControlEntry In _children
                nodes.Add(child.BuildNode())
            Next

            Dim tileSize As SKSize = ResolveTileSize(profile)
            Return MASLayoutBuilder.TileGrid(nodes,
                                             _minColumns,
                                             _maxColumns,
                                             tileSize.Width,
                                             tileSize.Height,
                                             MASLayoutSpacingResolver.ScaleLength(_gap, profile),
                                             MASLayoutSpacingResolver.ScaleInset(_padding, profile),
                                             ResolveMainAlignment(_alignment),
                                             MASLayoutGroupSizingMode.EqualSize)
        End Function

        Friend Sub CollectControls(target As IList(Of MASControlBase))
            If target Is Nothing Then Return
            For Each child As MASApplicationLayoutControlEntry In _children
                child.CollectControls(target)
            Next
        End Sub

        Private Function ResolveTileSize(profile As MASSizeProfile) As SKSize
            If _customTileWidth > 0.0F AndAlso _customTileHeight > 0.0F Then
                Return New SKSize(MASLayoutSpacingResolver.ScaleWidth(_customTileWidth, profile),
                                  MASLayoutSpacingResolver.ScaleHeight(_customTileHeight, profile))
            End If

            Dim baseSize As SKSize = MASApplicationGalleryTileSizeResolver.ResolveBase(_tileSize)
            Return New SKSize(MASLayoutSpacingResolver.ScaleWidth(baseSize.Width, profile),
                              MASLayoutSpacingResolver.ScaleHeight(baseSize.Height, profile))
        End Function

        Private Shared Function NormalizeTileSize(value As MASApplicationGalleryTileSize) As MASApplicationGalleryTileSize
            If [Enum].IsDefined(GetType(MASApplicationGalleryTileSize), value) Then Return value
            Return MASApplicationGalleryTileSize.[Default]
        End Function

        Private Shared Function NormalizeAlignment(value As MASApplicationGalleryAlignment) As MASApplicationGalleryAlignment
            If [Enum].IsDefined(GetType(MASApplicationGalleryAlignment), value) Then Return value
            Return MASApplicationGalleryAlignment.Start
        End Function

        Private Shared Function ResolveMainAlignment(value As MASApplicationGalleryAlignment) As MASLayoutMainAlignment
            Select Case NormalizeAlignment(value)
                Case MASApplicationGalleryAlignment.Center
                    Return MASLayoutMainAlignment.Center
                Case MASApplicationGalleryAlignment.[End]
                    Return MASLayoutMainAlignment.[End]
                Case Else
                    Return MASLayoutMainAlignment.Start
            End Select
        End Function
    End Class

    ''' <summary>
    ''' Internal semantic gallery tile-size resolver. Base values stay inside Nexamas UI and are later
    ''' scaled by MASSizeProfile; external projects should not hard-code these DIP numbers.
    ''' </summary>
    Friend NotInheritable Class MASApplicationGalleryTileSizeResolver
        Private Sub New()
        End Sub

        Friend Shared Function ResolveBase(size As MASApplicationGalleryTileSize) As SKSize
            Select Case Normalize(size)
                Case MASApplicationGalleryTileSize.Compact
                    Return MASApplicationLayoutSizeTokens.GalleryCompactTileSize()
                Case MASApplicationGalleryTileSize.Large
                    Return MASApplicationLayoutSizeTokens.GalleryLargeTileSize()
                Case MASApplicationGalleryTileSize.Preview
                    Return MASApplicationLayoutSizeTokens.GalleryPreviewTileSize()
                Case MASApplicationGalleryTileSize.Hero
                    Return MASApplicationLayoutSizeTokens.GalleryHeroTileSize()
                Case Else
                    Return MASApplicationLayoutSizeTokens.GalleryDefaultTileSize()
            End Select
        End Function

        Private Shared Function Normalize(size As MASApplicationGalleryTileSize) As MASApplicationGalleryTileSize
            If [Enum].IsDefined(GetType(MASApplicationGalleryTileSize), size) Then Return size
            Return MASApplicationGalleryTileSize.[Default]
        End Function
    End Class

End Namespace
