Option Strict On
Option Explicit On

Imports System
Imports System.Windows.Forms
Imports Nexamas.UI.General
Imports Nexamas.UI.Icons
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Controls
Imports Nexamas.UI.TextInput
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public NotInheritable Class MASSearchTextBox
        Inherits MASInputBoxSkiaBase
        Implements IMASControlRuntimeServicesConsumer

        Private Shared ReadOnly _contract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASSearchTextBox))

#Region "Ctor / Factory"

        Public Sub New()
            Me.Placeholder = MASSearchTextBoxPolicy.ResolveDefaultPlaceholder()
            InitializeAdvancedSearchBox()
        End Sub

        Public Sub New(text As String)
            Me.New()
            Me.Text = MASSearchTextBoxPolicy.NormalizeSearchText(text)
        End Sub

        Friend Shared Function [Default]() As MASSearchTextBox
            Return New MASSearchTextBox()
        End Function

        Public Shared Function Create(Optional text As String = Nothing) As MASSearchTextBox
            Return New MASSearchTextBox(MASSearchTextBoxPolicy.NormalizeSearchText(text))
        End Function

#End Region

#Region "Public Fluent API"

        Friend Overloads Sub SetBounds(x As Single,
                                       y As Single,
                                       width As Single,
                                       height As Single)
            Me.SetLocalLayoutBoundsInternal(New SKRect(x, y, x + width, y + height))
        End Sub

        Friend Function WithBounds(x As Single,
                                   y As Single,
                                   width As Single,
                                   height As Single) As MASSearchTextBox
            SetBounds(x, y, width, height)
            Return Me
        End Function

        Public Function WithText(value As String) As MASSearchTextBox
            Me.Text = MASSearchTextBoxPolicy.NormalizeSearchText(value)
            Return Me
        End Function

        Public Function WithPlaceholder(value As String) As MASSearchTextBox
            Me.Placeholder = MASSearchTextBoxPolicy.NormalizePlaceholder(value)
            Return Me
        End Function

        Public Function WithMaxLength(value As Integer) As MASSearchTextBox
            Me.MaxLength = MASSearchTextBoxPolicy.NormalizeMaxLength(value)
            Return Me
        End Function

        Public Function AsReadOnly() As MASSearchTextBox
            Me.ReadOnly = True
            Return Me
        End Function

        Public Function AsEditable() As MASSearchTextBox
            Me.ReadOnly = False
            Return Me
        End Function

        Public Function WithValidation(state As MASTextValidationState,
                                       Optional message As String = Nothing) As MASSearchTextBox
            Me.SetValidation(state, message)
            Return Me
        End Function

        Public Function WithoutValidation() As MASSearchTextBox
            Me.ClearValidation()
            Return Me
        End Function

        Public Function ShowValidation(value As Boolean) As MASSearchTextBox
            Me.ShowValidationIndicator = value
            Return Me
        End Function

        Friend Function OnTextChanged(handler As Action(Of String)) As MASSearchTextBox
            If handler Is Nothing Then Throw New ArgumentNullException(NameOf(handler))

            AddHandler Me.TextChanged,
                Sub(sender As Object, e As EventArgs)
                    handler(Me.Text)
                End Sub

            Return Me
        End Function

        Friend Function OnSearchChanged(handler As Action(Of String)) As MASSearchTextBox
            Return OnTextChanged(handler)
        End Function

        Public Function FocusInput() As MASSearchTextBox
            Me.FocusText()
            Return Me
        End Function

        Public Function SelectTextAll() As MASSearchTextBox
            Me.SelectAll()
            Return Me
        End Function

        Public Function ClearSearch() As MASSearchTextBox
            Me.Clear()
            CloseAdvancedSuggestionPopup()
            Return Me
        End Function

#End Region

