Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Components
Imports Nexamas.UI.Host
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports SkiaSharp

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Official rendering hook surface for one MASApplicationWindow.
    ''' It subscribes to the existing root-host render events and does not create a parallel renderer.
    ''' </summary>
    <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
    Friend NotInheritable Class MASApplicationWindowRendering
        Implements IDisposable

        Friend Delegate Sub MASApplicationRenderHandler(context As MASApplicationRenderContext)

        Private ReadOnly _rootHost As MASSkiaRootHost
        Private ReadOnly _cardPainter As MASCardSurfacePainter
        Private _disposed As Boolean

        ''' <summary>
        ''' Draws behind the ControlsLayer.
        ''' Handlers may draw on the provided SKCanvas, but must not own host lifetime, input, overlays, or DPI state.
        ''' </summary>
        Friend Event BeforeControls As MASApplicationRenderHandler

        ''' <summary>
        ''' Draws after controls and before overlay preparation. Use for lightweight adorners only.
        ''' </summary>
        Friend Event AfterControls As MASApplicationRenderHandler

        ''' <summary>
        ''' Draws immediately before overlay/float content. Do not use this as a backdoor to OverlayManager or FloatRuntime ownership.
        ''' </summary>
        Friend Event BeforeOverlay As MASApplicationRenderHandler

        ''' <summary>
        ''' Draws after overlay/float content. Use sparingly for diagnostics or final visual adorners.
        ''' </summary>
        Friend Event AfterOverlay As MASApplicationRenderHandler

        Friend Sub New(rootHost As MASSkiaRootHost)
            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))

            _rootHost = rootHost
            _cardPainter = New MASCardSurfacePainter()

            AddHandler _rootHost.RenderBeforeControls, AddressOf OnRootBeforeControls
            AddHandler _rootHost.RenderAfterControls, AddressOf OnRootAfterControls
            AddHandler _rootHost.RenderBeforeOverlay, AddressOf OnRootBeforeOverlay
            AddHandler _rootHost.RenderAfterOverlay, AddressOf OnRootAfterOverlay
        End Sub

        Friend ReadOnly Property IsDisposed As Boolean
            Get
                Return _disposed
            End Get
        End Property

        ''' <summary>
        ''' Draws a standard MAS card surface using the official MAS rendering facade.
        ''' This keeps card painters internal while allowing application code to draw MAS-consistent chrome.
        ''' </summary>
        Friend Sub DrawCardSurface(renderContext As MASApplicationRenderContext,
                                   boundsPx As SKRect,
                                   Optional visualStyle As MASCardVisualStyle = MASCardVisualStyle.Default,
                                   Optional dpi As Single = 0.0F,
                                   Optional surfaceMaterialKey As String = Nothing)

            If _disposed Then Return
            If renderContext Is Nothing OrElse Not renderContext.HasCanvas() Then Return
            If boundsPx.IsEmpty OrElse boundsPx.Width <= 1.0F OrElse boundsPx.Height <= 1.0F Then Return

            Dim ctx As MASThemeContext = renderContext.ThemeContext
            If ctx Is Nothing Then Return

            Dim safeDpi As Single = dpi
            If safeDpi <= 0.0F Then
                safeDpi = renderContext.Dpi
            End If

            _cardPainter.Draw(
                canvas:=renderContext.Canvas,
                ctx:=ctx,
                rPx:=boundsPx,
                dpi:=safeDpi,
                visualStyle:=visualStyle,
                surfaceMaterialKey:=surfaceMaterialKey)
        End Sub


        ''' <summary>
        ''' Draws the official command-region background when requested by the caller. The public
        ''' choice is only visible/hidden; Nexamas UI owns the internal visual and paints the same
        ''' default card surface used by application-surface regions, not a command-specific SurfaceVisualStyle.
        ''' </summary>
        Friend Sub DrawCommandBackground(renderContext As MASApplicationRenderContext,
                                         boundsPx As SKRect,
                                         showBackground As Boolean,
                                         Optional dpi As Single = 0.0F,
                                         Optional surfaceMaterialKey As String = Nothing)

            If Not showBackground Then Return

            DrawCardSurface(
                renderContext:=renderContext,
                boundsPx:=boundsPx,
                visualStyle:=MASCardVisualStyle.Default,
                dpi:=dpi,
                surfaceMaterialKey:=surfaceMaterialKey)
        End Sub


        ''' <summary>
        ''' Draws a SurfaceVisualStyle-owned application surface inside caller-owned bounds.
        ''' This is the official advanced rendering gateway for application regions that already
        ''' have a correct MASLayout slot and only need Nexamas UI-owned material/frame/chrome
        ''' personality. It must not be used to compute layout or replace semantic application-surface APIs.
        ''' </summary>
        Friend Sub DrawSurfaceVisualStyle(renderContext As MASApplicationRenderContext,
                                          boundsPx As SKRect,
                                          styleKey As String,
                                          Optional cornerRadiusDip As Single = 12.0F,
                                          Optional borderStrengthLevel As Integer = 4,
                                          Optional surfaceStrengthLevel As Integer = 4,
                                          Optional dpi As Single = 0.0F)

            If _disposed Then Return
            If renderContext Is Nothing OrElse Not renderContext.HasCanvas() Then Return
            If boundsPx.IsEmpty OrElse boundsPx.Width <= 1.0F OrElse boundsPx.Height <= 1.0F Then Return

            Dim ctx As MASThemeContext = renderContext.ThemeContext
            If ctx Is Nothing Then Return

            Dim safeDpi As Single = dpi
            If safeDpi <= 0.0F OrElse Single.IsNaN(safeDpi) OrElse Single.IsInfinity(safeDpi) Then
                safeDpi = renderContext.Dpi
            End If
            If safeDpi <= 0.0F OrElse Single.IsNaN(safeDpi) OrElse Single.IsInfinity(safeDpi) Then
                safeDpi = 1.0F
            End If

            Dim safeStyleKey As String = If(styleKey, String.Empty).Trim()
            If safeStyleKey.Length = 0 OrElse String.Equals(safeStyleKey, MASSurfaceVisualStyleIds.Auto, StringComparison.OrdinalIgnoreCase) Then
                safeStyleKey = MASSurfaceVisualStyleIds.PlatformDialogFrame
            End If

            Dim style As MASSurfaceVisualStyle = MASSurfaceVisualStyleRegistry.Resolve(safeStyleKey)
            If style Is Nothing Then Return

            Dim radiusDip As Single = SafeNonNegative(cornerRadiusDip)
            Dim radiusPx As Single = radiusDip * safeDpi

            MASSurfaceTreatmentRuntimeSurfaceVisual.TryDrawRuntimeSurfaceVisual(
                canvas:=renderContext.Canvas,
                ctx:=ctx,
                boundsPx:=boundsPx,
                consumerKind:=MASSurfaceTreatmentConsumerKind.ApplicationChromeSurface,
                materialKey:=style.SurfaceMaterialKey,
                dpi:=safeDpi,
                cornerRadiusPx:=radiusPx,
                surfaceRole:=style.SurfaceRole,
                surfaceStrengthLevel:=ClampLevel(surfaceStrengthLevel),
                borderStrengthLevel:=ClampLevel(borderStrengthLevel),
                requestedFrameStrength:=ToFrameStrength(ClampLevel(borderStrengthLevel)),
                hasExplicitMaterialOverride:=False)
        End Sub

        Friend Sub DrawBackground(renderContext As MASApplicationRenderContext,
                                  background As MASBackground)

            If _disposed Then Return
            If renderContext Is Nothing OrElse Not renderContext.HasCanvas() Then Return
            If background Is Nothing Then Return

            Dim ctx As MASThemeContext = renderContext.ThemeContext
            If ctx Is Nothing Then Return

            background.Render(
                renderContext.Canvas,
                ctx,
                renderContext.WidthPx,
                renderContext.HeightPx)
        End Sub

        Friend Sub DrawTopBar(renderContext As MASApplicationRenderContext,
                              topBar As MASTopBarComponent,
                              boundsPx As SKRect,
                              elapsedSeconds As Single)

            If _disposed Then Return
            If renderContext Is Nothing OrElse Not renderContext.HasCanvas() Then Return
            If topBar Is Nothing Then Return
            If boundsPx.IsEmpty OrElse boundsPx.Width <= 0.0F OrElse boundsPx.Height <= 0.0F Then Return

            Dim ctx As MASThemeContext = renderContext.ThemeContext
            If ctx Is Nothing Then Return

            topBar.Render(
                renderContext.Canvas,
                ctx,
                boundsPx,
                elapsedSeconds)
        End Sub


        Private Shared Function SafeNonNegative(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value < 0.0F Then Return 0.0F
            Return value
        End Function

        Private Shared Function ClampLevel(value As Integer) As Integer
            If value < 1 Then Return 1
            If value > 6 Then Return 6
            Return value
        End Function

        Private Shared Function ToFrameStrength(value As Integer) As MASSurfaceFrameStrength
            Select Case ClampLevel(value)
                Case 1
                    Return MASSurfaceFrameStrength.Level1
                Case 2
                    Return MASSurfaceFrameStrength.Level2
                Case 3
                    Return MASSurfaceFrameStrength.Level3
                Case 4
                    Return MASSurfaceFrameStrength.Level4
                Case 5
                    Return MASSurfaceFrameStrength.Level5
                Case Else
                    Return MASSurfaceFrameStrength.Level6
            End Select
        End Function

        Private Sub OnRootBeforeControls(canvas As SKCanvas,
                                         info As SKImageInfo,
                                         ctx As MASThemeContext)
            If _disposed Then Return
            Try
                RaiseEvent BeforeControls(New MASApplicationRenderContext(canvas, info, ctx))
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException1, "MASApplicationWindow.Rendering.BeforeControls")
            End Try
        End Sub

        Private Sub OnRootAfterControls(canvas As SKCanvas,
                                        info As SKImageInfo,
                                        ctx As MASThemeContext)
            If _disposed Then Return
            Try
                RaiseEvent AfterControls(New MASApplicationRenderContext(canvas, info, ctx))
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException2, "MASApplicationWindow.Rendering.AfterControls")
            End Try
        End Sub

        Private Sub OnRootBeforeOverlay(canvas As SKCanvas,
                                        info As SKImageInfo,
                                        ctx As MASThemeContext)
            If _disposed Then Return
            Try
                RaiseEvent BeforeOverlay(New MASApplicationRenderContext(canvas, info, ctx))
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException3, "MASApplicationWindow.Rendering.BeforeOverlay")
            End Try
        End Sub

        Private Sub OnRootAfterOverlay(canvas As SKCanvas,
                                       info As SKImageInfo,
                                       ctx As MASThemeContext)
            If _disposed Then Return
            Try
                RaiseEvent AfterOverlay(New MASApplicationRenderContext(canvas, info, ctx))
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException4, "MASApplicationWindow.Rendering.AfterOverlay")
            End Try
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            Try
                RemoveHandler _rootHost.RenderBeforeControls, AddressOf OnRootBeforeControls
            Catch masCaughtException5 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException5)
            End Try

            Try
                RemoveHandler _rootHost.RenderAfterControls, AddressOf OnRootAfterControls
            Catch masCaughtException6 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException6)
            End Try

            Try
                RemoveHandler _rootHost.RenderBeforeOverlay, AddressOf OnRootBeforeOverlay
            Catch masCaughtException7 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException7)
            End Try

            Try
                RemoveHandler _rootHost.RenderAfterOverlay, AddressOf OnRootAfterOverlay
            Catch masCaughtException8 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException8)
            End Try

            Try
                _cardPainter.Dispose()
            Catch masCaughtException9 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException9)
            End Try
        End Sub

    End Class

End Namespace
