Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Rendering

    Friend NotInheritable Class MASPanelShellHeaderPainter

        Private Sub New()
        End Sub

        Friend Shared Sub Draw(canvas As SKCanvas,
                       ctx As MASThemeContext,
                       dpi As Single,
                       style As MASPanelShellResolvedStyle,
                       spec As MASPanelShellSpec,
                       result As MASPanelShellResult,
                       contract As MASResolvedComponentContract)

            If canvas Is Nothing OrElse ctx Is Nothing OrElse style Is Nothing OrElse style.SurfaceTheme Is Nothing Then Return
            If spec Is Nothing OrElse spec.Header Is Nothing OrElse result Is Nothing Then Return
            If result.HeaderRectPx.IsEmpty Then Return

            If contract Is Nothing Then Throw New ArgumentNullException(NameOf(contract))

            Dim scope As MASContractRenderScope =
    MASArchitectureRuntime.CreateRenderScopeForComponent(Of MASPanelShellContract)(
        NameOf(MASPanelShellHeaderPainter),
        contract,
        MASRenderLayer.Surface,
        MASRenderLayer.Text)

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

            dpi = PixelSnap.SafeDpi(dpi)

            Dim chromeContext As MASSurfaceChromeContext =
                MASSurfaceMaterialComponentGateway.CreatePanelShellHeaderChromeContext(
                    themeContext:=ctx,
                    surfaceTheme:=style.SurfaceTheme,
                    materialKey:=style.ResolvedMaterialKey,
                    boundsPx:=result.HeaderRectPx,
                    baseBoundsPx:=result.BaseRectPx,
                    cornerRadiusPx:=result.RadiusPx,
                    borderStrengthLevel:=style.BorderStrengthLevel,
                    surfaceStrengthLevel:=style.SurfaceStrengthLevel,
                    dpi:=dpi,
                    visualStyle:=style.VisualStyle,
                    visualState:=MASSurfaceVisualState.Normal)

            Dim chromePlan As MASSurfaceHeaderChromePlan =
                MASSurfaceHeaderChromePlanner.Resolve(chromeContext)

            DrawBackground(canvas, chromePlan, spec, result)
            DrawHeaderAccents(canvas, dpi, chromePlan, spec, result)

            If spec.Header.ShowIcon Then
                DrawIcon(canvas, dpi, chromePlan, spec, result)
            End If

            DrawText(canvas, ctx, dpi, chromePlan, spec, result)

            If spec.Header.ShowCloseButton Then
                DrawCloseButton(canvas, ctx, dpi, chromePlan, spec, result, contract)
            End If

            If spec.Header.DrawSeparator Then
                DrawSeparator(canvas, dpi, chromePlan, result)
            End If
        End Sub

        Private Shared Sub DrawBackground(canvas As SKCanvas,
                                          plan As MASSurfaceHeaderChromePlan,
                                          spec As MASPanelShellSpec,
                                          result As MASPanelShellResult)

            MASSurfaceHeaderChromePainter.DrawBackground(
    canvas:=canvas,
    headerRectPx:=result.HeaderRectPx,
    baseRectPx:=result.BaseRectPx,
    cornerRadiusPx:=result.RadiusPx,
    plan:=plan,
    shouldDrawGloss:=spec.Header.DrawGloss)
        End Sub

        Private Shared Sub DrawSeparator(canvas As SKCanvas,
                                         dpi As Single,
                                         plan As MASSurfaceHeaderChromePlan,
                                         result As MASPanelShellResult)

            MASSurfaceHeaderChromePainter.DrawSeparator(
                canvas:=canvas,
                headerRectPx:=result.HeaderRectPx,
                baseRectPx:=result.BaseRectPx,
                cornerRadiusPx:=result.RadiusPx,
                dpi:=dpi,
                plan:=plan)
        End Sub


        Private Shared Sub DrawHeaderAccents(canvas As SKCanvas,
                                             dpi As Single,
                                             plan As MASSurfaceHeaderChromePlan,
                                             spec As MASPanelShellSpec,
                                             result As MASPanelShellResult)

            If canvas Is Nothing OrElse spec Is Nothing OrElse result Is Nothing Then Return
            If spec.Header Is Nothing OrElse result.HeaderRectPx.IsEmpty Then Return
            If Not spec.Header.DrawCrown AndAlso _
               Not spec.Header.DrawSeam AndAlso _
               Not spec.Header.DrawInnerRim Then Return

            dpi = PixelSnap.SafeDpi(dpi)

            Dim headerRect As SKRect = result.HeaderRectPx
            Dim baseRect As SKRect = result.BaseRectPx
            Dim radiusPx As Single = Math.Max(0.0F, result.RadiusPx)

            MASVisualPrimitivesPainter.WithClipRoundRect(canvas, baseRect, radiusPx,
                Sub()
                    If spec.Header.DrawCrown AndAlso plan.DividerLight.Alpha > 0 Then
                        Dim y As Single = PixelSnap.Snap(headerRect.Top + Math.Max(0.75F, dpi * 0.65F), 0.5F)
                        Dim xInset As Single = Math.Max(4.0F * dpi, Math.Min(radiusPx * 0.42F, headerRect.Width * 0.18F))

                        Using crownPaint As New SKPaint With {
                            .IsAntialias = True,
                            .IsDither = True,
                            .Style = SKPaintStyle.Stroke,
                            .StrokeWidth = Math.Max(0.75F, dpi * 0.75F),
                            .StrokeCap = SKStrokeCap.Round,
                            .Color = ColorMath.WithAlpha(plan.DividerLight, CByte(Math.Min(86, Math.Max(18, CInt(plan.DividerLight.Alpha)))))
                        }
                            canvas.DrawLine(headerRect.Left + xInset, y, headerRect.Right - xInset, y, crownPaint)
                        End Using
                    End If

                    If spec.Header.DrawSeam AndAlso plan.DividerDark.Alpha > 0 Then
                        Dim y As Single = PixelSnap.Snap(headerRect.Bottom - Math.Max(1.25F, dpi * 1.1F), 0.5F)

                        Using seamPaint As New SKPaint With {
                            .IsAntialias = True,
                            .IsDither = True,
                            .Style = SKPaintStyle.Stroke,
                            .StrokeWidth = Math.Max(0.65F, dpi * 0.65F),
                            .StrokeCap = SKStrokeCap.Square,
                            .Color = ColorMath.WithAlpha(plan.DividerDark, CByte(Math.Min(64, Math.Max(16, CInt(plan.DividerDark.Alpha)))))
                        }
                            canvas.DrawLine(headerRect.Left, y, headerRect.Right, y, seamPaint)
                        End Using
                    End If

                    If spec.Header.DrawInnerRim AndAlso plan.Glow.Alpha > 0 Then
                        Dim rimRect As SKRect = headerRect
                        Dim inset As Single = Math.Max(0.75F, dpi * 0.75F)
                        rimRect.Inflate(-inset, -inset)

                        If PixelSnap.HasArea(rimRect, 0.5F) Then
                            Using rimPaint As New SKPaint With {
                                .IsAntialias = True,
                                .IsDither = True,
                                .Style = SKPaintStyle.Stroke,
                                .StrokeWidth = Math.Max(0.55F, dpi * 0.55F),
                                .StrokeJoin = SKStrokeJoin.Round,
                                .Color = ColorMath.WithAlpha(plan.Glow, CByte(Math.Min(48, Math.Max(12, CInt(plan.Glow.Alpha)))))
                            }
                                canvas.DrawRoundRect(
                                    MASSurfaceMaterialPaintUtils.RoundRect(
                                        rimRect,
                                        Math.Max(0.0F, radiusPx - inset)),
                                    rimPaint)
                            End Using
                        End If
                    End If
                End Sub)

        End Sub

        Private Shared Sub DrawIcon(canvas As SKCanvas,
                                    dpi As Single,
                                    plan As MASSurfaceHeaderChromePlan,
                                    spec As MASPanelShellSpec,
                                    result As MASPanelShellResult)

            If result.HeaderIconRectPx.IsEmpty Then Return

            Dim col As SKColor =
                If(spec.Header.IconColorOverride.HasValue,
                   spec.Header.IconColorOverride.Value,
                   plan.TextIcon)

            MASIconPainter.Draw(
                canvas:=canvas,
                bounds:=PixelSnap.SnapRectHalf(result.HeaderIconRectPx),
                dpi:=dpi,
                kind:=spec.Header.IconKind,
                color:=col,
                style:=spec.Header.IconStyle)
        End Sub

        Private Shared Sub DrawText(canvas As SKCanvas,
                                    ctx As MASThemeContext,
                                    dpi As Single,
                                    plan As MASSurfaceHeaderChromePlan,
                                    spec As MASPanelShellSpec,
                                    result As MASPanelShellResult)

            If ctx.Typography Is Nothing Then Return
            If String.IsNullOrWhiteSpace(spec.Header.Title) Then Return
            If result.HeaderTitleRectPx.IsEmpty Then Return

            TypographyTextPrimitives.DrawSingleLineText(
                canvas:=canvas,
                typography:=ctx.Typography,
                text:=spec.Header.Title,
                bounds:=result.HeaderTitleRectPx,
                dpi:=dpi,
                style:=MASTypography.MASTextStyle.Title,
                color:=plan.TextTitle,
                align:=TypographyTextPrimitives.TextAlign.Left,
                drawShadow:=False)

            If Not String.IsNullOrWhiteSpace(spec.Header.Subtitle) AndAlso
               Not result.HeaderSubtitleRectPx.IsEmpty Then

                TypographyTextPrimitives.DrawSingleLineText(
                    canvas:=canvas,
                    typography:=ctx.Typography,
                    text:=spec.Header.Subtitle,
                    bounds:=result.HeaderSubtitleRectPx,
                    dpi:=dpi,
                    style:=MASTypography.MASTextStyle.Small,
                    color:=plan.TextSubtitle,
                    align:=TypographyTextPrimitives.TextAlign.Left,
                    drawShadow:=False)
            End If
        End Sub

        Private Shared Sub DrawCloseButton(canvas As SKCanvas,
                                   ctx As MASThemeContext,
                                   dpi As Single,
                                   plan As MASSurfaceHeaderChromePlan,
                                   spec As MASPanelShellSpec,
                                   result As MASPanelShellResult,
                                   contract As MASResolvedComponentContract)

            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If spec Is Nothing OrElse result Is Nothing Then Return

            Dim r As SKRect = PixelSnap.SnapRectHalf(result.HeaderCloseRectPx)
            If r.IsEmpty Then Return

            Dim masState As MASInteractionState =
    ResolveCloseButtonMASInteractionState(
        isPressed:=spec.Header.ClosePressed,
        isHover:=spec.Header.CloseHover)

            If masState <> MASInteractionState.Enabled AndAlso ctx.Theme IsNot Nothing Then
                Dim overlaySpec As MASVisualInteractionOverlaySpec =
        MASInteractionResolver.Build(
            contract:=contract,
            state:=masState,
            theme:=ctx.Theme)

                If overlaySpec.FillEnabled OrElse overlaySpec.RingEnabled Then
                    MASSurfaceInteractionRing.DrawOverlay(
            canvas:=canvas,
            baseRectPx:=r,
            contract:=contract,
            spec:=overlaySpec,
            dpi:=dpi)
                End If
            End If

            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.4F, 1.6F * dpi),
                .StrokeCap = SKStrokeCap.Round,
                .Color = ColorMath.WithAlpha(plan.TextTitle, 210)
            }
                Dim inset As Single = Math.Max(6.0F * dpi, r.Width * 0.32F)

                canvas.DrawLine(r.Left + inset, r.Top + inset, r.Right - inset, r.Bottom - inset, p)
                canvas.DrawLine(r.Right - inset, r.Top + inset, r.Left + inset, r.Bottom - inset, p)
            End Using
        End Sub

        Private Shared Function ResolveCloseButtonMASInteractionState(isPressed As Boolean,
                                                              isHover As Boolean) As MASInteractionState

            If isPressed Then Return MASInteractionState.Pressed
            If isHover Then Return MASInteractionState.Hovered

            Return MASInteractionState.Enabled
        End Function

    End Class

End Namespace
