Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.General
Imports SkiaSharp

Namespace Nexamas.UI.Rendering

    ''' <summary>
    ''' Woven Slate texture/body painter
    ''' - flat polished cold glass
    ''' - premium woven micro-texture
    ''' - elegant top sheen and inner glass wash
    ''' - refined edge fade, center bloom, and quiet lower anchor
    ''' - ambient shadow is orchestrated by ShadowSystem semantic facades
    ''' </summary>
    Friend NotInheritable Class MASWovenSlateTexturePainter
        Implements IDisposable

        Private _disposed As Boolean

        Friend Sub Draw(canvas As SKCanvas,
                        rectPx As SKRect,
                        dpi As Single,
                        Optional cornerRadiusDip As Single = 11.0F)

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

            dpi = PixelSnap.SafeDpi(dpi)
            rectPx = PixelSnap.SnapRectHalf(rectPx)

            Dim rr As Single = Math.Max(4.0F, cornerRadiusDip * dpi)

            DrawBaseBody(canvas, rectPx, rr)
            DrawTopGlassSheen(canvas, rectPx, rr, dpi)
            DrawEdgeFade(canvas, rectPx, rr, dpi)
            DrawInnerWash(canvas, rectPx, rr, dpi)
            DrawWovenTexture(canvas, rectPx, rr, dpi)
            DrawCenterGlow(canvas, rectPx, rr, dpi)
            DrawBottomAnchor(canvas, rectPx, rr, dpi)
            DrawBorders(canvas, rectPx, rr, dpi)
            DrawTopHairlineLift(canvas, rectPx, rr, dpi)
        End Sub