#Region "Overrides"

        Protected Overrides ReadOnly Property HasLeftIcon As Boolean
            Get
                Return True
            End Get
        End Property

        Protected Overrides ReadOnly Property RightReservedWidthDip As Single
            Get
                Return 0.0F
            End Get
        End Property

        Protected Overrides ReadOnly Property InteractionKindValue As Integer
            Get
                Return CInt(CommonEnums.ControlKind.TextBox)
            End Get
        End Property

        Protected Overrides Sub DrawLeftIcon(canvas As SKCanvas,
                                             iconRect As SKRect,
                                             dpi As Single)

            If canvas Is Nothing Then Return
            If iconRect.Width <= 1.0F OrElse iconRect.Height <= 1.0F Then Return

            Dim ctx As MASThemeContext = TryGetContext()
            If ctx Is Nothing OrElse ctx.InputTheme Is Nothing Then Return

            Dim iconColor As SKColor =
                If(Me.Enabled,
                   ctx.InputTheme.Text.Placeholder.WithAlpha(210),
                   ctx.InputTheme.Text.Disabled.WithAlpha(180))

            Dim drawCtx As New MASIconDrawContext(
                canvas:=canvas,
                bounds:=GrowCentered(iconRect, 1.28F),
                dpi:=PixelSnap.SafeDpi(dpi),
                color:=iconColor,
                style:=MASIconStyle.Outline
            )

            MASIconPainter.Draw(drawCtx, MASIconKind.Search)
        End Sub

        Protected Overrides Function OnMouseDown(ctx As MASThemeContext,
                                                 ptPx As SKPoint,
                                                 button As Integer) As Boolean
            If button = CInt(MouseButtons.Left) Then
                RequestFocus()
            End If

            Dim handled As Boolean = MyBase.OnMouseDown(ctx, ptPx, button)
            If button = CInt(MouseButtons.Left) Then
                ShowAdvancedSuggestions(ctx)
            End If

            Return handled
        End Function

        Protected Overrides Function OnKeyDown(ctx As MASThemeContext,
                                               keyCode As Keys) As Boolean
            RequestFocus()

            If MASSearchTextBoxPolicy.ShouldCommitFromKey(keyCode) Then
                CommitSearch()
                Return True
            End If

            If MASSearchTextBoxPolicy.ShouldCloseSuggestionsFromKey(keyCode) Then
                CloseAdvancedSuggestionPopup()
                Return True
            End If

            If MASSearchTextBoxPolicy.ShouldOpenSuggestionsFromKey(keyCode) Then
                ShowAdvancedSuggestions(ctx)
                Return True
            End If

            Dim handled As Boolean = MyBase.OnKeyDown(ctx, keyCode)
            Return handled
        End Function

        Protected Overrides Function OnKeyUp(ctx As MASThemeContext,
                                             keyCode As Keys) As Boolean
            RequestFocus()
            Return MyBase.OnKeyUp(ctx, keyCode)
        End Function

        Protected Overrides Function OnTextInput(ctx As MASThemeContext,
                                                 text As String) As Boolean
            RequestFocus()
            Return MyBase.OnTextInput(ctx, text)
        End Function

        Protected Overrides Function FilterIncomingText(value As String) As String
            Return MASSearchTextBoxPolicy.NormalizeSearchText(value)
        End Function

        Friend Function CreateSearchTextBoxReadinessManifest() As Nexamas.UI.Components.Governance.MASSearchTextBoxReadinessManifest
            Return Nexamas.UI.Components.Governance.MASSearchTextBoxReadinessManifest.CreateCurrent()
        End Function

#End Region

#Region "Helpers"

        Private Shared Function GrowCentered(r As SKRect, scale As Single) As SKRect
            If scale <= 0.0F Then scale = 1.0F

            Dim w As Single = r.Width * scale
            Dim h As Single = r.Height * scale

            Return New SKRect(
                r.MidX - (w / 2.0F),
                r.MidY - (h / 2.0F),
                r.MidX + (w / 2.0F),
                r.MidY + (h / 2.0F)
            )
        End Function

#End Region


#Region "Unified MASSize Fluent API"

        ''' <summary>
        ''' Strongly typed entry into the shared MASSize intent API.
        ''' This method keeps fluent chains on the concrete element while delegating all sizing decisions to MASControlBase/MASSize.
        ''' </summary>
        Public Shadows Function WithSize(sizeIntent As Nexamas.UI.Layout.MASSize) As MASSearchTextBox
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region
    End Class

End Namespace
