Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Rendering

    Friend NotInheritable Class MASPanelShellRenderer

        Private Shared ReadOnly _shellContract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASPanelShellContract))

        ''' <summary>
        ''' Shared shadow painter for PanelShell chrome.
        ''' The renderer owns no shadow constants; shadow shape/strength comes from
        ''' MASShadowResolver + MASShadowHierarchyProfiles through the PanelShell contract.
        ''' </summary>
        Private Shared ReadOnly _shadowPainter As New MASShadowPainter()

        Private Sub New()
        End Sub

        Friend Shared Function Measure(dpi As Single,
                                       spec As MASPanelShellSpec) As MASPanelShellResult

            Return MASPanelShellLayoutEngine.Measure(dpi, spec, _shellContract)

        End Function

        Friend Shared Function Draw(canvas As SKCanvas,
                                    ctx As MASThemeContext,
                                    dpi As Single,
                                    spec As MASPanelShellSpec) As MASPanelShellResult

            Dim result As MASPanelShellResult =
                Measure(dpi, spec)

            If canvas Is Nothing OrElse spec Is Nothing Then Return result
            If Not PixelSnap.HasArea(result.BaseRectPx) Then Return result

            Dim scope As MASContractRenderScope =
                MASArchitectureRuntime.CreateRenderScope(
                    NameOf(MASPanelShellRenderer),
                    _shellContract,
                    MASRenderLayer.Surface,
                    MASRenderLayer.Shadow,
                    MASRenderLayer.Text)

            scope.RequireAnyLayer(
                MASRenderLayer.Surface,
                MASRenderLayer.Shadow,
                MASRenderLayer.Text)

            dpi = PixelSnap.SafeDpi(dpi)

            Dim style As MASPanelShellResolvedStyle = Nothing
            If Not MASPanelShellResolvedStyle.TryCreate(ctx, spec, style) Then Return result

            DrawMaterialSurface(
                canvas:=canvas,
                ctx:=ctx,
                dpi:=dpi,
                spec:=spec,
                result:=result,
                style:=style)

            If result.HasHeader Then
                MASPanelShellHeaderPainter.Draw(
                    canvas:=canvas,
                    ctx:=ctx,
                    dpi:=dpi,
                    style:=style,
                    spec:=spec,
                    result:=result,
                    contract:=_shellContract)
            End If

            Return result

        End Function

        Private Shared Sub DrawMaterialSurface(canvas As SKCanvas,
                                               ctx As MASThemeContext,
                                               dpi As Single,
                                               spec As MASPanelShellSpec,
                                               result As MASPanelShellResult,
                                               style As MASPanelShellResolvedStyle)

            If canvas Is Nothing OrElse ctx Is Nothing OrElse style Is Nothing Then Return

            DrawShellShadow(canvas, result, style, dpi)

            If Not MASSurfaceMaterialComponentGateway.TryDrawPanelShellSurface(
                canvas:=canvas,
                ctx:=ctx,
                boundsPx:=result.BaseRectPx,
                materialKey:=style.ResolvedMaterialKey,
                dpi:=dpi,
                cornerRadiusPx:=result.RadiusPx,
                visualStyle:=style.VisualStyle,
                surfaceStrengthLevel:=style.SurfaceStrengthLevel,
                borderStrengthLevel:=style.BorderStrengthLevel,
                frameStrength:=ToFrameStrength(style.BorderStrengthLevel),
                hasExplicitMaterialOverride:=True) Then
                Return
            End If

        End Sub

        Private Shared Sub DrawShellShadow(canvas As SKCanvas,
                                           result As MASPanelShellResult,
                                           style As MASPanelShellResolvedStyle,
                                           dpi As Single)

            If canvas Is Nothing OrElse result Is Nothing OrElse style Is Nothing Then Return
            If Not PixelSnap.HasArea(result.BaseRectPx) Then Return

            dpi = PixelSnap.SafeDpi(dpi)

            Dim spec As MASLayeredShadowSpec =
                MASShadowResolver.ResolveLayered(_shellContract)

            Dim shadowBase As SKColor =
                ResolvePanelShellShadowBase(style)

            _shadowPainter.DrawLayeredShadow(
                canvas:=canvas,
                r:=result.BaseRectPx,
                radiusPx:=result.RadiusPx,
                dpi:=dpi,
                shadowBase:=shadowBase,
                spec:=spec)

        End Sub

        Private Shared Function ResolvePanelShellShadowBase(style As MASPanelShellResolvedStyle) As SKColor

            If style IsNot Nothing AndAlso style.SurfaceTheme IsNot Nothing Then
                Dim c As SKColor = style.SurfaceTheme.Chrome.ShadowBase
                If c.Alpha <> 0 Then Return c

                c = style.SurfaceTheme.Chrome.ShadowAmbient
                If c.Alpha <> 0 Then Return c

                c = style.SurfaceTheme.Chrome.ShadowContact
                If c.Alpha <> 0 Then Return c
            End If

            Return Nexamas.UI.Values.Color.Core.ShadowBase

        End Function

        Private Shared Function ToFrameStrength(value As Integer) As MASSurfaceFrameStrength
            Select Case Math.Max(1, Math.Min(6, 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


    End Class

End Namespace