Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Controls

    Partial Public NotInheritable Class MASSidePanel

#Region "Panel / close action motion"

        Private _sidePanelRevealRunner As MASMotionTimelineRunner
        Private _sidePanelRevealProgress As Single = 1.0F
        Private _hasSidePanelRevealMotion As Boolean

        Private _sidePanelCloseButtonRunner As MASMotionTimelineRunner
        Private _sidePanelCloseButtonProgress As Single = 1.0F
        Private _hasSidePanelCloseButtonMotion As Boolean

        Friend Sub StartSidePanelRevealMotion()
            If _disposedLocal Then Return

            StopSidePanelRevealMotion(resetState:=False)
            _sidePanelRevealProgress = 0.0F
            _hasSidePanelRevealMotion = True

            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.PanelReveal, 0.0F, 1.0F)
            If Not plan.ShouldAnimate Then
                CompleteSidePanelRevealMotionFrame(Nothing)
                Return
            End If

            _sidePanelRevealRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASSidePanel.PanelReveal",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplySidePanelRevealMotionFrame,
                completed:=AddressOf CompleteSidePanelRevealMotionFrame)
            _sidePanelRevealRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplySidePanelRevealMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _sidePanelRevealProgress = MASMotionSystem.ClampProgress(frame.EasedProgress)
            _hasSidePanelRevealMotion = True
            InvalidateVisual()
        End Sub

        Private Sub CompleteSidePanelRevealMotionFrame(frame As MASMotionFrame)
            StopSidePanelRevealMotion(resetState:=True)
            InvalidateVisual()
        End Sub

        Private Sub StopSidePanelRevealMotion(resetState As Boolean)
            If _sidePanelRevealRunner IsNot Nothing Then
                _sidePanelRevealRunner.Dispose()
                _sidePanelRevealRunner = Nothing
            End If

            If resetState Then
                _sidePanelRevealProgress = 1.0F
                _hasSidePanelRevealMotion = False
            End If
        End Sub

        Private Function IsSidePanelRevealMotionActive() As Boolean
            Return _hasSidePanelRevealMotion AndAlso _sidePanelRevealRunner IsNot Nothing AndAlso _sidePanelRevealRunner.IsRunning
        End Function

        Private Sub StartSidePanelCloseButtonMotion()
            If _disposedLocal Then Return

            StopSidePanelCloseButtonMotion(resetState:=False)
            _sidePanelCloseButtonProgress = 0.0F
            _hasSidePanelCloseButtonMotion = True

            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.PressRelease, 0.0F, 1.0F)
            If Not plan.ShouldAnimate Then
                CompleteSidePanelCloseButtonMotionFrame(Nothing)
                Return
            End If

            _sidePanelCloseButtonRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASSidePanel.CloseButton",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplySidePanelCloseButtonMotionFrame,
                completed:=AddressOf CompleteSidePanelCloseButtonMotionFrame)
            _sidePanelCloseButtonRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplySidePanelCloseButtonMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _sidePanelCloseButtonProgress = MASMotionSystem.ClampProgress(frame.EasedProgress)
            _hasSidePanelCloseButtonMotion = True
            InvalidateVisual()
        End Sub

        Private Sub CompleteSidePanelCloseButtonMotionFrame(frame As MASMotionFrame)
            StopSidePanelCloseButtonMotion(resetState:=True)
            InvalidateVisual()
        End Sub

        Private Sub StopSidePanelCloseButtonMotion(resetState As Boolean)
            If _sidePanelCloseButtonRunner IsNot Nothing Then
                _sidePanelCloseButtonRunner.Dispose()
                _sidePanelCloseButtonRunner = Nothing
            End If

            If resetState Then
                _sidePanelCloseButtonProgress = 1.0F
                _hasSidePanelCloseButtonMotion = False
            End If
        End Sub

        Private Function IsSidePanelCloseButtonMotionActive() As Boolean
            Return _hasSidePanelCloseButtonMotion AndAlso _sidePanelCloseButtonRunner IsNot Nothing AndAlso _sidePanelCloseButtonRunner.IsRunning
        End Function

        Private Sub DrawSidePanelRevealMotionOverlay(canvas As SKCanvas,
                                                     ctx As MASThemeContext,
                                                     bounds As SKRect,
                                                     dpi As Single)
            If canvas Is Nothing OrElse Not IsSidePanelRevealMotionActive() Then Return
            If bounds.Width <= 1.0F OrElse bounds.Height <= 1.0F Then Return

            Dim fade As Single = 1.0F - MASMotionSystem.ClampProgress(_sidePanelRevealProgress)
            If fade <= 0.001F Then Return

            Dim alpha As Byte = CByte(Math.Max(0, Math.Min(72, CInt(Math.Round(54.0R * CDbl(fade))))))
            Dim accent As SKColor = ResolveSidePanelMotionAccent(ctx).WithAlpha(alpha)
            Dim radius As Single = Math.Max(12.0F * dpi, DrawerTokens.CloseButtonRadiusDip * dpi)

            Using fill As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Fill,
                .Color = accent,
                .BlendMode = SKBlendMode.SrcOver
            }
                canvas.DrawRoundRect(bounds, radius, radius, fill)
            End Using
        End Sub

        Private Sub DrawSidePanelCloseButtonPulse(canvas As SKCanvas,
                                                  ctx As MASThemeContext,
                                                  buttonRect As SKRect,
                                                  dpi As Single)
            If canvas Is Nothing OrElse Not IsSidePanelCloseButtonMotionActive() Then Return
            If buttonRect.Width <= 1.0F OrElse buttonRect.Height <= 1.0F Then Return

            Dim progress As Single = MASMotionSystem.ClampProgress(_sidePanelCloseButtonProgress)
            Dim fade As Single = 1.0F - progress
            If fade <= 0.001F Then Return

            Dim alpha As Byte = CByte(Math.Max(0, Math.Min(96, CInt(Math.Round(72.0R * CDbl(fade))))))
            Dim inflate As Single = progress * 2.0F * dpi
            Dim pulseBounds As New SKRect(buttonRect.Left - inflate,
                                          buttonRect.Top - inflate,
                                          buttonRect.Right + inflate,
                                          buttonRect.Bottom + inflate)
            Dim radius As Single = (DrawerTokens.CloseButtonRadiusDip + 2.0F) * dpi

            Using paint As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.0F, 1.25F * dpi),
                .Color = ResolveSidePanelMotionAccent(ctx).WithAlpha(alpha),
                .BlendMode = SKBlendMode.SrcOver
            }
                canvas.DrawRoundRect(pulseBounds, radius, radius, paint)
            End Using
        End Sub

        Private Shared Function ResolveSidePanelMotionAccent(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.BrandTheme IsNot Nothing Then Return ctx.BrandTheme.BrandPrimary
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Info
            Return Nexamas.UI.Values.Color.Accent.Accent2
        End Function

#End Region

    End Class

End Namespace
