Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.General
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Friend NotInheritable Class RadioButtonLayoutHelper

        Private Sub New()
        End Sub

        Friend Structure LayoutInfo
            Friend Host As SKRect
            Friend BulletRect As SKRect
            Friend TextRect As SKRect
            Friend InteractiveRect As SKRect
        End Structure

        Friend Shared Function BuildLayout(ctx As MASThemeContext,
                                           boundsPx As SKRect,
                                           text As String) As LayoutInfo

            Dim dpi As Single = ResolveDpi(ctx)

            Dim lo As New LayoutInfo With {
                .Host = boundsPx,
                .BulletRect = SKRect.Empty,
                .TextRect = SKRect.Empty,
                .InteractiveRect = SKRect.Empty
            }

            If boundsPx.Width <= 0 OrElse boundsPx.Height <= 0 Then
                Return lo
            End If

            Dim outerSize As Single = RadioButtonTokens.OuterSize * dpi
            Dim gap As Single = RadioButtonTokens.LabelGap * dpi
            Dim textPadR As Single = RadioButtonTokens.TextPadRight * dpi
            Dim hitPadAfterText As Single = Math.Max(RadioButtonTokens.HitPadAfterText * dpi, textPadR)

            Dim bulletTop As Single = boundsPx.MidY - (outerSize * 0.5F)

            Dim bulletRect As New SKRect(
                boundsPx.Left,
                bulletTop,
                boundsPx.Left + outerSize,
                bulletTop + outerSize
            )

            bulletRect = PixelSnap.SnapRectHalf(bulletRect)

            Dim hasText As Boolean = Not String.IsNullOrWhiteSpace(text)
            Dim textLeft As Single = bulletRect.Right + If(hasText, gap, 0.0F)
            Dim measuredTextWidth As Single = If(hasText, MeasureTextWidthPx(ctx, text, dpi), 0.0F)

            Dim textRight As Single
            If hasText Then
                textRight = Math.Min(textLeft + measuredTextWidth + textPadR, boundsPx.Right)
            Else
                textRight = textLeft
            End If

            Dim textRect As New SKRect(
                textLeft,
                boundsPx.Top,
                Math.Max(textLeft, textRight),
                boundsPx.Bottom
            )

            Dim interactiveRight As Single
            If hasText Then
                interactiveRight = textLeft + measuredTextWidth + hitPadAfterText
            Else
                interactiveRight = bulletRect.Right
            End If

            interactiveRight = Math.Min(interactiveRight, boundsPx.Right)

            Dim interactiveRect As New SKRect(
                boundsPx.Left,
                boundsPx.Top,
                Math.Max(boundsPx.Left, interactiveRight),
                boundsPx.Bottom
            )

            lo.BulletRect = bulletRect
            lo.TextRect = textRect
            lo.InteractiveRect = interactiveRect

            Return lo
        End Function

        Private Shared Function MeasureTextWidthPx(ctx As MASThemeContext,
                                                   text As String,
                                                   dpi As Single) As Single
            If String.IsNullOrEmpty(text) Then Return 0.0F

            If ctx IsNot Nothing AndAlso ctx.Typography IsNot Nothing Then
                Using p As SKPaint = ctx.Typography.CreatePaint(MASTypography.MASTextStyle.Body, SKColors.Black)
                    If p IsNot Nothing Then
                        PrepareMeasurementPaint(p)
                        Return Math.Max(0.0F, MASShapedText.MeasureWidth(text, p))
                    End If
                End Using
            End If

            Return CSng(text.Length) * RadioButtonTokens.FallbackCharacterWidth * dpi
        End Function

        Private Shared Sub PrepareMeasurementPaint(paint As SKPaint)
            If paint Is Nothing Then Return

            paint.IsAntialias = True
            paint.IsDither = True
        End Sub

        Private Shared Function ResolveDpi(ctx As MASThemeContext) As Single
            If ctx Is Nothing Then Return 1.0F
            Return PixelSnap.SafeDpi(ctx.Dpi)
        End Function

    End Class

End Namespace