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.Theming
Imports SkiaSharp

Namespace Nexamas.UI.Application


    ''' <summary>
    ''' Public split-pane builder used only through MASApplicationLayoutPageBuilder.SplitPane().
    ''' It composes one left narrative stack and one right surface stack through the native
    ''' MASLayout grid/stack primitives, so consumers get a stable page pattern without
    ''' manual widths, coordinates, or a separate showcase layout helper.
    ''' </summary>
    Public NotInheritable Class MASApplicationSplitPaneLayoutBuilder
        Private ReadOnly _narrative As New List(Of Object)()
        Private ReadOnly _surface As New List(Of Object)()
        Private _gap As Single = MASApplicationLayoutSizeTokens.GridGap
        Private _narrativeSpacing As Single = MASApplicationLayoutSizeTokens.StackSpacing
        Private _surfaceSpacing As Single = MASApplicationLayoutSizeTokens.StackSpacing

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

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

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

        ''' <summary>
        ''' Adds one control to the narrative pane. The Add* naming avoids ambiguity with
        ''' product-domain variables named Narrative/Surface and keeps the SplitPane API
        ''' explicit as a layout builder rather than a Controls collection indexer.
        ''' </summary>
        Public Function AddNarrative(control As MASControlBase,
                                     Optional sizeIntent As MASSize = Nothing) As MASApplicationSplitPaneLayoutBuilder
            If control IsNot Nothing Then
                _narrative.Add(New MASApplicationLayoutControlEntry(control, sizeIntent, MASLayoutCrossAlignment.Stretch))
            End If

            Return Me
        End Function

        ''' <summary>
        ''' Adds one control to the surface pane. Surfaces remain MASLayout entries; this
        ''' method does not create a parallel sizing or rendering path.
        ''' </summary>
        Public Function AddSurface(control As MASControlBase,
                                   Optional sizeIntent As MASSize = Nothing) As MASApplicationSplitPaneLayoutBuilder
            If control IsNot Nothing Then
                _surface.Add(New MASApplicationLayoutControlEntry(control, sizeIntent, MASLayoutCrossAlignment.Stretch))
            End If

            Return Me
        End Function

        ''' <summary>
        ''' Adds an official surface grid inside the right pane. This is still built from
        ''' MASApplicationLayoutGridBuilder and MASLayout; it only prevents product pages
        ''' from inventing local widths when a narrative pane must sit beside two related
        ''' collection/data surfaces.
        ''' </summary>
        Friend Function AddSurfaceGrid(columns As Integer,
                                       kind As MASApplicationControlSurfaceSizeKind,
                                       ParamArray controls() As MASControlBase) As MASApplicationSplitPaneLayoutBuilder
            Dim grid As New MASApplicationLayoutGridBuilder(Math.Max(1, columns))
            grid.Gap(MASLayoutSpacing.Medium)
            If controls IsNot Nothing Then
                Dim sizeIntent As MASSize = MASApplicationLayoutPolicy.ResolveControlSurfaceSize(kind)
                For Each control As MASControlBase In controls
                    If control IsNot Nothing Then grid.Add(control, sizeIntent)
                Next
            End If

            _surface.Add(grid)
            Return Me
        End Function

        Friend Function BuildNode(Optional sizeProfile As MASSizeProfile = Nothing) As MASLayoutNode
            Dim profile As MASSizeProfile = MASSizeProfile.Normalize(sizeProfile)
            Dim columns As New List(Of MASLayoutNode)()

            Dim narrativeNode As MASLayoutNode = BuildPaneNode(_narrative, _narrativeSpacing, profile)
            If narrativeNode IsNot Nothing Then columns.Add(narrativeNode)

            Dim surfaceNode As MASLayoutNode = BuildPaneNode(_surface, _surfaceSpacing, profile)
            If surfaceNode IsNot Nothing Then columns.Add(surfaceNode)

            If columns.Count = 0 Then Return Nothing
            If columns.Count = 1 Then Return columns(0)

            Return MASLayoutBuilder.SplitPane(narrativeNode,
                                             surfaceNode,
                                             MASLayoutSpacingResolver.ScaleLength(_gap, profile),
                                             MASLayoutInset.Empty,
                                             MASApplicationLayoutSizeTokens.NarrativeSurfaceNarrativePreferredWidth,
                                             MASApplicationLayoutSizeTokens.NarrativeSurfaceMinimumSplitWidth)
        End Function

        Friend Sub CollectControls(target As IList(Of MASControlBase))
            If target Is Nothing Then Return
            CollectPaneControls(_narrative, target)
            CollectPaneControls(_surface, target)
        End Sub

        Private Shared Function BuildPaneNode(children As IEnumerable(Of Object),
                                              spacing As Single,
                                              profile As MASSizeProfile) As MASLayoutNode
            Dim nodes As New List(Of MASLayoutNode)()
            If children IsNot Nothing Then
                For Each child As Object In children
                    Dim node As MASLayoutNode = BuildPaneChildNode(child, profile)
                    If node IsNot Nothing Then nodes.Add(node)
                Next
            End If

            If nodes.Count = 0 Then Return Nothing

            Return MASLayoutBuilder.StackVertical(nodes,
                                                  MASLayoutSpacingResolver.ScaleLength(spacing, profile),
                                                  MASLayoutInset.Empty,
                                                  MASLayoutCrossAlignment.Stretch,
                                                  MASLayoutGroupSizingMode.Intrinsic)
        End Function

        Private Shared Function BuildPaneChildNode(child As Object, profile As MASSizeProfile) As MASLayoutNode
            If TypeOf child Is MASApplicationLayoutControlEntry Then
                Return DirectCast(child, MASApplicationLayoutControlEntry).BuildNode()
            End If

            If TypeOf child Is MASApplicationLayoutGridBuilder Then
                Return DirectCast(child, MASApplicationLayoutGridBuilder).BuildNode(profile)
            End If

            Return Nothing
        End Function

        Private Shared Sub CollectPaneControls(children As IEnumerable(Of Object), target As IList(Of MASControlBase))
            If children Is Nothing OrElse target Is Nothing Then Return
            For Each child As Object In children
                If TypeOf child Is MASApplicationLayoutControlEntry Then
                    DirectCast(child, MASApplicationLayoutControlEntry).CollectControls(target)
                ElseIf TypeOf child Is MASApplicationLayoutGridBuilder Then
                    DirectCast(child, MASApplicationLayoutGridBuilder).CollectControls(target)
                End If
            Next
        End Sub
    End Class

End Namespace
