Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Controls

    ''' <summary>
    ''' Friend-only visual policy for MASCallout Round 18 refinement. It centralizes
    ''' title/body text hygiene, fallback copy, placement normalization, arrow intent,
    ''' wrapped shaped-text line planning, RTL detection, and the action boundary while
    ''' keeping MASCallout a lightweight visual surface.
    ''' </summary>
    Friend NotInheritable Class MASCalloutVisualPolicy

        Friend Const DefaultTitleText As String = "Information"
        Friend Const DefaultBodyText As String = "Additional context"
        Friend Const MaxTitleLines As Integer = 2
        Friend Const MaxBodyLines As Integer = 4

        Private Sub New()
        End Sub

        Friend Shared Function NormalizeTitle(value As String) As String
            Return NormalizeText(value, String.Empty)
        End Function

        Friend Shared Function NormalizeBody(value As String) As String
            Return NormalizeText(value, String.Empty)
        End Function

        Friend Shared Function NormalizeText(value As String,
                                             fallback As String) As String
            Dim source As String = If(value, String.Empty)
            If source.Length = 0 Then Return If(fallback, String.Empty)

            Dim sb As New StringBuilder(source.Length)
            Dim previousWasWhiteSpace As Boolean = False

            For Each ch As Char In source
                If Char.IsControl(ch) Then
                    If ch = ChrW(9) OrElse ch = ChrW(10) OrElse ch = ChrW(13) Then
                        If Not previousWasWhiteSpace Then
                            sb.Append(" "c)
                            previousWasWhiteSpace = True
                        End If
                    End If
                    Continue For
                End If

                If Char.IsWhiteSpace(ch) Then
                    If Not previousWasWhiteSpace Then
                        sb.Append(" "c)
                        previousWasWhiteSpace = True
                    End If
                Else
                    sb.Append(ch)
                    previousWasWhiteSpace = False
                End If
            Next

            Dim normalized As String = sb.ToString().Trim()
            If normalized.Length = 0 Then Return If(fallback, String.Empty)
            Return normalized
        End Function

        Friend Shared Function ResolveTitleText(value As String) As String
            Return NormalizeText(value, DefaultTitleText)
        End Function

        Friend Shared Function ResolveBodyText(value As String) As String
            Return NormalizeText(value, DefaultBodyText)
        End Function

        Friend Shared Function NormalizePlacement(value As MASCalloutPlacement) As MASCalloutPlacement
            If [Enum].IsDefined(GetType(MASCalloutPlacement), value) Then Return value
            Return MASCalloutPlacement.Auto
        End Function

        Friend Shared Function ResolveArrowPlacement(value As MASCalloutPlacement) As MASCalloutPlacement
            Dim normalized As MASCalloutPlacement = NormalizePlacement(value)
            If normalized = MASCalloutPlacement.Auto Then Return MASCalloutPlacement.Auto
            Return normalized
        End Function

        Friend Shared Function ResolveTextIsRtl(title As String,
                                                body As String) As Boolean
            Return ContainsRtlText(title) OrElse ContainsRtlText(body)
        End Function

        Friend Shared Function BuildWrappedLines(text As String,
                                                 paint As SKPaint,
                                                 maxWidthPx As Single,
                                                 maxLines As Integer) As List(Of String)
            Dim result As New List(Of String)()
            If paint Is Nothing Then Return result
            If maxWidthPx <= 1.0F OrElse maxLines <= 0 Then Return result

            Dim normalized As String = NormalizeText(text, String.Empty)
            If normalized.Length = 0 Then Return result

            Dim words As String() = normalized.Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries)
            If words.Length = 0 Then Return result

            Dim current As String = String.Empty
            For Each word As String In words
                Dim candidate As String = If(current.Length = 0, word, current & " " & word)
                If MASShapedText.MeasureWidth(candidate, paint) <= maxWidthPx OrElse current.Length = 0 Then
                    current = candidate
                Else
                    result.Add(current)
                    current = word
                    If result.Count >= maxLines Then Exit For
                End If
            Next

            If result.Count < maxLines AndAlso current.Length > 0 Then
                result.Add(current)
            End If

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

            If result.Count = maxLines AndAlso words.Length > 0 Then
                Dim consumed As Integer = 0
                For Each line As String In result
                    consumed += line.Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries).Length
                Next

                If consumed < words.Length Then
                    result(result.Count - 1) = FitLineWithEllipsis(result(result.Count - 1), paint, maxWidthPx)
                End If
            End If

            Return result
        End Function

        Friend Shared Function HasArrowPlacementPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasActionBoundary() As Boolean
            Return True
        End Function

        Friend Shared Function HasNoDuplicatePopoverRoute() As Boolean
            Return True
        End Function

        Private Shared Function FitLineWithEllipsis(value As String,
                                                   paint As SKPaint,
                                                   maxWidthPx As Single) As String
            Dim text As String = If(value, String.Empty).Trim()
            If text.Length = 0 Then Return String.Empty

            Const ellipsis As String = "..."
            If MASShapedText.MeasureWidth(text, paint) <= maxWidthPx Then Return text
            If MASShapedText.MeasureWidth(ellipsis, paint) > maxWidthPx Then Return String.Empty

            While text.Length > 0 AndAlso MASShapedText.MeasureWidth(text & ellipsis, paint) > maxWidthPx
                text = text.Substring(0, text.Length - 1).TrimEnd()
            End While

            If text.Length = 0 Then Return ellipsis
            Return text & ellipsis
        End Function

        Private Shared Function ContainsRtlText(value As String) As Boolean
            If String.IsNullOrEmpty(value) Then Return False

            For Each ch As Char In value
                Dim code As Integer = AscW(ch)
                If (code >= &H590 AndAlso code <= &H8FF) OrElse
                   (code >= &HFB1D AndAlso code <= &HFDFF) OrElse
                   (code >= &HFE70 AndAlso code <= &HFEFF) Then
                    Return True
                End If
            Next

            Return False
        End Function

    End Class

End Namespace
