Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Composition
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp
Imports Nexamas.UI.Architecture

Namespace Nexamas.UI.Components

    Friend NotInheritable Class MASPathDisplayBox
        Inherits MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract


        Private Shared ReadOnly _contract As MASResolvedComponentContract =
    MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASPathDisplayBox))
#Region "Fields"

        Private _text As String = String.Empty

#End Region

#Region "Factories"

        Friend Shared Function Create(Optional text As String = Nothing) As MASPathDisplayBox
            Dim box As New MASPathDisplayBox()

            If text IsNot Nothing Then
                box.Text = text
            End If

            Return box
        End Function

#End Region

#Region "Public API"

        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 MASPathDisplayBox
            SetBounds(bounds)
            Return Me
        End Function

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

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

        Friend Function WithText(value As String) As MASPathDisplayBox
            Text = value
            Return Me
        End Function


        Friend Property Text As String
            Get
                Return _text
            End Get
            Set(value As String)
                Dim v As String = If(value, String.Empty)

                If String.Equals(_text, v, StringComparison.Ordinal) Then Return

                _text = v
                InvalidateVisual()
            End Set
        End Property

#Region "Size/Layout Contract"

        Friend Function GetPreferredLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetPreferredLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).DesiredSize
        End Function

        Friend Function GetMinLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetMinLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).MinSize
        End Function

        Friend Function MeasureIntrinsicSize(context As MASSizeContext, intent As MASSize) As MASSizeResult Implements IMASIntrinsicSizeContract.MeasureIntrinsicSize
            Dim safeContext As MASSizeContext = MASIntrinsicControlSizeMetrics.EnsureContext(context)
            Dim shown As String = If(String.IsNullOrWhiteSpace(_text), ToolbarTokens.PathDisplayFallbackText, _text)
            Dim textSize As SKSize = MASLayoutTextMeasureGateway.Measure(safeContext.IntegrationContext, shown, MASTypography.MASTextStyle.Small, Single.PositiveInfinity, allowWrap:=False).Size
            Dim desired As SKSize = MASIntrinsicControlSizeMetrics.ResolvePathDisplayDesiredSize(textSize)
            Return MASSizeResolver.FromMeasured(
                desired,
                MASIntrinsicControlSizeMetrics.ResolvePathDisplayMinimumSize(),
                MASIntrinsicControlSizeMetrics.ResolvePathDisplayMaximumSize(),
                intent,
                safeContext,
                True,
                False,
                MASIntrinsicControlSizeMetrics.CreatePathDisplayContentInset(),
                MASIntrinsicControlSizeMetrics.CreatePathDisplayVisualOverflowInset(),
                MASLayoutInset.Empty,
                False)
        End Function

        Private Shared Function CreateSizeContext(context As MASLayoutMeasureContext) As MASSizeContext
            If context Is Nothing Then Return MASIntrinsicControlSizeMetrics.EnsureContext(Nothing)
            Return context.ToSizeContext()
        End Function

#End Region
#End Region

#Region "Render"

        Protected Overrides Sub Render(canvas As SKCanvas,
                                       ctx As MASThemeContext,
                                       pixelBounds As SKRect)

            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If pixelBounds.Width <= ToolbarTokens.MinimumUsablePixelSize OrElse pixelBounds.Height <= ToolbarTokens.MinimumUsablePixelSize Then Return

            Dim dpi As Single = PixelSnap.SafeDpi(ctx.Dpi)
            Dim r As SKRect = PixelSnap.SnapRectHalf(pixelBounds)

            DrawBackground(canvas, ctx, r, dpi)
            DrawText(canvas, ctx, r, dpi)
        End Sub

        Private Sub DrawBackground(canvas As SKCanvas,
                                   ctx As MASThemeContext,
                                   r As SKRect,
                                   dpi As Single)

            Dim radius As Single = ToolbarTokens.PathDisplayRadius * dpi

            Using bg As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Fill,
                .Color = ctx.TextColorTheme.MutedText.WithAlpha(ToolbarTokens.PathDisplayBackgroundAlpha)
            }
                canvas.DrawRoundRect(r, radius, radius, bg)
            End Using

            Using border As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = ToolbarTokens.PathDisplayStrokeWidth,
                .Color = ctx.TextColorTheme.MutedText.WithAlpha(ToolbarTokens.PathDisplayBorderAlpha)
            }
                canvas.DrawRoundRect(r, radius, radius, border)
            End Using
        End Sub

        Private Sub DrawText(canvas As SKCanvas,
                             ctx As MASThemeContext,
                             r As SKRect,
                             dpi As Single)

            Dim shown As String = If(String.IsNullOrWhiteSpace(_text), ToolbarTokens.PathDisplayFallbackText, _text)

            Dim inner As New SKRect(
                r.Left + ToolbarTokens.PathDisplayContentInsetX * dpi,
                r.Top,
                r.Right - ToolbarTokens.PathDisplayContentInsetX * dpi,
                r.Bottom
            )

            If inner.Width <= ToolbarTokens.MinimumUsablePixelSize OrElse inner.Height <= ToolbarTokens.MinimumUsablePixelSize Then Return

            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .SubpixelText = True,
                .LcdRenderText = True,
                .Color = ctx.TextColorTheme.PrimaryText.WithAlpha(ToolbarTokens.PathDisplayTextAlpha),
                .TextSize = ToolbarTokens.PathDisplayTextSize * dpi,
                .Typeface = SKTypeface.FromFamilyName("Segoe UI")
            }

                If p.Typeface Is Nothing Then
                    p.Typeface = SKTypeface.Default
                End If

                Dim fitted As String = FitTextEndEllipsis(shown, p, inner.Width)

                Dim fm As SKFontMetrics = p.FontMetrics
                Dim baselineY As Single = inner.MidY - ((fm.Ascent + fm.Descent) * 0.5F)
                baselineY = CSng(Math.Round(baselineY * 2.0F, MidpointRounding.AwayFromZero) / 2.0F)

                MASShapedText.DrawLeftToRight(
    canvas:=canvas,
    text:=fitted,
    x:=inner.Left,
    baselineY:=baselineY,
    paint:=p
)
            End Using
        End Sub

#End Region

#Region "Routing"

        Protected Overrides Function ExcludeFromPointerRouting() As Boolean
            Return True
        End Function

#End Region

#Region "Helpers"

        Private Shared Function FitTextEndEllipsis(text As String,
                                                   paint As SKPaint,
                                                   maxWidth As Single) As String

            If String.IsNullOrEmpty(text) Then Return String.Empty
            If paint Is Nothing Then Return text
            If maxWidth <= ToolbarTokens.MinimumUsablePixelSize Then Return String.Empty

            If MASShapedText.MeasureWidth(text, paint) <= maxWidth Then
                Return text
            End If

            Const ellipsis As String = "..."

            If MASShapedText.MeasureWidth(ellipsis, paint) > maxWidth Then
                Return String.Empty
            End If

            Dim lo As Integer = 0
            Dim hi As Integer = text.Length

            While lo < hi
                Dim mid As Integer = (lo + hi + 1) \ 2
                Dim candidate As String = ellipsis & text.Substring(text.Length - mid)

                If MASShapedText.MeasureWidth(candidate, paint) <= maxWidth Then
                    lo = mid
                Else
                    hi = mid - 1
                End If
            End While

            If lo <= 0 Then Return ellipsis

            Return ellipsis & text.Substring(text.Length - lo)
        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>
        Friend Shadows Function WithSize(sizeIntent As Nexamas.UI.Layout.MASSize) As MASPathDisplayBox
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region
    End Class

End Namespace
