Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Composition

    ''' <summary>
    ''' Internal selection-dialog content page recipe for MAS Composition.
    ''' This type creates layout descriptions only. It does not create a Form, draw Windows chrome,
    ''' draw a top bar, open overlays, own focus/input routing, own Theme state, or render borders.
    ''' The outer dialog shell should be owned by the Application/PanelShell layer so it can use the
    ''' same MASPanelShell header/chrome path used by MessageBox, FilePicker, and FileExplorer.
    ''' </summary>
    <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
    Friend NotInheritable Class MASSelectionDialogPage

        Private Const DEFAULT_SPACING As Single = MASCompositionPageSizeTokens.SelectionDialogSpacing
        Private Const DEFAULT_TOOLBAR_SPACING As Single = MASCompositionPageSizeTokens.SelectionDialogToolbarSpacing
        Private Const DEFAULT_ACTIONS_SPACING As Single = MASCompositionPageSizeTokens.SelectionDialogActionsSpacing
        Private Const DEFAULT_MAX_CONTENT_WIDTH As Single = MASCompositionPageSizeTokens.SelectionDialogMaxContentWidth

        Private Sub New()
        End Sub

        ''' <summary>
        ''' Creates a selection-dialog content page from existing controls and nested layout nodes.
        ''' Header title/description are optional because the outer MASPanelShell header may already own the dialog title.
        ''' </summary>
        Friend Shared Function Create(Optional title As MASControlBase = Nothing,
                                      Optional description As MASControlBase = Nothing,
                                      Optional toolbar As IMASLayoutNode = Nothing,
                                      Optional content As IMASLayoutNode = Nothing,
                                      Optional actions As IMASLayoutNode = Nothing,
                                      Optional spacing As Single = DEFAULT_SPACING,
                                      Optional padding As MASLayoutThickness = Nothing,
                                      Optional titleHeight As MASSizePolicy = Nothing,
                                      Optional descriptionHeight As MASSizePolicy = Nothing,
                                      Optional toolbarHeight As MASSizePolicy = Nothing,
                                      Optional contentHeight As MASSizePolicy = Nothing,
                                      Optional actionsWidth As MASSizePolicy = Nothing,
                                      Optional actionsHeight As MASSizePolicy = Nothing,
                                      Optional maxContentWidth As Single = DEFAULT_MAX_CONTENT_WIDTH,
                                      Optional scrollEnabled As Boolean = False,
                                      Optional scrollKey As String = "",
                                      Optional useDefaultVisualPolish As Boolean = True) As IMASLayoutNode

            Dim items As New List(Of MASLayoutItem)()

            If title IsNot Nothing Then
                items.Add(
                    MASComposition.Item(
                        control:=title,
                        width:=MASSizePolicy.Fill(1.0F),
                        height:=If(titleHeight, MASSizePolicy.Auto()),
                        alignment:=MASLayoutAlignment.Stretch,
                        margin:=ResolveTitleMargin(useDefaultVisualPolish),
                        key:="MASSelectionDialogPage.Title"))
            End If

            If description IsNot Nothing Then
                items.Add(
                    MASComposition.Item(
                        control:=description,
                        width:=MASSizePolicy.Fill(1.0F),
                        height:=If(descriptionHeight, MASSizePolicy.Auto()),
                        alignment:=MASLayoutAlignment.Stretch,
                        margin:=ResolveDescriptionMargin(useDefaultVisualPolish),
                        key:="MASSelectionDialogPage.Description"))
            End If

            If toolbar IsNot Nothing Then
                items.Add(
                    MASComposition.NodeItem(
                        node:=toolbar,
                        width:=MASSizePolicy.Fill(1.0F),
                        height:=If(toolbarHeight, MASSizePolicy.Auto()),
                        alignment:=MASLayoutAlignment.Stretch,
                        margin:=ResolveToolbarMargin(useDefaultVisualPolish),
                        key:="MASSelectionDialogPage.Toolbar"))
            End If

            If content IsNot Nothing Then
                Dim contentNode As IMASLayoutNode =
                    WrapContentSlot(
                        node:=content,
                        maxContentWidth:=maxContentWidth,
                        scrollEnabled:=scrollEnabled,
                        scrollKey:=scrollKey)

                items.Add(
                    MASComposition.NodeItem(
                        node:=contentNode,
                        width:=MASSizePolicy.Fill(1.0F),
                        height:=If(contentHeight, MASSizePolicy.Fill(1.0F)),
                        alignment:=MASLayoutAlignment.Stretch,
                        key:="MASSelectionDialogPage.Content"))
            End If

            If actions IsNot Nothing Then
                items.Add(
                    MASComposition.NodeItem(
                        node:=actions,
                        width:=If(actionsWidth, MASSizePolicy.Auto()),
                        height:=If(actionsHeight, MASSizePolicy.Auto()),
                        alignment:=MASLayoutAlignment.End,
                        margin:=ResolveActionsMargin(useDefaultVisualPolish),
                        key:="MASSelectionDialogPage.Actions"))
            End If

            Dim pageNode As IMASLayoutNode =
                MASComposition.Vertical(
                    children:=items.ToArray(),
                    spacing:=SafeSpacing(spacing),
                    padding:=ResolvePagePadding(padding, useDefaultVisualPolish),
                    alignment:=MASLayoutAlignment.Stretch)

            Return pageNode
        End Function

        ''' <summary>
        ''' Creates a selection-dialog content page from title and description text.
        ''' Generated labels are ordinary MASLabel controls; rendering remains owned by the label system.
        ''' </summary>
        Friend Shared Function FromText(Optional titleText As String = "",
                                        Optional descriptionText As String = "",
                                        Optional toolbar As IMASLayoutNode = Nothing,
                                        Optional content As IMASLayoutNode = Nothing,
                                        Optional actions As IMASLayoutNode = Nothing,
                                        Optional spacing As Single = DEFAULT_SPACING,
                                        Optional padding As MASLayoutThickness = Nothing,
                                        Optional titleHeight As MASSizePolicy = Nothing,
                                        Optional descriptionHeight As MASSizePolicy = Nothing,
                                        Optional toolbarHeight As MASSizePolicy = Nothing,
                                        Optional contentHeight As MASSizePolicy = Nothing,
                                        Optional actionsWidth As MASSizePolicy = Nothing,
                                        Optional actionsHeight As MASSizePolicy = Nothing,
                                        Optional maxContentWidth As Single = DEFAULT_MAX_CONTENT_WIDTH,
                                        Optional scrollEnabled As Boolean = False,
                                        Optional scrollKey As String = "",
                                        Optional useDefaultVisualPolish As Boolean = True) As IMASLayoutNode

            Dim title As MASLabel = Nothing
            Dim description As MASLabel = Nothing

            If Not String.IsNullOrWhiteSpace(titleText) Then
                title = CreateTitleLabel(titleText)
            End If

            If Not String.IsNullOrWhiteSpace(descriptionText) Then
                description = CreateDescriptionLabel(descriptionText)
            End If

            Return Create(
                title:=title,
                description:=description,
                toolbar:=toolbar,
                content:=content,
                actions:=actions,
                spacing:=spacing,
                padding:=padding,
                titleHeight:=titleHeight,
                descriptionHeight:=descriptionHeight,
                toolbarHeight:=toolbarHeight,
                contentHeight:=contentHeight,
                actionsWidth:=actionsWidth,
                actionsHeight:=actionsHeight,
                maxContentWidth:=maxContentWidth,
                scrollEnabled:=scrollEnabled,
                scrollKey:=scrollKey,
                useDefaultVisualPolish:=useDefaultVisualPolish)
        End Function

        ''' <summary>
        ''' Wraps a single content control as a fill layout node suitable for the Content slot.
        ''' </summary>
        Friend Shared Function Content(control As MASControlBase,
                                       Optional width As MASSizePolicy = Nothing,
                                       Optional height As MASSizePolicy = Nothing,
                                       Optional margin As MASLayoutThickness = Nothing,
                                       Optional key As String = "") As IMASLayoutNode

            If control Is Nothing Then Return Nothing

            Return MASComposition.Vertical(
                children:=New MASLayoutItem() {
                    MASComposition.Item(
                        control:=control,
                        width:=If(width, MASSizePolicy.Fill(1.0F)),
                        height:=If(height, MASSizePolicy.Fill(1.0F)),
                        alignment:=MASLayoutAlignment.Stretch,
                        margin:=margin,
                        key:=If(key, String.Empty))
                },
                spacing:=0.0F,
                padding:=MASLayoutThickness.None(),
                alignment:=MASLayoutAlignment.Stretch)
        End Function

        ''' <summary>
        ''' Creates the standard selection-toolbar row. The row is layout-only and is intended for
        ''' actions such as Recommended, Select All, and Unselect.
        ''' </summary>
        Friend Shared Function ToolbarRow(controls As IEnumerable(Of MASControlBase),
                                          Optional spacing As Single = DEFAULT_TOOLBAR_SPACING,
                                          Optional padding As MASLayoutThickness = Nothing,
                                          Optional key As String = "",
                                          Optional useDefaultVisualPolish As Boolean = True) As IMASLayoutNode

            Dim items As New List(Of MASLayoutItem)()

            If controls IsNot Nothing Then
                Dim index As Integer = 0

                For Each control As MASControlBase In controls
                    If control IsNot Nothing Then
                        Dim itemKey As String = If(String.IsNullOrEmpty(key), String.Empty, key & "." & index.ToString(Globalization.CultureInfo.InvariantCulture))

                        items.Add(
                            MASComposition.Item(
                                control:=control,
                                width:=MASSizePolicy.Auto(),
                                height:=MASSizePolicy.Auto(),
                                alignment:=MASLayoutAlignment.Center,
                                key:=itemKey))

                        index += 1
                    End If
                Next
            End If

            Return MASComposition.Horizontal(
                children:=items.ToArray(),
                spacing:=SafeSpacing(spacing),
                padding:=ResolveToolbarPadding(padding, useDefaultVisualPolish),
                alignment:=MASLayoutAlignment.Center)
        End Function

        ''' <summary>
        ''' Creates the standard footer actions row for selection dialogs.
        ''' The caller still owns button click handlers and final dialog results.
        ''' </summary>
        Friend Shared Function ActionsRow(primary As MASControlBase,
                                          Optional secondary As MASControlBase = Nothing,
                                          Optional spacing As Single = DEFAULT_ACTIONS_SPACING,
                                          Optional padding As MASLayoutThickness = Nothing,
                                          Optional key As String = "",
                                          Optional useDefaultVisualPolish As Boolean = True) As IMASLayoutNode

            Return MASPage.ActionsRow(
                primary:=primary,
                secondary:=secondary,
                spacing:=spacing,
                padding:=padding,
                key:=key,
                useDefaultVisualPolish:=useDefaultVisualPolish)
        End Function

        ''' <summary>
        ''' Creates the standard footer actions row from an ordered set of action controls.
        ''' </summary>
        Friend Shared Function ActionsRow(controls As IEnumerable(Of MASControlBase),
                                          Optional spacing As Single = DEFAULT_ACTIONS_SPACING,
                                          Optional padding As MASLayoutThickness = Nothing,
                                          Optional key As String = "",
                                          Optional useDefaultVisualPolish As Boolean = True) As IMASLayoutNode

            Return MASPage.ActionsRow(
                controls:=controls,
                spacing:=spacing,
                padding:=padding,
                key:=key,
                useDefaultVisualPolish:=useDefaultVisualPolish)
        End Function

        Private Shared Function CreateTitleLabel(text As String) As MASLabel
            Return New MASLabel(If(text, String.Empty)) With {
                .LabelVariant = MASLabelVariant.Heading,
                .TextRole = MASLabelTextRole.Primary,
                .HorizontalAlignment = MASHorizontalAlignment.Left,
                .VerticalAlignment = MASVerticalAlignment.Center,
                .MultiLine = True,
                .WordWrap = True,
                .CompositionLifetimeOwnedInternal = True
            }
        End Function

        Private Shared Function CreateDescriptionLabel(text As String) As MASLabel
            Return New MASLabel(If(text, String.Empty)) With {
                .LabelVariant = MASLabelVariant.Body,
                .TextRole = MASLabelTextRole.Secondary,
                .HorizontalAlignment = MASHorizontalAlignment.Left,
                .VerticalAlignment = MASVerticalAlignment.Center,
                .MultiLine = True,
                .WordWrap = True,
                .CompositionLifetimeOwnedInternal = True
            }
        End Function

        Private Shared Function ResolvePagePadding(value As MASLayoutThickness, useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If useDefaultVisualPolish AndAlso IsEmptyThickness(value) Then
                Return MASCompositionPageSizeTokens.SelectionDialogPagePadding()
            End If

            Return value
        End Function

        Private Shared Function ResolveToolbarPadding(value As MASLayoutThickness, useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If useDefaultVisualPolish AndAlso IsEmptyThickness(value) Then
                Return MASLayoutThickness.None()
            End If

            Return value
        End Function

        Private Shared Function ResolveTitleMargin(useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If Not useDefaultVisualPolish Then Return MASLayoutThickness.None()
            Return MASCompositionPageSizeTokens.SelectionDialogTitleMargin()
        End Function

        Private Shared Function ResolveDescriptionMargin(useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If Not useDefaultVisualPolish Then Return MASLayoutThickness.None()
            Return MASCompositionPageSizeTokens.SelectionDialogDescriptionMargin()
        End Function

        Private Shared Function ResolveToolbarMargin(useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If Not useDefaultVisualPolish Then Return MASLayoutThickness.None()
            Return MASCompositionPageSizeTokens.SelectionDialogToolbarMargin()
        End Function

        Private Shared Function ResolveActionsMargin(useDefaultVisualPolish As Boolean) As MASLayoutThickness
            If Not useDefaultVisualPolish Then Return MASLayoutThickness.None()
            Return MASCompositionPageSizeTokens.SelectionDialogActionsMargin()
        End Function

        Private Shared Function WrapContentSlot(node As IMASLayoutNode,
                                                          maxContentWidth As Single,
                                                          scrollEnabled As Boolean,
                                                          scrollKey As String) As IMASLayoutNode
            If node Is Nothing Then Return Nothing

            If scrollEnabled Then
                Return New MASVerticalScrollLayoutNode(
                    content:=node,
                    scrollKey:=NormalizeScrollKey(scrollKey),
                    maxContentWidth:=maxContentWidth,
                    padding:=MASLayoutThickness.None())
            End If

            Return WrapMaxContentWidth(node, maxContentWidth)
        End Function

        Private Shared Function WrapMaxContentWidth(node As IMASLayoutNode,
                                                    maxContentWidth As Single) As IMASLayoutNode
            If node Is Nothing Then Return Nothing

            If Not IsFinitePositive(maxContentWidth) Then
                Return node
            End If

            Return MASComposition.Vertical(
                spacing:=0.0F,
                padding:=MASLayoutThickness.None(),
                alignment:=MASLayoutAlignment.Center,
                children:=New MASLayoutItem() {
                    MASComposition.NodeItem(
                        node:=node,
                        width:=MASSizePolicy.Fixed(maxContentWidth),
                        height:=MASSizePolicy.Fill(1.0F),
                        alignment:=MASLayoutAlignment.Center)
                })
        End Function

        Private Shared Function NormalizeScrollKey(value As String) As String
            If String.IsNullOrWhiteSpace(value) Then Return "MASSelectionDialogPage.Scroll"
            Return value.Trim()
        End Function

        Private Shared Function IsEmptyThickness(value As MASLayoutThickness) As Boolean
            Return MASCompositionPageSizeTokens.IsEmptyThickness(value)
        End Function

        Private Shared Function SafeSpacing(value As Single) As Single
            Return MASCompositionPageSizeTokens.SafeSpacing(value)
        End Function

        Private Shared Function IsFinitePositive(value As Single) As Boolean
            Return MASCompositionPageSizeTokens.IsFinitePositive(value)
        End Function

    End Class

End Namespace
