Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Rendering

    ''' <summary>
    ''' Friend-only painter for premium flat action tiles used by Nexamas UI-owned
    ''' tool surfaces. It is intentionally internal: controls may reuse the drawing
    ''' policy without creating a public MASFlatButton API or a parallel button route.
    ''' </summary>
    Friend NotInheritable Class MASFlatActionButtonPainter

        Private Sub New()
        End Sub

        Friend Shared Sub Draw(canvas As SKCanvas,
                               ctx As MASThemeContext,
                               palette As MASFlatActionButtonPalette,
                               spec As MASFlatActionButtonSpec)
            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If spec.Rect.Width <= 1.0F OrElse spec.Rect.Height <= 1.0F Then Return

            Dim dpi As Single = PixelSnap.SafeDpi(spec.Dpi)
            Dim r As SKRect = PixelSnap.SnapRectHalf(spec.Rect)
            Dim radius As Single = Math.Max(MASFlatActionButtonTokens.RadiusMinDip * dpi,
                                            r.Height * MASFlatActionButtonTokens.RadiusRatio)
            radius = PixelSnap.SafeRadius(radius)

            Dim state As MASFlatActionButtonResolvedState = ResolveState(palette, spec)

            If spec.Enabled AndAlso Not spec.IsPressed AndAlso state.ShadowAlpha > 0 Then
                Dim shadowRect As New SKRect(r.Left,
                                             r.Top + (MASFlatActionButtonTokens.ShadowOffsetDip * dpi),
                                             r.Right,
                                             r.Bottom + (MASFlatActionButtonTokens.ShadowOffsetDip * dpi))
                MASShadowPainter.DrawFlatRoundRectShadow(
                    canvas:=canvas,
                    rectPx:=shadowRect,
                    radiusPx:=radius,
                    color:=SKColors.Black.WithAlpha(state.ShadowAlpha))
            End If

            Using fill As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Fill,
                .Color = state.Fill
            }
                canvas.DrawRoundRect(r, radius, radius, fill)
            End Using

            Using stroke As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(0.8F, MASFlatActionButtonTokens.StrokeWidthDip * dpi),
                .Color = state.Stroke
            }
                canvas.DrawRoundRect(PixelSnap.InsetAll(r, 0.5F * dpi),
                                     Math.Max(1.0F, radius - 0.5F * dpi),
                                     Math.Max(1.0F, radius - 0.5F * dpi),
                                     stroke)
            End Using

            DrawGlyphAndLabel(canvas, ctx, r, spec, state.Icon, state.Text, dpi)
        End Sub

        Private Shared Function ResolveState(palette As MASFlatActionButtonPalette,
                                             spec As MASFlatActionButtonSpec) As MASFlatActionButtonResolvedState
            Dim fillAlpha As Byte = MASFlatActionButtonTokens.NormalFillAlpha
            Dim strokeAlpha As Byte = MASFlatActionButtonTokens.NormalStrokeAlpha
            Dim shadowAlpha As Byte = MASFlatActionButtonTokens.NormalShadowAlpha
            Dim iconColor As SKColor = palette.Icon.WithAlpha(MASFlatActionButtonTokens.NormalIconAlpha)
            Dim textColor As SKColor = palette.Text.WithAlpha(MASFlatActionButtonTokens.NormalTextAlpha)

            If spec.Emphasized Then
                fillAlpha = MASFlatActionButtonTokens.EmphasizedFillAlpha
                strokeAlpha = MASFlatActionButtonTokens.EmphasizedStrokeAlpha
            End If

            If Not spec.Enabled Then
                fillAlpha = MASFlatActionButtonTokens.DisabledFillAlpha
                strokeAlpha = MASFlatActionButtonTokens.DisabledStrokeAlpha
                shadowAlpha = 0
                iconColor = palette.Icon.WithAlpha(MASFlatActionButtonTokens.DisabledIconAlpha)
                textColor = palette.Text.WithAlpha(MASFlatActionButtonTokens.DisabledTextAlpha)
            ElseIf spec.IsPressed Then
                fillAlpha = MASFlatActionButtonTokens.PressedFillAlpha
                strokeAlpha = MASFlatActionButtonTokens.PressedStrokeAlpha
                shadowAlpha = MASFlatActionButtonTokens.PressedShadowAlpha
                iconColor = palette.IconPressed.WithAlpha(MASFlatActionButtonTokens.NormalIconAlpha)
                textColor = palette.Text.WithAlpha(MASFlatActionButtonTokens.NormalTextAlpha)
            ElseIf spec.IsHover Then
                fillAlpha = MASFlatActionButtonTokens.HoverFillAlpha
                strokeAlpha = MASFlatActionButtonTokens.HoverStrokeAlpha
                shadowAlpha = MASFlatActionButtonTokens.HoverShadowAlpha
                iconColor = palette.IconHover.WithAlpha(MASFlatActionButtonTokens.NormalIconAlpha)
                textColor = palette.Text.WithAlpha(MASFlatActionButtonTokens.NormalTextAlpha)
            End If

            Dim fillBase As SKColor = palette.Fill
            If fillBase.Alpha = 0 Then fillBase = New SKColor(230, 240, 248, 255)
            fillBase = ColorMath.Mix(fillBase, palette.SurfaceFill, 0.18F)

            Dim strokeBase As SKColor = palette.Stroke
            If strokeBase.Alpha = 0 Then strokeBase = palette.SurfaceStroke

            Return New MASFlatActionButtonResolvedState With {
                .Fill = ColorMath.WithAlpha(fillBase, fillAlpha),
                .Stroke = ColorMath.WithAlpha(strokeBase, strokeAlpha),
                .Icon = iconColor,
                .Text = textColor,
                .ShadowAlpha = shadowAlpha
            }
        End Function

        Private Shared Sub DrawGlyphAndLabel(canvas As SKCanvas,
                                             ctx As MASThemeContext,
                                             rect As SKRect,
                                             spec As MASFlatActionButtonSpec,
                                             iconColor As SKColor,
                                             textColor As SKColor,
                                             dpi As Single)
            If spec.Compact Then
                Dim iconInset As Single = Math.Max(MASFlatActionButtonTokens.CompactIconInsetMinDip * dpi,
                                                   rect.Height * MASFlatActionButtonTokens.CompactIconInsetRatio)
                Dim iconRect As SKRect = PixelSnap.InsetAll(rect, iconInset)
                DrawGlyph(canvas, iconRect, dpi, spec.Glyph, iconColor)
                Return
            End If

            Dim iconTopInsetDip As Single = If(spec.IconTopInsetDip > 0.0F,
                                                 spec.IconTopInsetDip,
                                                 MASFlatActionButtonTokens.IconTopInsetDip)
            Dim iconAreaHeightRatio As Single = If(spec.IconAreaHeightRatio > 0.0F,
                                                   spec.IconAreaHeightRatio,
                                                   MASFlatActionButtonTokens.IconAreaHeightRatio)
            Dim iconSizeRatio As Single = If(spec.IconSizeRatio > 0.0F,
                                             spec.IconSizeRatio,
                                             MASFlatActionButtonTokens.IconSizeRatio)
            Dim iconSizeMinDip As Single = If(spec.IconSizeMinDip > 0.0F,
                                             spec.IconSizeMinDip,
                                             MASFlatActionButtonTokens.IconSizeMinDip)
            Dim iconSizeMaxDip As Single = If(spec.IconSizeMaxDip > 0.0F,
                                             spec.IconSizeMaxDip,
                                             MASFlatActionButtonTokens.IconSizeMaxDip)

            Dim iconArea As New SKRect(rect.Left,
                                       rect.Top + (iconTopInsetDip * dpi),
                                       rect.Right,
                                       rect.Top + rect.Height * iconAreaHeightRatio)
            Dim iconSize As Single = Math.Min(iconArea.Width, iconArea.Height) * iconSizeRatio
            iconSize = Math.Max(iconSizeMinDip * dpi,
                                Math.Min(iconSizeMaxDip * dpi, iconSize))
            Dim iconRectWide As New SKRect(iconArea.MidX - (iconSize * 0.5F),
                                           iconArea.MidY - (iconSize * 0.5F),
                                           iconArea.MidX + (iconSize * 0.5F),
                                           iconArea.MidY + (iconSize * 0.5F))

            DrawGlyph(canvas, iconRectWide, dpi, spec.Glyph, iconColor)

            Dim label As String = If(spec.Label, String.Empty)
            If label.Length = 0 Then Return

            Dim labelTopRatio As Single = If(spec.LabelTopRatio > 0.0F,
                                             spec.LabelTopRatio,
                                             MASFlatActionButtonTokens.LabelTopRatio)
            Dim labelBottomInsetDip As Single = If(spec.LabelBottomInsetDip > 0.0F,
                                                spec.LabelBottomInsetDip,
                                                MASFlatActionButtonTokens.LabelBottomInsetDip)
            Dim labelRect As New SKRect(rect.Left + (MASFlatActionButtonTokens.LabelSideInsetDip * dpi),
                                        rect.Top + rect.Height * labelTopRatio,
                                        rect.Right - (MASFlatActionButtonTokens.LabelSideInsetDip * dpi),
                                        rect.Bottom - (labelBottomInsetDip * dpi))
            TypographyTextPrimitives.DrawSingleLineText(
                canvas:=canvas,
                ctx:=ctx,
                text:=label,
                bounds:=labelRect,
                dpi:=dpi,
                style:=MASTypography.MASTextStyle.Button,
                color:=textColor,
                align:=TypographyTextPrimitives.TextAlign.Center,
                drawShadow:=False)
        End Sub

        Private Shared Sub DrawGlyph(canvas As SKCanvas,
                                     iconRect As SKRect,
                                     dpi As Single,
                                     glyph As MASFlatActionButtonGlyphKind,
                                     color As SKColor)
            Select Case glyph
                Case MASFlatActionButtonGlyphKind.ZoomIn
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.ZoomIn, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.ZoomOut
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.ZoomOut, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.Fit
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.Expand, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.RotateRight
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.RotateRight, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.Export
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.Export, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.ResetView
                    MASIconPainter.Draw(canvas, iconRect, dpi, MASIconKind.ResetView, color, MASIconStyle.Outline)

                Case MASFlatActionButtonGlyphKind.FlipHorizontal
                    DrawFlipGlyph(canvas, iconRect, dpi, color)
            End Select
        End Sub

        Private Shared Sub DrawFlipGlyph(canvas As SKCanvas,
                                         iconRect As SKRect,
                                         dpi As Single,
                                         color As SKColor)
            If canvas Is Nothing Then Return
            If iconRect.Width <= 1.0F OrElse iconRect.Height <= 1.0F Then Return

            Dim safeDpi As Single = PixelSnap.SafeDpi(dpi)
            Dim stroke As Single = Math.Max(1.2F, 1.4F * safeDpi)
            Dim cx As Single = iconRect.MidX
            Dim top As Single = iconRect.Top + iconRect.Height * 0.16F
            Dim bottom As Single = iconRect.Bottom - iconRect.Height * 0.16F
            Dim left As Single = iconRect.Left + iconRect.Width * 0.12F
            Dim right As Single = iconRect.Right - iconRect.Width * 0.12F
            Dim arrow As Single = Math.Max(4.0F * safeDpi, iconRect.Width * 0.14F)

            Using p As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = stroke,
                .Color = color,
                .StrokeCap = SKStrokeCap.Round,
                .StrokeJoin = SKStrokeJoin.Round
            }
                canvas.DrawLine(cx, top, cx, bottom, p)
                canvas.DrawLine(left, iconRect.MidY, cx - arrow, iconRect.MidY, p)
                canvas.DrawLine(left + arrow, iconRect.MidY - arrow, left, iconRect.MidY, p)
                canvas.DrawLine(left + arrow, iconRect.MidY + arrow, left, iconRect.MidY, p)

                canvas.DrawLine(cx + arrow, iconRect.MidY, right, iconRect.MidY, p)
                canvas.DrawLine(right - arrow, iconRect.MidY - arrow, right, iconRect.MidY, p)
                canvas.DrawLine(right - arrow, iconRect.MidY + arrow, right, iconRect.MidY, p)
            End Using
        End Sub

    End Class

    Friend Enum MASFlatActionButtonGlyphKind
        None = 0
        ZoomIn = 1
        ZoomOut = 2
        Fit = 3
        RotateRight = 4
        FlipHorizontal = 5
        Export = 6
        ResetView = 7
    End Enum

    Friend Structure MASFlatActionButtonPalette
        Friend Fill As SKColor
        Friend Stroke As SKColor
        Friend SurfaceFill As SKColor
        Friend SurfaceStroke As SKColor
        Friend Icon As SKColor
        Friend IconHover As SKColor
        Friend IconPressed As SKColor
        Friend Text As SKColor
    End Structure

    Friend Structure MASFlatActionButtonSpec
        Friend Rect As SKRect
        Friend Glyph As MASFlatActionButtonGlyphKind
        Friend Label As String
        Friend Dpi As Single
        Friend Compact As Boolean
        Friend Enabled As Boolean
        Friend IsHover As Boolean
        Friend IsPressed As Boolean
        Friend IconTopInsetDip As Single
        Friend IconAreaHeightRatio As Single
        Friend IconSizeRatio As Single
        Friend IconSizeMinDip As Single
        Friend IconSizeMaxDip As Single
        Friend LabelTopRatio As Single
        Friend LabelBottomInsetDip As Single
        Friend Emphasized As Boolean
    End Structure

    Friend Structure MASFlatActionButtonResolvedState
        Friend Fill As SKColor
        Friend Stroke As SKColor
        Friend Icon As SKColor
        Friend Text As SKColor
        Friend ShadowAlpha As Byte
    End Structure

    Friend NotInheritable Class MASFlatActionButtonTokens

        Private Sub New()
        End Sub

        Friend Const NormalFillAlpha As Byte = 0
        Friend Const HoverFillAlpha As Byte = 86
        Friend Const PressedFillAlpha As Byte = 116
        Friend Const DisabledFillAlpha As Byte = 0
        Friend Const EmphasizedFillAlpha As Byte = 52

        Friend Const NormalStrokeAlpha As Byte = 0
        Friend Const HoverStrokeAlpha As Byte = 92
        Friend Const PressedStrokeAlpha As Byte = 112
        Friend Const DisabledStrokeAlpha As Byte = 0
        Friend Const EmphasizedStrokeAlpha As Byte = 54

        Friend Const NormalShadowAlpha As Byte = 0
        Friend Const HoverShadowAlpha As Byte = 0
        Friend Const PressedShadowAlpha As Byte = 0

        Friend Const NormalIconAlpha As Byte = 224
        Friend Const NormalTextAlpha As Byte = 214
        Friend Const DisabledIconAlpha As Byte = 92
        Friend Const DisabledTextAlpha As Byte = 104

        Friend Const RadiusMinDip As Single = 6.0F
        Friend Const RadiusRatio As Single = 0.18F
        Friend Const StrokeWidthDip As Single = 1.0F
        Friend Const ShadowOffsetDip As Single = 0.0F

        Friend Const CompactIconInsetMinDip As Single = 7.0F
        Friend Const CompactIconInsetRatio As Single = 0.24F
        Friend Const IconTopInsetDip As Single = 4.0F
        Friend Const IconAreaHeightRatio As Single = 0.54F
        Friend Const IconSizeRatio As Single = 0.66F
        Friend Const IconSizeMinDip As Single = 16.5F
        Friend Const IconSizeMaxDip As Single = 27.0F
        Friend Const LabelTopRatio As Single = 0.58F
        Friend Const LabelSideInsetDip As Single = 4.0F
        Friend Const LabelBottomInsetDip As Single = 4.0F

    End Class

End Namespace
