Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Composition
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.RuntimeEnvironment
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Controls

    ''' <summary>
    ''' Public MAS-prefixed label text role contract used by MASLabel theme color resolution.
    ''' </summary>
    Public Enum MASLabelTextRole
        Primary = 0
        Secondary = 1
        Muted = 2
        Disabled = 3
        Inverse = 4
        OnBrandPrimary = 5
        OnBrandPrimaryStrong = 6
    End Enum

    Public Enum MASHorizontalAlignment
        Left = 0
        Center = 1
        Right = 2
    End Enum

    Public Enum MASVerticalAlignment
        Top = 0
        Center = 1
        Bottom = 2
    End Enum

    Public Enum MASLabelVariant
        Title = 0
        Heading = 1
        Subtitle = 2
        Body = 3
        Caption = 4
        Micro = 5
        Button = 6
        TopBarTitle = 7
    End Enum

    Partial Public NotInheritable Class MASLabel
        Inherits MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract

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

        Private Shared ReadOnly _typefaceLock As New Object()
        Private Shared ReadOnly _typefaceCache As New Dictionary(Of Integer, SKTypeface)()
        Private _text As String = String.Empty
        Private _labelVariant As MASLabelVariant = MASLabelVariant.Body
        Private _textStyle As MASTypography.MASTextStyle = MASTypography.MASTextStyle.Body
        Private _textRole As MASLabelTextRole = MASLabelTextRole.Primary

        Private _horizontalAlignment As MASHorizontalAlignment = MASHorizontalAlignment.Left
        Private _verticalAlignment As MASVerticalAlignment = MASVerticalAlignment.Center

        Private _paddingLeft As Single = 0.0F
        Private _paddingTop As Single = 0.0F
        Private _paddingRight As Single = 0.0F
        Private _paddingBottom As Single = 0.0F

        Private _multiLine As Boolean = False
        Private _wordWrap As Boolean = True
        Private _maxLines As Integer = 0
        Private _lineHeightMultiplier As Single = MASTypography.WrapLineHeightMul

        Private _hasTextColor As Boolean = False
        Private _textColor As SKColor = SKColors.Transparent

        Private _fontSizeDip As Single = 0.0F
        Private _fontWeight As Integer = 0

        Private _singleLineLayoutValid As Boolean
        Private _singleLineLayoutText As String = Nothing
        Private _singleLineLayoutWidthPx As Single
        Private _singleLineLayoutThemeStamp As Integer
        Private _singleLineLayoutDpi As Single
        Private _singleLineLayoutTextStyle As MASTypography.MASTextStyle
        Private _singleLineLayoutFontSizeDip As Single
        Private _singleLineLayoutFontWeight As Integer
        Private _singleLineLayoutFittedText As String = String.Empty
        Private _singleLineLayoutTextWidthPx As Single
        Private _singleLineLayoutEnvironmentStamp As MASRuntimeEnvironmentStamp

        Private _multiLineLayoutValid As Boolean
        Private _multiLineLayoutText As String = Nothing
        Private _multiLineLayoutWidthPx As Single
        Private _multiLineLayoutThemeStamp As Integer
        Private _multiLineLayoutDpi As Single
        Private _multiLineLayoutTextStyle As MASTypography.MASTextStyle
        Private _multiLineLayoutFontSizeDip As Single
        Private _multiLineLayoutFontWeight As Integer
        Private _multiLineLayoutWordWrap As Boolean
        Private _multiLineLayoutMaxLines As Integer
        Private _multiLineLayoutLineHeightMultiplier As Single
        Private _multiLineLayoutLines As String()
        Private _multiLineLayoutWidthsPx As Single()
        Private _multiLineLayoutLineHeightPx As Single
        Private _multiLineLayoutTotalHeightPx As Single
        Private _multiLineLayoutAscentPx As Single
        Private _multiLineLayoutDescentPx As Single
        Private _multiLineLayoutEnvironmentStamp As MASRuntimeEnvironmentStamp

        Public Sub New()
            MyBase.New()
        End Sub

        Public Sub New(text As String)
            MyBase.New()
            _text = MASLabelTypographyPolicy.NormalizeLabelText(text)
        End Sub

#Region "Factories"

        ''' <summary>
        ''' Creates a new MAS label using the standard SDK entry pattern.
        ''' </summary>
        Public Shared Function Create(Optional text As String = Nothing) As MASLabel
            Return New MASLabel(text)
        End Function

