Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Rendering

    ''' <summary>
    ''' Draws premium card frame/border chrome for elevated card surfaces.
    ''' </summary>
    ''' <remarks>
    ''' The surface body is drawn by the material fill painter. This class owns only frame concerns.
    ''' </remarks>
    Friend NotInheritable Class MASPremiumCardFramePainter
        Implements IDisposable

        Private _disposed As Boolean

        Private ReadOnly _strokeOuter As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Stroke}
        Private ReadOnly _strokeInner As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Stroke}
        Private ReadOnly _frameBorder As New MASSurfaceFrameBorderPainter()

        Friend Sub Draw(canvas As SKCanvas,
                        ctx As MASThemeContext,
                        baseRect As SKRect,
                        radius As Single,
                        dpi As Single,
                        visualStyle As MASCardVisualStyle)

            If _disposed Then Return
            If canvas Is Nothing Then Return
            If baseRect.Width <= 1.0F OrElse baseRect.Height <= 1.0F Then Return

            dpi = PixelSnap.SafeDpi(dpi)
            radius = PixelSnap.SafeRadius(radius)

            If visualStyle = MASCardVisualStyle.Secondary Then
                Dim borderSpec As MASSurfaceFrameBorderSpec =
                    MASCardSecondaryFrameBorderResolver.Resolve(
                        ctx:=ctx,
                        strength:=MASSurfaceFrameStrength.Level6)

                borderSpec = MASSurfaceFramePainter.ScaleBorderSpec(borderSpec, dpi)

                _frameBorder.Draw(
                    canvas:=canvas,
                    baseRect:=baseRect,
                    baseRadiusPx:=radius,
                    dpi:=dpi,
                    spec:=borderSpec)

                Return
            End If

            Dim pal As MASCardSurfaceVisualPalette =
                MASCardSurfaceVisualPaletteResolver.Resolve(ctx, visualStyle)

            DrawDefaultBorderHierarchy(
                canvas:=canvas,
                baseRect:=baseRect,
                radius:=radius,
                dpi:=dpi,
                pal:=pal)
        End Sub

        Private Sub DrawDefaultBorderHierarchy(canvas As SKCanvas,
                                               baseRect As SKRect,
                                               radius As Single,
                                               dpi As Single,
                                               pal As MASCardSurfaceVisualPalette)

            If canvas Is Nothing Then Return
            If baseRect.Width <= 1 OrElse baseRect.Height <= 1 Then Return

            Dim fam As CommonEnums.SurfaceFamily = CommonEnums.SurfaceFamily.Card
            Dim behavior As MASVisualEffectIntensityProfiles.AcrylicSurfaceIntensityProfile =
                MASVisualEffectIntensityProfiles.ResolveAcrylic(fam)

            Dim outerStroke As MASVisualPrimitivesPainter.StrokeRoundRectInfo =
                MASVisualPrimitivesPainter.BuildStrokeRoundRectInfo(
                    baseRect:=baseRect,
                    baseRadius:=radius,
                    dpi:=dpi,
                    edgeInsetPx:=0.0F,
                    strokeWidthPx:=Math.Max(SurfaceTokens.FxRingStroke * dpi,
                                            SurfaceTokens.FxRingMinStrokePx))

            If outerStroke.HasValue Then
                Dim outerStrength As Single = Math.Max(0.0F, Math.Min(1.0F, behavior.OuterBorderStrength))

                Dim outerBase As SKColor =
                    ColorMath.Mix(pal.BorderOuter, pal.ColdTint, 0.16F)

                Dim outerAlpha As Integer =
                    CInt(Math.Round(22.0F + outerStrength * 26.0F))

                If outerAlpha < 0 Then outerAlpha = 0
                If outerAlpha > 255 Then outerAlpha = 255

                _strokeOuter.IsAntialias = True
                _strokeOuter.IsDither = False
                _strokeOuter.Style = SKPaintStyle.Stroke
                _strokeOuter.StrokeJoin = SKStrokeJoin.Round
                _strokeOuter.StrokeCap = SKStrokeCap.Round
                _strokeOuter.StrokeWidth = outerStroke.StrokeWidth
                _strokeOuter.Color = ColorMath.WithAlpha(outerBase, CByte(outerAlpha))

                canvas.DrawRoundRect(outerStroke.Rect, outerStroke.Radius, outerStroke.Radius, _strokeOuter)
            End If

            Dim innerStroke As MASVisualPrimitivesPainter.StrokeRoundRectInfo =
                MASVisualPrimitivesPainter.BuildStrokeRoundRectInfo(
                    baseRect:=baseRect,
                    baseRadius:=radius,
                    dpi:=dpi,
                    edgeInsetPx:=1.0F * dpi,
                    strokeWidthPx:=Math.Max(0.8F, 0.72F * dpi))

            If innerStroke.HasValue Then
                Dim topRim As SKColor =
                    ColorMath.Mix(pal.SurfaceTop, pal.Sheen, 0.24F)

                Dim midRim As SKColor =
                    ColorMath.Mix(pal.SurfaceMid, pal.BorderInner, 0.18F)

                Dim innerAlphaMul As Single =
                    0.72F + (behavior.InnerBorderStrength * 0.56F)

                Dim topA As Byte =
                    CByte(Math.Max(0, Math.Min(255, CInt(Math.Round(28.0F * innerAlphaMul)))))

                Dim midA As Byte =
                    CByte(Math.Max(0, Math.Min(255, CInt(Math.Round(10.0F * innerAlphaMul)))))

                Using sh As SKShader = SKShader.CreateLinearGradient(
                    New SKPoint(innerStroke.Rect.Left, innerStroke.Rect.Top),
                    New SKPoint(innerStroke.Rect.Left, innerStroke.Rect.Bottom),
                    New SKColor() {
                        ColorMath.WithAlpha(topRim, topA),
                        ColorMath.WithAlpha(midRim, midA),
                        SKColors.Transparent
                    },
                    New Single() {0.0F, 0.38F, 1.0F},
                    SKShaderTileMode.Clamp)

                    _strokeInner.IsAntialias = True
                    _strokeInner.IsDither = False
                    _strokeInner.Style = SKPaintStyle.Stroke
                    _strokeInner.StrokeJoin = SKStrokeJoin.Round
                    _strokeInner.StrokeCap = SKStrokeCap.Round
                    _strokeInner.StrokeWidth = innerStroke.StrokeWidth
                    _strokeInner.Shader = sh

                    canvas.DrawRoundRect(innerStroke.Rect, innerStroke.Radius, innerStroke.Radius, _strokeInner)
                    _strokeInner.Shader = Nothing
                End Using
            End If
        End Sub

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

            SafeDispose(_strokeOuter)
            SafeDispose(_strokeInner)

            Try
                _frameBorder.Dispose()
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException1)
            End Try
        End Sub

        Private Shared Sub SafeDispose(p As SKPaint)
            If p Is Nothing Then Return
            Try
                p.Dispose()
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException2)
            End Try
        End Sub

    End Class

End Namespace
