Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Controls

    Friend NotInheritable Class MASLabelTypographyPolicy
        Private Sub New()
        End Sub

        Friend Shared Function NormalizeLabelText(value As String) As String
            Dim source As String = If(value, String.Empty).Replace(vbCrLf, vbLf).Replace(vbCr, vbLf)
            If source.Length = 0 Then Return String.Empty

            Dim builder As New StringBuilder(source.Length)

            For Each ch As Char In source
                If ch = ControlChars.Lf OrElse ch = ControlChars.Tab Then
                    builder.Append(ch)
                ElseIf Char.IsControl(ch) Then
                    builder.Append(" "c)
                Else
                    builder.Append(ch)
                End If
            Next

            Return builder.ToString()
        End Function

        Friend Shared Function ResolveRenderableText(value As String, allowMultiline As Boolean) As String
            Dim normalized As String = NormalizeLabelText(value)
            If allowMultiline Then Return normalized
            If normalized.Length = 0 Then Return String.Empty

            normalized = normalized.Replace(ControlChars.Lf, " "c).Replace(ControlChars.Tab, " "c)

            While normalized.Contains("  ")
                normalized = normalized.Replace("  ", " ")
            End While

            Return normalized.Trim()
        End Function

        Friend Shared Function NormalizeVariant(value As MASLabelVariant) As MASLabelVariant
            If [Enum].IsDefined(GetType(MASLabelVariant), value) Then Return value
            Return MASLabelVariant.Body
        End Function

        Friend Shared Function NormalizeTextRole(value As MASLabelTextRole) As MASLabelTextRole
            If [Enum].IsDefined(GetType(MASLabelTextRole), value) Then Return value
            Return MASLabelTextRole.Primary
        End Function

        Friend Shared Function NormalizeHorizontalAlignment(value As MASHorizontalAlignment) As MASHorizontalAlignment
            If [Enum].IsDefined(GetType(MASHorizontalAlignment), value) Then Return value
            Return MASHorizontalAlignment.Left
        End Function

        Friend Shared Function NormalizeVerticalAlignment(value As MASVerticalAlignment) As MASVerticalAlignment
            If [Enum].IsDefined(GetType(MASVerticalAlignment), value) Then Return value
            Return MASVerticalAlignment.Center
        End Function

        Friend Shared Function NormalizeMaxLines(value As Integer) As Integer
            Return Math.Max(0, value)
        End Function

        Friend Shared Function NormalizeFontSize(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value < 0.0F Then Return 0.0F
            Return Math.Min(96.0F, value)
        End Function

        Friend Shared Function NormalizeFontWeight(value As Integer) As Integer
            If value <= 0 Then Return 0
            Return Math.Min(900, Math.Max(100, value))
        End Function

        Friend Shared Function NormalizeLineHeightMultiplier(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value <= 0.0F Then Return MASTypography.WrapLineHeightMul
            Return Math.Max(0.9F, Math.Min(2.5F, value))
        End Function

        Friend Shared Function ResolveTextStyleFromVariant(value As MASLabelVariant) As MASTypography.MASTextStyle
            Select Case NormalizeVariant(value)
                Case MASLabelVariant.Title
                    Return MASTypography.MASTextStyle.Title
                Case MASLabelVariant.Heading
                    Return MASTypography.MASTextStyle.Title
                Case MASLabelVariant.Subtitle
                    Return MASTypography.MASTextStyle.Body
                Case MASLabelVariant.Body
                    Return MASTypography.MASTextStyle.Body
                Case MASLabelVariant.Caption
                    Return MASTypography.MASTextStyle.Small
                Case MASLabelVariant.Micro
                    Return MASTypography.MASTextStyle.Micro
                Case MASLabelVariant.Button
                    Return MASTypography.MASTextStyle.Button
                Case MASLabelVariant.TopBarTitle
                    Return MASTypography.MASTextStyle.TopBarTitle
                Case Else
                    Return MASTypography.MASTextStyle.Body
            End Select
        End Function

        Friend Shared Function ResolveEffectiveHorizontalAlignment(value As MASHorizontalAlignment,
                                                                  text As String,
                                                                  ctx As MASThemeContext) As MASHorizontalAlignment
            Dim normalized As MASHorizontalAlignment = NormalizeHorizontalAlignment(value)
            If normalized = MASHorizontalAlignment.Center Then Return normalized

            Dim isRtl As Boolean = MASShapedText.IsRtl(If(text, String.Empty))
            If Not isRtl Then Return normalized

            If normalized = MASHorizontalAlignment.Left Then Return MASHorizontalAlignment.Right
            If normalized = MASHorizontalAlignment.Right Then Return MASHorizontalAlignment.Left
            Return normalized
        End Function

        Friend Shared Function ResolveTextColor(enabled As Boolean,
                                                role As MASLabelTextRole,
                                                hasExplicitColor As Boolean,
                                                explicitColor As SKColor,
                                                ctx As MASThemeContext) As SKColor
            If hasExplicitColor Then Return explicitColor
            If ctx Is Nothing OrElse ctx.TextColorTheme Is Nothing Then Return SKColors.Black

            Dim theme As IMASTextColorTheme = ctx.TextColorTheme
            If Not enabled Then Return theme.DisabledText

            Select Case NormalizeTextRole(role)
                Case MASLabelTextRole.Primary
                    Return theme.PrimaryText
                Case MASLabelTextRole.Secondary
                    Return theme.SecondaryText
                Case MASLabelTextRole.Muted
                    Return theme.MutedText
                Case MASLabelTextRole.Disabled
                    Return theme.DisabledText
                Case MASLabelTextRole.Inverse
                    Return theme.InverseText
                Case MASLabelTextRole.OnBrandPrimary
                    Return theme.OnBrandPrimaryText
                Case MASLabelTextRole.OnBrandPrimaryStrong
                    Return theme.OnBrandPrimaryStrongText
                Case Else
                    Return theme.PrimaryText
            End Select
        End Function

        Friend Shared Function BuildWrappedLines(text As String,
                                                 paint As SKPaint,
                                                 maxWidth As Single,
                                                 wordWrap As Boolean,
                                                 maxLines As Integer) As List(Of String)
            Dim result As New List(Of String)()
            Dim source As String = ResolveRenderableText(text, allowMultiline:=True)

            If source.Length = 0 OrElse paint Is Nothing OrElse maxWidth <= 1.0F Then Return result

            Dim limit As Integer = If(maxLines <= 0, Integer.MaxValue, maxLines)

            If Not wordWrap Then
                Dim paragraphs() As String = source.Split(ControlChars.Lf)
                For Each paragraph As String In paragraphs
                    If result.Count >= limit Then Exit For
                    result.Add(MASTextCore.FitEllipsis(paragraph.TrimEnd(), maxWidth, paint))
                Next
                ApplyFinalEllipsisIfNeeded(result, maxWidth, paint, maxLines)
                Return result
            End If

            Dim sourceParagraphs() As String = source.Split(ControlChars.Lf)

            For Each paragraph As String In sourceParagraphs
                If result.Count >= limit Then Exit For

                If paragraph.Length = 0 Then
                    result.Add(String.Empty)
                    Continue For
                End If

                Dim words() As String = paragraph.Split(New Char() {" "c, ControlChars.Tab}, StringSplitOptions.RemoveEmptyEntries)
                Dim current As String = String.Empty

                For i As Integer = 0 To words.Length - 1
                    If result.Count >= limit Then Exit For

                    Dim word As String = words(i)
                    Dim candidate As String = If(current.Length = 0, word, current & " " & word)

                    If MASShapedText.MeasureWidth(candidate, paint) <= maxWidth Then
                        current = candidate
                    Else
                        If current.Length > 0 Then
                            result.Add(current)
                            current = String.Empty
                        End If

                        If result.Count >= limit Then Exit For

                        If MASShapedText.MeasureWidth(word, paint) > maxWidth Then
                            result.Add(MASTextCore.FitEllipsis(word, maxWidth, paint))
                        Else
                            current = word
                        End If
                    End If
                Next

                If result.Count >= limit Then Exit For
                If current.Length > 0 Then result.Add(current)
            Next

            ApplyFinalEllipsisIfNeeded(result, maxWidth, paint, maxLines)
            Return result
        End Function

        Friend Shared Function ResolveBaseline(bounds As SKRect,
                                               paint As SKPaint,
                                               verticalAlignment As MASVerticalAlignment) As Single
            If paint Is Nothing Then Return bounds.MidY

            Dim fm As SKFontMetrics = paint.FontMetrics

            Select Case NormalizeVerticalAlignment(verticalAlignment)
                Case MASVerticalAlignment.Top
                    Return bounds.Top - fm.Ascent
                Case MASVerticalAlignment.Bottom
                    Return bounds.Bottom - fm.Descent
                Case Else
                    Return bounds.MidY - ((fm.Ascent + fm.Descent) * 0.5F)
            End Select
        End Function

        Private Shared Sub ApplyFinalEllipsisIfNeeded(lines As List(Of String),
                                                      maxWidth As Single,
                                                      paint As SKPaint,
                                                      maxLines As Integer)
            If lines Is Nothing OrElse lines.Count = 0 Then Return
            If maxLines <= 0 Then Return

            If lines.Count > maxLines Then
                lines.RemoveRange(maxLines, lines.Count - maxLines)
            End If

            If lines.Count = maxLines Then
                lines(lines.Count - 1) = MASTextCore.FitEllipsis(lines(lines.Count - 1), maxWidth, paint)
            End If
        End Sub
    End Class

End Namespace
