Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Components.DropDownMenu
Imports Nexamas.UI.Icons
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public Class MASToolbar

#Region "CommandBar API"

        ''' <summary>
        ''' Adds a premium command action to the official MAS toolbar/command-bar surface.
        ''' The action is represented by a MASButton so it inherits Nexamas UI button theming,
        ''' tooltip, focus, command, size, and icon behavior instead of using an ad-hoc renderer.
        ''' </summary>
        Public Function AddCommand(commandId As String,
                                   text As String,
                                   Optional description As String = "",
                                   Optional iconKind As MASIconKind = MASIconKind.None,
                                   Optional action As Action(Of MASButton) = Nothing,
                                   Optional intent As MASButtonIntent = MASButtonIntent.Default,
                                   Optional widthDip As Single = 0.0F,
                                   Optional alignment As MASToolbarItemAlignment = MASToolbarItemAlignment.Left) As MASButton

            Dim id As String = NormalizeCommandBarId(commandId)
            If id.Length = 0 Then Throw New ArgumentException("A command id is required.", NameOf(commandId))

            Dim button As MASButton = CreateCommandButton(id, text, description, iconKind, action, intent)
            AddCommandButtonToToolbar(id, button, text, iconKind, widthDip, alignment)
            Return button
        End Function

        ''' <summary>
        ''' Adds an official split command to the MAS command-bar surface.  The primary action
        ''' stays button-like while menu choices are provided by MASDropDownMenuBuilder and
        ''' displayed through the existing DropDownMenu FloatRuntime route.
        ''' </summary>
        Public Function AddSplitCommand(commandId As String,
                                        text As String,
                                        configureMenu As Action(Of MASDropDownMenuBuilder),
                                        Optional description As String = "",
                                        Optional primaryAction As Action(Of MASSplitButton) = Nothing,
                                        Optional intent As MASButtonIntent = MASButtonIntent.Default,
                                        Optional widthDip As Single = 0.0F,
                                        Optional alignment As MASToolbarItemAlignment = MASToolbarItemAlignment.Left) As MASSplitButton

            Dim id As String = NormalizeCommandBarId(commandId)
            If id.Length = 0 Then Throw New ArgumentException("A command id is required.", NameOf(commandId))

            Dim button As MASSplitButton = CreateCommandSplitButton(id, text, description, configureMenu, primaryAction, intent)
            AddSplitCommandButtonToToolbar(id, button, text, widthDip, alignment)
            Return button
        End Function

        Friend Function ApplyCommandBarDefaultsInternal() As MASToolbar
            Dim premiumProfile As MASCommandBarPremiumProfile = MASCommandBarPremiumProfile.CreateDefault()
            _horizontalPaddingDip = premiumProfile.HorizontalPaddingDip
            _verticalInsetDip = premiumProfile.VerticalInsetDip
            _gapDip = premiumProfile.GapDip
            _itemHeightDip = premiumProfile.ItemHeightDip
            _defaultButtonWidthDip = premiumProfile.IconButtonWidthDip
            _defaultSeparatorWidthDip = premiumProfile.SeparatorWidthDip
            _surfaceMaterialKey = premiumProfile.SurfaceMaterialKey

            RequestSizeLayoutRefreshForSizeAffectingChange("MASToolbar.ApplyCommandBarDefaultsInternal")
            InvalidateVisual()
            Return Me
        End Function

        Friend Function EnsureCommandButtonInternal(commandId As String,
                                                    text As String,
                                                    Optional description As String = "",
                                                    Optional iconKind As MASIconKind = MASIconKind.None,
                                                    Optional action As Action(Of MASButton) = Nothing,
                                                    Optional intent As MASButtonIntent = MASButtonIntent.Default,
                                                    Optional widthDip As Single = 0.0F,
                                                    Optional alignment As MASToolbarItemAlignment = MASToolbarItemAlignment.Left) As MASButton

            Dim id As String = NormalizeCommandBarId(commandId)
            If id.Length = 0 Then Return Nothing

            Dim existing As ToolbarEntry = FindEntry(id)
            If existing IsNot Nothing Then
                Dim existingButton As MASButton = TryCast(existing.Control, MASButton)
                If existingButton Is Nothing Then Return Nothing

                ConfigureCommandButton(existingButton, id, text, description, iconKind, action, intent)
                If widthDip > 0.0F Then existing.WidthDip = Math.Max(widthDip, ToolbarTokens.CommandButtonMinimumWidth)
                RequestSizeLayoutRefreshForSizeAffectingChange("MASToolbar.EnsureCommandButtonInternal")
                InvalidateVisual()
                Return existingButton
            End If

            Return AddCommand(id, text, description, iconKind, action, intent, widthDip, alignment)
        End Function

        Friend Function HasCommandItemInternal(commandId As String) As Boolean
            Return FindEntry(NormalizeCommandBarId(commandId)) IsNot Nothing
        End Function

