Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Components
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Controls
Imports SkiaSharp

Namespace Nexamas.UI.Verification

    ''' <summary>
    ''' Per-scenario deterministic capture context used by Render Verification capture hosts.
    ''' </summary>
    ''' <remarks>
    ''' The context owns the bitmap, canvas, ThemeHost, and ControlsLayer for one scenario. Scene builders may add
    ''' real MAS controls to <see cref="Layer"/> or draw owned chrome directly to <see cref="Canvas"/>. The host renders
    ''' the layer once, then executes registered after-layer renderers such as tooltip floats or footer chrome.
    ''' </remarks>
    Friend NotInheritable Class MASRenderVerificationCaptureContext
        Implements IDisposable

        Private ReadOnly _afterLayerRenderers As New List(Of Action(Of MASRenderVerificationCaptureContext))()
        Private ReadOnly _themeHost As ThemeHost
        Private _bitmap As SKBitmap
        Private _canvas As SKCanvas
        Private _disposed As Boolean

        Friend Sub New(scenario As MASRenderVerificationScenario,
                       bitmap As SKBitmap,
                       canvas As SKCanvas,
                       themeHost As ThemeHost,
                       layer As ControlsLayer)
            If scenario Is Nothing Then Throw New ArgumentNullException(NameOf(scenario))
            If bitmap Is Nothing Then Throw New ArgumentNullException(NameOf(bitmap))
            If canvas Is Nothing Then Throw New ArgumentNullException(NameOf(canvas))
            If themeHost Is Nothing Then Throw New ArgumentNullException(NameOf(themeHost))
            If layer Is Nothing Then Throw New ArgumentNullException(NameOf(layer))

            Me.Scenario = scenario
            _bitmap = bitmap
            _canvas = canvas
            _themeHost = themeHost
            Me.Layer = layer
        End Sub

        Friend ReadOnly Property Scenario As MASRenderVerificationScenario

        Friend ReadOnly Property Canvas As SKCanvas
            Get
                ThrowIfDisposed()
                Return _canvas
            End Get
        End Property

        Friend ReadOnly Property Layer As ControlsLayer

        Friend ReadOnly Property ThemeContext As MASThemeContext
            Get
                ThrowIfDisposed()
                Return _themeHost.Context
            End Get
        End Property

        ''' <summary>
        ''' Registers deterministic drawing that must occur after ControlsLayer rendered its real MAS controls.
        ''' </summary>
        Friend Sub AddAfterLayerRenderer(renderer As Action(Of MASRenderVerificationCaptureContext))
            ThrowIfDisposed()
            If renderer Is Nothing Then Return
            _afterLayerRenderers.Add(renderer)
        End Sub

        ''' <summary>
        ''' Renders the real controls layer and then every deterministic after-layer renderer in registration order.
        ''' </summary>
        Friend Sub RenderLayerAndAfterLayer()
            ThrowIfDisposed()
            Layer.Render(Canvas, ThemeContext)

            For Each renderer As Action(Of MASRenderVerificationCaptureContext) In _afterLayerRenderers
                renderer(Me)
            Next
        End Sub

        ''' <summary>
        ''' Transfers bitmap ownership to the caller. The context will still dispose canvas/layer/theme resources.
        ''' </summary>
        Friend Function DetachBitmap() As SKBitmap
            ThrowIfDisposed()
            Dim result As SKBitmap = _bitmap
            _bitmap = Nothing
            Return result
        End Function

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

            If Layer IsNot Nothing Then Layer.Dispose()
            If _canvas IsNot Nothing Then
                _canvas.Dispose()
                _canvas = Nothing
            End If
            If _themeHost IsNot Nothing Then _themeHost.Dispose()
            If _bitmap IsNot Nothing Then
                _bitmap.Dispose()
                _bitmap = Nothing
            End If
        End Sub

        Private Sub ThrowIfDisposed()
            If _disposed Then Throw New ObjectDisposedException(GetType(MASRenderVerificationCaptureContext).Name)
        End Sub
    End Class

End Namespace