#Region "Layers"

        Private Shared Sub DrawBaseBody(canvas As SKCanvas,
                                        rectPx As SKRect,
                                        radiusPx As Single)

            Dim c0 As New SKColor(247, 251, 255, 222)
            Dim c1 As New SKColor(239, 246, 253, 214)
            Dim c2 As New SKColor(231, 239, 248, 208)
            Dim c3 As New SKColor(223, 232, 242, 204)

            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(rectPx.Left, rectPx.Top),
                New SKPoint(rectPx.Left, rectPx.Bottom),
                New SKColor() {c0, c1, c2, c3},
                New Single() {0.0F, 0.18F, 0.58F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh
                }
                    canvas.DrawRoundRect(rectPx, radiusPx, radiusPx, p)
                End Using
            End Using
        End Sub

        Private Shared Sub DrawTopGlassSheen(canvas As SKCanvas,
                                             rectPx As SKRect,
                                             radiusPx As Single,
                                             dpi As Single)

            Dim h As Single = Math.Max(10.0F * dpi, rectPx.Height * 0.17F)
            Dim sheenRect As New SKRect(
                rectPx.Left,
                rectPx.Top,
                rectPx.Right,
                rectPx.Top + h
            )

            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(sheenRect.Left, sheenRect.Top),
                New SKPoint(sheenRect.Left, sheenRect.Bottom),
                New SKColor() {
                    New SKColor(255, 255, 255, 74),
                    New SKColor(250, 252, 255, 26),
                    SKColors.Transparent
                },
                New Single() {0.0F, 0.3F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.Screen
                }
                    canvas.Save()
                    canvas.ClipRoundRect(
                        New SKRoundRect(rectPx, radiusPx, radiusPx),
                        SKClipOperation.Intersect,
                        antialias:=True
                    )
                    canvas.DrawRect(sheenRect, p)
                    canvas.Restore()
                End Using
            End Using
        End Sub

        Private Shared Sub DrawEdgeFade(canvas As SKCanvas,
                                        rectPx As SKRect,
                                        radiusPx As Single,
                                        dpi As Single)

            Dim fade As Single = Math.Max(8.0F * dpi, rectPx.Height * 0.12F)
            If fade * 2.0F >= rectPx.Width OrElse fade * 2.0F >= rectPx.Height Then Return

            canvas.Save()
            canvas.ClipRoundRect(
                New SKRoundRect(rectPx, radiusPx, radiusPx),
                SKClipOperation.Intersect,
                antialias:=True
            )

            ' Top
            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(rectPx.Left, rectPx.Top),
                New SKPoint(rectPx.Left, rectPx.Top + fade),
                New SKColor() {
                    New SKColor(255, 255, 255, 20),
                    SKColors.Transparent
                },
                New Single() {0.0F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.Screen
                }
                    canvas.DrawRect(New SKRect(rectPx.Left, rectPx.Top, rectPx.Right, rectPx.Top + fade), p)
                End Using
            End Using

            ' Left
            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(rectPx.Left, rectPx.Top),
                New SKPoint(rectPx.Left + fade, rectPx.Top),
                New SKColor() {
                    New SKColor(255, 255, 255, 10),
                    SKColors.Transparent
                },
                New Single() {0.0F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.Screen
                }
                    canvas.DrawRect(New SKRect(rectPx.Left, rectPx.Top, rectPx.Left + fade, rectPx.Bottom), p)
                End Using
            End Using

            ' Right
            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(rectPx.Right - fade, rectPx.Top),
                New SKPoint(rectPx.Right, rectPx.Top),
                New SKColor() {
                    SKColors.Transparent,
                    New SKColor(255, 255, 255, 8)
                },
                New Single() {0.0F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.Screen
                }
                    canvas.DrawRect(New SKRect(rectPx.Right - fade, rectPx.Top, rectPx.Right, rectPx.Bottom), p)
                End Using
            End Using

            canvas.Restore()
        End Sub

        Private Shared Sub DrawInnerWash(canvas As SKCanvas,
                                         rectPx As SKRect,
                                         radiusPx As Single,
                                         dpi As Single)

            Dim innerRect As SKRect = InsetRect(rectPx, 1.0F, 1.0F)

            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(innerRect.Left, innerRect.Top),
                New SKPoint(innerRect.Left, innerRect.Bottom),
                New SKColor() {
                    New SKColor(252, 253, 255, 38),
                    New SKColor(239, 244, 252, 18),
                    New SKColor(216, 228, 240, 10)
                },
                New Single() {0.0F, 0.5F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.SoftLight
                }
                    canvas.DrawRoundRect(
                        innerRect,
                        Math.Max(0.0F, radiusPx - 1.0F),
                        Math.Max(0.0F, radiusPx - 1.0F),
                        p
                    )
                End Using
            End Using
        End Sub

        Private Shared Sub DrawWovenTexture(canvas As SKCanvas,
                                            rectPx As SKRect,
                                            radiusPx As Single,
                                            dpi As Single)

            Dim spacingMain As Single = Math.Max(6.0F, 6.0F * dpi)
            Dim spacingCross As Single = spacingMain * 1.35F

            canvas.Save()
            canvas.ClipRoundRect(
                New SKRoundRect(rectPx, radiusPx, radiusPx),
                SKClipOperation.Intersect,
                antialias:=True
            )

            ' Bright threads
            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(0.7F, 0.7F * dpi),
                .Color = New SKColor(255, 255, 255, 18)
            }
                Dim x As Single = rectPx.Left - rectPx.Height
                While x < rectPx.Right
                    canvas.DrawLine(x, rectPx.Top, x + rectPx.Height, rectPx.Bottom, p)
                    x += spacingMain
                End While
            End Using

            ' Dark counter-threads
            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(0.5F, 0.5F * dpi),
                .Color = New SKColor(82, 102, 122, 10)
            }
                Dim x As Single = rectPx.Left
                While x < rectPx.Right + rectPx.Height
                    canvas.DrawLine(x, rectPx.Top, x - rectPx.Height, rectPx.Bottom, p)
                    x += spacingCross
                End While
            End Using

            ' Fine vertical polish streaks
            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(0.35F, 0.35F * dpi),
                .Color = New SKColor(255, 255, 255, 5)
            }
                Dim x As Single = rectPx.Left + (2.0F * dpi)
                While x < rectPx.Right
                    canvas.DrawLine(x, rectPx.Top, x, rectPx.Bottom, p)
                    x += Math.Max(10.0F, 10.0F * dpi)
                End While
            End Using

            canvas.Restore()
        End Sub

        Private Shared Sub DrawCenterGlow(canvas As SKCanvas,
                                          rectPx As SKRect,
                                          radiusPx As Single,
                                          dpi As Single)

            Dim cx As Single = rectPx.MidX
            Dim cy As Single = rectPx.Top + (rectPx.Height * 0.34F)
            Dim rad As Single = Math.Max(rectPx.Width, rectPx.Height) * 0.72F

            Using sh As SKShader = SKShader.CreateRadialGradient(
                New SKPoint(cx, cy),
                rad,
                New SKColor() {
                    New SKColor(255, 255, 255, 14),
                    New SKColor(245, 250, 255, 5),
                    SKColors.Transparent
                },
                New Single() {0.0F, 0.4F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .BlendMode = SKBlendMode.Screen,
                    .Shader = sh
                }
                    canvas.DrawRoundRect(rectPx, radiusPx, radiusPx, p)
                End Using
            End Using
        End Sub

        Private Shared Sub DrawBottomAnchor(canvas As SKCanvas,
                                            rectPx As SKRect,
                                            radiusPx As Single,
                                            dpi As Single)

            Dim settleRect As New SKRect(
                rectPx.Left,
                rectPx.Top + (rectPx.Height * 0.72F),
                rectPx.Right,
                rectPx.Bottom
            )

            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(settleRect.Left, settleRect.Top),
                New SKPoint(settleRect.Left, settleRect.Bottom),
                New SKColor() {
                    SKColors.Transparent,
                    New SKColor(142, 160, 180, 10),
                    New SKColor(112, 130, 150, 16)
                },
                New Single() {0.0F, 0.6F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh,
                    .BlendMode = SKBlendMode.Multiply
                }
                    canvas.Save()
                    canvas.ClipRoundRect(
                        New SKRoundRect(rectPx, radiusPx, radiusPx),
                        SKClipOperation.Intersect,
                        antialias:=True
                    )
                    canvas.DrawRect(settleRect, p)
                    canvas.Restore()
                End Using
            End Using
        End Sub

        Private Shared Sub DrawBorders(canvas As SKCanvas,
                                       rectPx As SKRect,
                                       radiusPx As Single,
                                       dpi As Single)

            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.0F, 1.0F * dpi),
                .Color = New SKColor(148, 165, 184, 128)
            }
                canvas.DrawRoundRect(rectPx, radiusPx, radiusPx, p)
            End Using

            Dim innerRect As SKRect = InsetRect(rectPx, 1.0F, 1.0F)
            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.0F, 1.0F * dpi),
                .Color = New SKColor(255, 255, 255, 68)
            }
                canvas.DrawRoundRect(
                    innerRect,
                    Math.Max(0.0F, radiusPx - 1.0F),
                    Math.Max(0.0F, radiusPx - 1.0F),
                    p
                )
            End Using

            ' Inner cool rim
            Dim innerRect2 As SKRect = InsetRect(rectPx, 2.0F, 2.0F)
            If innerRect2.Width > 2.0F AndAlso innerRect2.Height > 2.0F Then
                Using sh As SKShader = SKShader.CreateLinearGradient(
                    New SKPoint(innerRect2.Left, innerRect2.Top),
                    New SKPoint(innerRect2.Left, innerRect2.Bottom),
                    New SKColor() {
                        New SKColor(255, 255, 255, 18),
                        New SKColor(210, 225, 240, 10),
                        SKColors.Transparent
                    },
                    New Single() {0.0F, 0.42F, 1.0F},
                    SKShaderTileMode.Clamp
                )
                    Using p As New SKPaint With {
                        .IsAntialias = True,
                        .IsDither = True,
                        .Style = SKPaintStyle.Stroke,
                        .StrokeWidth = Math.Max(1.0F, 0.8F * dpi),
                        .Shader = sh
                    }
                        canvas.DrawRoundRect(
                            innerRect2,
                            Math.Max(0.0F, radiusPx - 2.0F),
                            Math.Max(0.0F, radiusPx - 2.0F),
                            p
                        )
                    End Using
                End Using
            End If
        End Sub

        Private Shared Sub DrawTopHairlineLift(canvas As SKCanvas,
                                               rectPx As SKRect,
                                               radiusPx As Single,
                                               dpi As Single)

            Dim h As Single = Math.Max(2.0F, 2.0F * dpi)
            Dim topRect As New SKRect(
                rectPx.Left + 1.0F,
                rectPx.Top + 1.0F,
                rectPx.Right - 1.0F,
                rectPx.Top + h
            )

            Using sh As SKShader = SKShader.CreateLinearGradient(
                New SKPoint(topRect.Left, topRect.Top),
                New SKPoint(topRect.Left, topRect.Bottom),
                New SKColor() {
                    New SKColor(255, 255, 255, 84),
                    New SKColor(255, 255, 255, 16)
                },
                New Single() {0.0F, 1.0F},
                SKShaderTileMode.Clamp
            )
                Using p As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .Shader = sh
                }
                    canvas.Save()
                    canvas.ClipRoundRect(
                        New SKRoundRect(rectPx, radiusPx, radiusPx),
                        SKClipOperation.Intersect,
                        antialias:=True
                    )
                    canvas.DrawRect(topRect, p)
                    canvas.Restore()
                End Using
            End Using
        End Sub

#End Region

#Region "Helpers"

        Private Shared Function InsetRect(r As SKRect, dx As Single, dy As Single) As SKRect
            Return New SKRect(r.Left + dx, r.Top + dy, r.Right - dx, r.Bottom - dy)
        End Function

#End Region

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

    End Class

End Namespace