#End Region

#Region "CommandBar Helpers"

        Private Function CreateCommandButton(commandId As String,
                                             text As String,
                                             description As String,
                                             iconKind As MASIconKind,
                                             action As Action(Of MASButton),
                                             intent As MASButtonIntent) As MASButton

            Dim button As New MASButton(ResolveCommandText(commandId, text)) With {
                .Name = SafeName(commandId)
            }

            ConfigureCommandButton(button, commandId, text, description, iconKind, action, intent)
            AddHandler button.Click, AddressOf OnInternalButtonClick
            Return button
        End Function

        Private Function CreateCommandSplitButton(commandId As String,
                                                  text As String,
                                                  description As String,
                                                  configureMenu As Action(Of MASDropDownMenuBuilder),
                                                  action As Action(Of MASSplitButton),
                                                  intent As MASButtonIntent) As MASSplitButton

            Dim button As New MASSplitButton(ResolveCommandText(commandId, text)) With {
                .Name = SafeName(commandId)
            }

            ConfigureCommandSplitButton(button, commandId, text, description, configureMenu, action, intent)
            AddHandler button.Click, AddressOf OnInternalButtonClick
            Return button
        End Function

        Private Sub ConfigureCommandButton(button As MASButton,
                                           commandId As String,
                                           text As String,
                                           description As String,
                                           iconKind As MASIconKind,
                                           action As Action(Of MASButton),
                                           intent As MASButtonIntent)

            If button Is Nothing Then Return

            button.Text = ResolveCommandText(commandId, text)
            button.Tooltip = ResolveCommandTooltip(description, button.Text)
            button.Intent = intent
            button.Personality = MASButtonPersonality.MAS
            button.WithMinSize(ToolbarTokens.CommandButtonMinimumWidth, ToolbarTokens.CommandButtonMinimumHeight)
            button.WithPreferredSize(ResolveCommandButtonWidthDip(button.Text, iconKind), ToolbarTokens.CommandBarItemHeight)

            If action IsNot Nothing Then
                button.Command = action
            End If

            ApplyCommandIcon(button, iconKind)
        End Sub

        Private Sub AddCommandButtonToToolbar(commandId As String,
                                              button As MASButton,
                                              text As String,
                                              iconKind As MASIconKind,
                                              widthDip As Single,
                                              alignment As MASToolbarItemAlignment)

            Dim resolvedWidth As Single = If(widthDip > 0.0F,
                                             Math.Max(widthDip, ToolbarTokens.CommandButtonMinimumWidth),
                                             ResolveCommandButtonWidthDip(ResolveCommandText(commandId, text), iconKind))

            AddControlInternal(
                id:=commandId,
                control:=button,
                widthDip:=resolvedWidth,
                kind:=MASToolbarItemKind.Control,
                sizing:=MASToolbarItemSizing.Fixed,
                alignment:=alignment,
                minWidthDip:=ToolbarTokens.CommandButtonMinimumWidth,
                maxWidthDip:=ToolbarTokens.CommandButtonMaximumWidth)
        End Sub

        Private Sub ConfigureCommandSplitButton(button As MASSplitButton,
                                                commandId As String,
                                                text As String,
                                                description As String,
                                                configureMenu As Action(Of MASDropDownMenuBuilder),
                                                action As Action(Of MASSplitButton),
                                                intent As MASButtonIntent)

            If button Is Nothing Then Return

            button.Text = ResolveCommandText(commandId, text)
            button.Tooltip = ResolveCommandTooltip(description, button.Text)
            button.Intent = intent
            button.WithMenu(configureMenu)

            If action IsNot Nothing Then
                button.MainCommand = action
            End If
        End Sub

        Private Sub AddSplitCommandButtonToToolbar(commandId As String,
                                                   button As MASSplitButton,
                                                   text As String,
                                                   widthDip As Single,
                                                   alignment As MASToolbarItemAlignment)

            Dim resolvedWidth As Single = If(widthDip > 0.0F,
                                             Math.Max(widthDip, ToolbarTokens.CommandButtonMinimumWidth + ButtonTokens.SplitButtonMenuWidth),
                                             Math.Min(ToolbarTokens.CommandButtonMaximumWidth + ButtonTokens.SplitButtonMenuWidth,
                                                      Math.Max(ToolbarTokens.CommandButtonMinimumWidth + ButtonTokens.SplitButtonMenuWidth,
                                                               ResolveCommandButtonWidthDip(ResolveCommandText(commandId, text), MASIconKind.None) + ButtonTokens.SplitButtonMenuWidth)))

            AddControlInternal(
                id:=commandId,
                control:=button,
                widthDip:=resolvedWidth,
                kind:=MASToolbarItemKind.Control,
                sizing:=MASToolbarItemSizing.Fixed,
                alignment:=alignment,
                minWidthDip:=ToolbarTokens.CommandButtonMinimumWidth + ButtonTokens.SplitButtonMenuWidth,
                maxWidthDip:=ToolbarTokens.CommandButtonMaximumWidth + ButtonTokens.SplitButtonMenuWidth)
        End Sub

        Private Shared Sub ApplyCommandIcon(button As MASButton,
                                            iconKind As MASIconKind)
            If button Is Nothing Then Return

            If iconKind = MASIconKind.None Then
                button.ClearIcon()
                Return
            End If

            button.WithIconPlacement(MASButtonIconPlacement.Left)
            button.WithIcon(
                Sub(canvas As SKCanvas, bounds As SKRect, dpi As Single, color As SKColor)
                    MASIconPainter.Draw(canvas, bounds, dpi, iconKind, color, MASIconStyle.Outline)
                End Sub)
        End Sub

        Private Shared Function ResolveCommandButtonWidthDip(text As String,
                                                             iconKind As MASIconKind) As Single
            Dim label As String = If(text, String.Empty).Trim()
            Dim textWidth As Single = CSng(Math.Max(0, label.Length)) * ToolbarTokens.CommandButtonAverageTextWidth
            Dim iconWidth As Single = If(iconKind = MASIconKind.None, 0.0F, ToolbarTokens.CommandButtonIconReserveWidth)
            Dim desired As Single = ToolbarTokens.CommandButtonHorizontalPadding + textWidth + iconWidth

            Return Math.Min(ToolbarTokens.CommandButtonMaximumWidth,
                            Math.Max(ToolbarTokens.CommandButtonMinimumWidth, desired))
        End Function

        Private Shared Function ResolveCommandText(commandId As String,
                                                   text As String) As String
            Dim label As String = If(text, String.Empty).Trim()
            If label.Length > 0 Then Return label
            Return NormalizeCommandBarId(commandId)
        End Function

        Private Shared Function ResolveCommandTooltip(description As String,
                                                      fallbackText As String) As String
            Dim value As String = If(description, String.Empty).Trim()
            If value.Length > 0 Then Return value
            Return If(fallbackText, String.Empty).Trim()
        End Function

        Private Shared Function NormalizeCommandBarId(value As String) As String
            Return If(value, String.Empty).Trim()
        End Function

#End Region

    End Class

End Namespace
