Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Windows.Forms
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-owned policy for MASRating. It centralizes value normalization,
    ''' half-step rounding, bounded maximums, RTL math, and explicit architecture
    ''' boundaries so the control does not become a review store, analytics pipe,
    ''' feedback service, persistence layer, recommendation model, or moderation path.
    ''' </summary>
    Friend NotInheritable Class MASRatingPolicy
        Private Sub New()
        End Sub

        Friend Shared Function NormalizeLabel(value As String) As String
            Dim text As String = If(value, String.Empty).Trim()
            If text.Length = 0 Then Return RatingTokens.DefaultLabel
            Return text
        End Function

        Friend Shared Function NormalizeMaximum(value As Integer) As Integer
            If value < 1 Then Return 1
            If value > RatingTokens.MaxRatingItems Then Return RatingTokens.MaxRatingItems
            Return value
        End Function

        Friend Shared Function NormalizeValue(value As Double,
                                              maximum As Integer,
                                              allowHalfValues As Boolean) As Double
            Dim max As Integer = NormalizeMaximum(maximum)
            If Double.IsNaN(value) OrElse Double.IsInfinity(value) Then value = 0.0R
            If value < 0.0R Then value = 0.0R
            If value > CDbl(max) Then value = CDbl(max)
            Dim stepSize As Double = If(allowHalfValues, 0.5R, 1.0R)
            Dim rounded As Double = Math.Round(value / stepSize, MidpointRounding.AwayFromZero) * stepSize
            If rounded < 0.0R Then Return 0.0R
            If rounded > CDbl(max) Then Return CDbl(max)
            Return rounded
        End Function

        Friend Shared Function ValueFromPointer(starIndex As Integer,
                                                localX As Single,
                                                starWidth As Single,
                                                maximum As Integer,
                                                allowHalfValues As Boolean,
                                                isRtl As Boolean) As Double
            Dim safeMax As Integer = NormalizeMaximum(maximum)
            If starIndex < 0 OrElse starIndex >= safeMax Then Return 0.0R
            If starWidth <= 1.0F Then Return NormalizeValue(starIndex + 1, safeMax, allowHalfValues)
            Dim logicalIndex As Integer = If(isRtl, safeMax - starIndex - 1, starIndex)
            If Not allowHalfValues Then Return NormalizeValue(logicalIndex + 1, safeMax, False)
            Dim ratio As Single = Math.Max(0.0F, Math.Min(1.0F, localX / starWidth))
            If isRtl Then ratio = 1.0F - ratio
            Dim halfStep As Double = If(ratio <= 0.5F, 0.5R, 1.0R)
            Return NormalizeValue(CDbl(logicalIndex) + halfStep, safeMax, True)
        End Function


        Friend Shared Function ValueFromPointerTrack(pointerX As Single,
                                                    trackLeft As Single,
                                                    starWidth As Single,
                                                    gapWidth As Single,
                                                    maximum As Integer,
                                                    allowHalfValues As Boolean,
                                                    isRtl As Boolean,
                                                    ByRef visualIndex As Integer) As Double
            visualIndex = -1
            Dim safeMax As Integer = NormalizeMaximum(maximum)
            If starWidth <= 1.0F Then Return 0.0R

            Dim safeGap As Single = Math.Max(0.0F, gapWidth)
            Dim pitch As Single = starWidth + safeGap
            Dim totalWidth As Single = CSng(safeMax) * starWidth + CSng(Math.Max(0, safeMax - 1)) * safeGap
            If totalWidth <= 1.0F OrElse pitch <= 1.0F Then Return 0.0R

            Dim x As Single = pointerX - trackLeft
            If x < 0.0F Then x = 0.0F
            If x > totalWidth Then x = totalWidth

            If x >= totalWidth Then
                visualIndex = safeMax - 1
            Else
                visualIndex = CInt(Math.Floor(CDbl(x / pitch)))
                If visualIndex < 0 Then visualIndex = 0
                If visualIndex >= safeMax Then visualIndex = safeMax - 1
            End If

            Dim localX As Single = x - CSng(visualIndex) * pitch
            If localX < 0.0F Then localX = 0.0F
            If localX > starWidth Then localX = starWidth

            Return ValueFromPointer(visualIndex, localX, starWidth, safeMax, allowHalfValues, isRtl)
        End Function

        Friend Shared Function BuildValueText(value As Double,
                                              maximum As Integer,
                                              allowHalfValues As Boolean) As String
            Dim normalized As Double = NormalizeValue(value, maximum, allowHalfValues)
            Dim format As String = If(allowHalfValues AndAlso Math.Abs(normalized - Math.Truncate(normalized)) > 0.01R, "0.0", "0")
            Return normalized.ToString(format, CultureInfo.CurrentCulture) & " / " & NormalizeMaximum(maximum).ToString(CultureInfo.CurrentCulture)
        End Function

        Friend Shared Function ResolveRightToLeft() As Boolean
            Try
                Return Nexamas.UI.Localization.MASLocalization.IsCurrentRightToLeft()
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(ex, "MASRatingPolicy.ResolveRightToLeft")
                Return False
            End Try
        End Function

        Friend Shared Function ResolveAccentColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.BrandTheme IsNot Nothing Then Return ctx.BrandTheme.BrandPrimary
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Warning
            Return New SKColor(64, 132, 246)
        End Function

        Friend Shared Function ResolvePrimaryTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.PrimaryText.WithAlpha(RatingTokens.TextAlpha)
            Return Nexamas.UI.Values.Color.Text.Primary.WithAlpha(RatingTokens.TextAlpha)
        End Function

        Friend Shared Function ResolveMutedTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.SecondaryText.WithAlpha(RatingTokens.MutedTextAlpha)
            Return Nexamas.UI.Values.Color.Text.Secondary.WithAlpha(RatingTokens.MutedTextAlpha)
        End Function

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

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

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

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

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

        Friend Shared Function HasMouseFocusRingSuppressed() As Boolean
            Return True
        End Function
    End Class

End Namespace
