Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Runtime.CompilerServices
Imports Nexamas.UI.Diagnostics

Namespace Nexamas.UI.Localization

    ''' <summary>
    ''' Internal diagnostic codes emitted when Localization/RTL resolution cannot honor the requested runtime culture.
    ''' </summary>
    Friend Enum MASLocalizationRtlResolutionDiagnosticCode
        None = 0
        UnsupportedRtlCultureFallback = 1
        InvalidCultureFallback = 2
        RuntimeRtlResolutionException = 3
    End Enum

    ''' <summary>
    ''' Immutable Friend-only report for Localization/RTL fallback diagnostics.
    ''' </summary>
    Friend NotInheritable Class MASLocalizationRtlResolutionDiagnosticReport
        Friend Sub New(capturedUtc As DateTimeOffset,
                       fallbackCount As Integer,
                       lastDiagnosticCode As String,
                       lastRequestedCultureName As String,
                       lastFallbackCultureName As String,
                       lastSource As String,
                       lastReason As String)

            Me.CapturedUtc = capturedUtc
            Me.FallbackCount = Math.Max(0, fallbackCount)
            Me.LastDiagnosticCode = If(lastDiagnosticCode, String.Empty)
            Me.LastRequestedCultureName = If(lastRequestedCultureName, String.Empty)
            Me.LastFallbackCultureName = If(lastFallbackCultureName, String.Empty)
            Me.LastSource = If(lastSource, String.Empty)
            Me.LastReason = If(lastReason, String.Empty)
        End Sub

        Friend ReadOnly Property CapturedUtc As DateTimeOffset
        Friend ReadOnly Property FallbackCount As Integer
        Friend ReadOnly Property LastDiagnosticCode As String
        Friend ReadOnly Property LastRequestedCultureName As String
        Friend ReadOnly Property LastFallbackCultureName As String
        Friend ReadOnly Property LastSource As String
        Friend ReadOnly Property LastReason As String

        Friend ReadOnly Property HasFallbacks As Boolean
            Get
                Return FallbackCount > 0
            End Get
        End Property
    End Class

    ''' <summary>
    ''' Single Localization-owned diagnostic channel for RTL/culture fallback decisions.
    ''' </summary>
    ''' <remarks>
    ''' Unknown RTL cultures must not collapse to the English/LTR product profile without a retained reason.
    ''' This channel keeps bounded internal counters and also publishes a safe structured record through
    ''' the existing MAS runtime fault channel so application diagnostics can surface the fallback without
    ''' exposing Localization internals or opening a public catalog API.
    ''' </remarks>
    Friend NotInheritable Class MASLocalizationRtlResolutionDiagnostics
        Private Const ContextPrefix As String = "Localization.RtlResolutionFallback."
        Private Const SyntheticExceptionTypeName As String = "Nexamas.UI.Localization.MASLocalizationRtlResolutionFallback"

        Private Shared ReadOnly SyncRoot As New Object()
        Private Shared _fallbackCount As Integer
        Private Shared _lastDiagnosticCode As MASLocalizationRtlResolutionDiagnosticCode = MASLocalizationRtlResolutionDiagnosticCode.None
        Private Shared _lastRequestedCultureName As String = String.Empty
        Private Shared _lastFallbackCultureName As String = String.Empty
        Private Shared _lastSource As String = String.Empty
        Private Shared _lastReason As String = String.Empty

        Private Sub New()
        End Sub

        Friend Shared Sub RecordFallback(requestedCultureName As String,
                                         fallbackCultureName As String,
                                         source As String,
                                         diagnosticCode As MASLocalizationRtlResolutionDiagnosticCode,
                                         reason As String,
                                         <CallerMemberName> Optional memberName As String = Nothing,
                                         <CallerFilePath> Optional sourceFile As String = Nothing,
                                         <CallerLineNumber> Optional sourceLine As Integer = 0)
            Dim normalizedCode As MASLocalizationRtlResolutionDiagnosticCode = NormalizeCode(diagnosticCode)
            If normalizedCode = MASLocalizationRtlResolutionDiagnosticCode.None Then Return

            Dim normalizedRequested As String = Normalize(requestedCultureName)
            Dim normalizedFallback As String = Normalize(fallbackCultureName)
            If normalizedFallback.Length = 0 Then normalizedFallback = "en-US"
            Dim normalizedSource As String = Normalize(source)
            If normalizedSource.Length = 0 Then normalizedSource = If(memberName, "Localization.RtlResolution")
            Dim normalizedReason As String = Normalize(reason)
            If normalizedReason.Length = 0 Then normalizedReason = "Localization/RTL resolution fell back to the default product culture."

            Dim occurrenceCount As Integer
            SyncLock SyncRoot
                _fallbackCount += 1
                occurrenceCount = _fallbackCount
                _lastDiagnosticCode = normalizedCode
                _lastRequestedCultureName = normalizedRequested
                _lastFallbackCultureName = normalizedFallback
                _lastSource = normalizedSource
                _lastReason = normalizedReason
            End SyncLock

            Dim record As New MASRuntimeFaultRecord(
                timestampUtc:=Nexamas.UI.Timing.MASTimeProvider.UtcNowOffset(),
                severity:=MASExceptionSeverity.Recoverable,
                category:=MASExceptionHandlingCategory.DiagnosticOnly,
                context:=ContextPrefix & normalizedCode.ToString(),
                sourceFile:=If(sourceFile, "<unknown>"),
                sourceLine:=sourceLine,
                exceptionTypeName:=SyntheticExceptionTypeName,
                message:=BuildMessage(normalizedRequested, normalizedFallback, normalizedSource, normalizedReason),
                occurrenceCount:=occurrenceCount,
                isFirstOccurrence:=(occurrenceCount = 1))

            MASRuntimeFaultChannel.Publish(record)
        End Sub

        Friend Shared Function GetReport() As MASLocalizationRtlResolutionDiagnosticReport
            SyncLock SyncRoot
                Return New MASLocalizationRtlResolutionDiagnosticReport(
                    capturedUtc:=Nexamas.UI.Timing.MASTimeProvider.UtcNowOffset(),
                    fallbackCount:=_fallbackCount,
                    lastDiagnosticCode:=If(_lastDiagnosticCode = MASLocalizationRtlResolutionDiagnosticCode.None, String.Empty, _lastDiagnosticCode.ToString()),
                    lastRequestedCultureName:=_lastRequestedCultureName,
                    lastFallbackCultureName:=_lastFallbackCultureName,
                    lastSource:=_lastSource,
                    lastReason:=_lastReason)
            End SyncLock
        End Function

        Friend Shared Sub ResetForTests()
            SyncLock SyncRoot
                _fallbackCount = 0
                _lastDiagnosticCode = MASLocalizationRtlResolutionDiagnosticCode.None
                _lastRequestedCultureName = String.Empty
                _lastFallbackCultureName = String.Empty
                _lastSource = String.Empty
                _lastReason = String.Empty
            End SyncLock
        End Sub

        Private Shared Function NormalizeCode(diagnosticCode As MASLocalizationRtlResolutionDiagnosticCode) As MASLocalizationRtlResolutionDiagnosticCode
            Select Case diagnosticCode
                Case MASLocalizationRtlResolutionDiagnosticCode.UnsupportedRtlCultureFallback,
                     MASLocalizationRtlResolutionDiagnosticCode.InvalidCultureFallback,
                     MASLocalizationRtlResolutionDiagnosticCode.RuntimeRtlResolutionException
                    Return diagnosticCode
                Case Else
                    Return MASLocalizationRtlResolutionDiagnosticCode.None
            End Select
        End Function

        Private Shared Function BuildMessage(requestedCultureName As String,
                                             fallbackCultureName As String,
                                             source As String,
                                             reason As String) As String
            Return "RequestedCulture=" & If(requestedCultureName, String.Empty) &
                   "; FallbackCulture=" & If(fallbackCultureName, String.Empty) &
                   "; Source=" & If(source, String.Empty) &
                   "; Reason=" & If(reason, String.Empty)
        End Function

        Private Shared Function Normalize(value As String) As String
            Return If(value, String.Empty).Trim()
        End Function
    End Class

End Namespace