#End Region

        Public Property [Text] As String
            Get
                Return _text
            End Get
            Set(value As String)
                Dim nextText As String = MASLabelTypographyPolicy.NormalizeLabelText(value)
                If String.Equals(_text, nextText, StringComparison.Ordinal) Then Return

                _text = nextText
                RaiseTextChanged()
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property LabelVariant As MASLabelVariant
            Get
                Return _labelVariant
            End Get
            Set(value As MASLabelVariant)
                Dim nextValue As MASLabelVariant = MASLabelTypographyPolicy.NormalizeVariant(value)
                If _labelVariant = nextValue Then Return

                _labelVariant = nextValue
                _textStyle = MASLabelTypographyPolicy.ResolveTextStyleFromVariant(nextValue)
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property TextStyle As MASTypography.MASTextStyle
            Get
                Return _textStyle
            End Get
            Set(value As MASTypography.MASTextStyle)
                If _textStyle = value Then Return

                _textStyle = value
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property TextRole As MASLabelTextRole
            Get
                Return _textRole
            End Get
            Set(value As MASLabelTextRole)
                Dim nextValue As MASLabelTextRole = MASLabelTypographyPolicy.NormalizeTextRole(value)
                If _textRole = nextValue Then Return

                _textRole = nextValue
                InvalidateVisual()
            End Set
        End Property

        <Obsolete("Use HorizontalAlignment instead. TextAlign is a compatibility alias and no longer exposes TypographyTextPrimitives.", False)>
        Friend Property TextAlign As MASHorizontalAlignment
            Get
                Return _horizontalAlignment
            End Get
            Set(value As MASHorizontalAlignment)
                HorizontalAlignment = value
            End Set
        End Property

        Public Property HorizontalAlignment As MASHorizontalAlignment
            Get
                Return _horizontalAlignment
            End Get
            Set(value As MASHorizontalAlignment)
                Dim nextValue As MASHorizontalAlignment = MASLabelTypographyPolicy.NormalizeHorizontalAlignment(value)
                If _horizontalAlignment = nextValue Then Return

                _horizontalAlignment = nextValue
                InvalidateVisual()
            End Set
        End Property

        Public Property VerticalAlignment As MASVerticalAlignment
            Get
                Return _verticalAlignment
            End Get
            Set(value As MASVerticalAlignment)
                Dim nextValue As MASVerticalAlignment = MASLabelTypographyPolicy.NormalizeVerticalAlignment(value)
                If _verticalAlignment = nextValue Then Return

                _verticalAlignment = nextValue
                InvalidateVisual()
            End Set
        End Property

        Public Property MultiLine As Boolean
            Get
                Return _multiLine
            End Get
            Set(value As Boolean)
                If _multiLine = value Then Return

                _multiLine = value
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property WordWrap As Boolean
            Get
                Return _wordWrap
            End Get
            Set(value As Boolean)
                If _wordWrap = value Then Return

                _wordWrap = value
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property MaxLines As Integer
            Get
                Return _maxLines
            End Get
            Set(value As Integer)
                Dim nextValue As Integer = MASLabelTypographyPolicy.NormalizeMaxLines(value)
                If _maxLines = nextValue Then Return

                _maxLines = nextValue
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property LineHeightMultiplier As Single
            Get
                Return _lineHeightMultiplier
            End Get
            Set(value As Single)
                Dim nextValue As Single = MASLabelTypographyPolicy.NormalizeLineHeightMultiplier(value)

                If NearlyEqual(_lineHeightMultiplier, nextValue) Then Return

                _lineHeightMultiplier = nextValue
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property FontSize As Single
            Get
                Return _fontSizeDip
            End Get
            Set(value As Single)
                Dim nextValue As Single = MASLabelTypographyPolicy.NormalizeFontSize(value)

                If NearlyEqual(_fontSizeDip, nextValue) Then Return

                _fontSizeDip = nextValue
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property FontWeight As Integer
            Get
                Return _fontWeight
            End Get
            Set(value As Integer)
                Dim nextValue As Integer = MASLabelTypographyPolicy.NormalizeFontWeight(value)
                If _fontWeight = nextValue Then Return

                _fontWeight = nextValue
                InvalidateTypographyLayoutCache()
            End Set
        End Property

        Public Property TextColor As SKColor
            Get
                Return _textColor
            End Get
            Set(value As SKColor)
                If _hasTextColor AndAlso _textColor.Equals(value) Then Return

                _textColor = value
                _hasTextColor = True
                InvalidateVisual()
            End Set
        End Property

        Public ReadOnly Property HasTextColor As Boolean
            Get
                Return _hasTextColor
            End Get
        End Property

        Public Sub ClearTextColor()
            If Not _hasTextColor Then Return

            _hasTextColor = False
            _textColor = SKColors.Transparent
            InvalidateVisual()
        End Sub

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Property PaddingLeft As Single
            Get
                Return _paddingLeft
            End Get
            Set(value As Single)
                SetPaddingCore(SafeNonNegative(value), _paddingTop, _paddingRight, _paddingBottom)
            End Set
        End Property

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Property PaddingTop As Single
            Get
                Return _paddingTop
            End Get
            Set(value As Single)
                SetPaddingCore(_paddingLeft, SafeNonNegative(value), _paddingRight, _paddingBottom)
            End Set
        End Property

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Property PaddingRight As Single
            Get
                Return _paddingRight
            End Get
            Set(value As Single)
                SetPaddingCore(_paddingLeft, _paddingTop, SafeNonNegative(value), _paddingBottom)
            End Set
        End Property

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Property PaddingBottom As Single
            Get
                Return _paddingBottom
            End Get
            Set(value As Single)
                SetPaddingCore(_paddingLeft, _paddingTop, _paddingRight, SafeNonNegative(value))
            End Set
        End Property

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Sub SetPadding(all As Single)
            Dim value As Single = SafeNonNegative(all)
            SetPaddingCore(value, value, value, value)
        End Sub

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Sub SetPadding(horizontal As Single, vertical As Single)
            Dim h As Single = SafeNonNegative(horizontal)
            Dim v As Single = SafeNonNegative(vertical)
            SetPaddingCore(h, v, h, v)
        End Sub

        <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
        Friend Sub SetPadding(left As Single, top As Single, right As Single, bottom As Single)
            SetPaddingCore(
                SafeNonNegative(left),
                SafeNonNegative(top),
                SafeNonNegative(right),
                SafeNonNegative(bottom))
        End Sub

        Friend Sub SetBounds(bounds As SKRect)
            SetBounds(bounds.Left, bounds.Top, bounds.Width, bounds.Height)
        End Sub

        Friend Sub SetBounds(x As Single,
                             y As Single,
                             width As Single,
                             height As Single)

             SetLocalLayoutBoundsInternal(New SKRect(
                x,
                y,
                x + Math.Max(0.0F, width),
                y + Math.Max(0.0F, height)
            ))
        End Sub

        Friend Function WithBounds(bounds As SKRect) As MASLabel
            SetBounds(bounds)
            Return Me
        End Function

        Friend Function WithBounds(x As Single,
                                   y As Single,
                                   width As Single,
                                   height As Single) As MASLabel

            SetBounds(x, y, width, height)
            Return Me
        End Function

        Public Function WithText(value As String) As MASLabel
            Text = value
            Return Me
        End Function


#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 MASLabel
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region
    End Class

End Namespace
