Option Strict On
Option Explicit On

Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
Imports Nexamas.UI.Components
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Theming
Imports SkiaSharp
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Rendering

Namespace Nexamas.UI.Controls

    <DefaultEvent("Click"),
     DefaultProperty("VisualStyle"),
     ToolboxItem(True)>
    Public NotInheritable Class MASCard
        Inherits MASWinControlBase
        Implements IMASIntrinsicSizeContract
        Implements IMASSurfaceLayoutContract
        Implements IMASLayoutParticipant

        Private Shared ReadOnly _contract As MASResolvedComponentContract =
    MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASCard))

        Private ReadOnly _painter As CardPainter
        Private _visualStyle As MASCardVisualStyle = MASCardVisualStyle.Default
        Private _surfaceMaterialKey As String = MASSurfaceMaterialIds.Auto
        Private _disposed As Boolean

        Public Sub New()
            _painter = New CardPainter()

            Margin = New Padding(8)
            Padding = New Padding(16)
            BackColor = Color.Transparent
        End Sub

#Region "Factories"

        Public Shared Function Create() As MASCard
            Return New MASCard()
        End Function

#End Region


#Region "MASSize / Surface Layout Contracts"

        Friend Function GetPreferredLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetPreferredLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).DesiredSize
        End Function

        Friend Function GetMinLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetMinLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).MinSize
        End Function

        Friend Function MeasureIntrinsicSize(context As MASSizeContext, intent As MASSize) As MASSizeResult Implements IMASIntrinsicSizeContract.MeasureIntrinsicSize
            Return MeasureSurfaceLayout(context, ResolveAvailableSurfaceSize(context), intent)
        End Function

        Private Function MeasureSurfaceLayout(context As MASSizeContext,
                                              availableSize As SKSize,
                                              intent As MASSize) As MASSizeResult Implements IMASSurfaceLayoutContract.MeasureSurfaceLayout
            Dim safeContext As MASSizeContext = EnsureSurfaceSizeContext(context, availableSize)
            Return MASSurfaceLayoutSizeResolver.Resolve(MASSurfaceLayoutKind.Card, safeContext, availableSize, intent)
        End Function

        Private Shared Function EnsureSurfaceSizeContext(context As MASSizeContext, availableSize As SKSize) As MASSizeContext
            If context IsNot Nothing Then Return context
            Return New MASSizeContext(ResolveAvailableSurfaceSize(Nothing, availableSize))
        End Function

        Private Shared Function CreateSizeContext(context As MASLayoutMeasureContext) As MASSizeContext
            If context Is Nothing Then Return New MASSizeContext(New SKSize(Single.PositiveInfinity, Single.PositiveInfinity))
            Return context.ToSizeContext(context.AvailableSize)
        End Function

        Private Shared Function ResolveAvailableSurfaceSize(context As MASSizeContext) As SKSize
            Return ResolveAvailableSurfaceSize(context, SKSize.Empty)
        End Function

        Private Shared Function ResolveAvailableSurfaceSize(context As MASSizeContext, availableSize As SKSize) As SKSize
            Dim width As Single = availableSize.Width
            Dim height As Single = availableSize.Height

            If (Single.IsNaN(width) OrElse width <= 0.0F OrElse Single.IsNegativeInfinity(width)) AndAlso context IsNot Nothing Then width = context.AvailableSize.Width
            If (Single.IsNaN(height) OrElse height <= 0.0F OrElse Single.IsNegativeInfinity(height)) AndAlso context IsNot Nothing Then height = context.AvailableSize.Height
            If Single.IsNaN(width) OrElse width <= 0.0F OrElse Single.IsNegativeInfinity(width) Then width = Single.PositiveInfinity
            If Single.IsNaN(height) OrElse height <= 0.0F OrElse Single.IsNegativeInfinity(height) Then height = Single.PositiveInfinity

            Return New SKSize(width, height)
        End Function

#End Region

#Region "Public API"

        Friend Overloads Sub SetBounds(bounds As SKRect)
            SetBounds(bounds.Left, bounds.Top, bounds.Width, bounds.Height)
        End Sub

        Friend Overloads Sub SetBounds(x As Single,
                             y As Single,
                             width As Single,
                             height As Single)

            MyBase.SetBounds(
                CInt(Math.Round(x)),
                CInt(Math.Round(y)),
                CInt(Math.Round(Math.Max(0.0F, width))),
                CInt(Math.Round(Math.Max(0.0F, height)))
            )
        End Sub

        Friend Function WithBounds(bounds As SKRect) As MASCard
            Return WithBounds(bounds.Left, bounds.Top, bounds.Width, bounds.Height)
        End Function

        Friend Function WithBounds(x As Single,
                                   y As Single,
                                   width As Single,
                                   height As Single) As MASCard

            SetBounds(x, y, width, height)
            Return Me
        End Function

        Public Function WithVisualStyle(value As MASCardVisualStyle) As MASCard
            VisualStyle = value
            Return Me
        End Function

        Public Function WithSurfaceMaterial(materialKey As String) As MASCard
            SurfaceMaterial = materialKey
            Return Me
        End Function

#End Region

        <Category("Nexamas UI"),
         Description("Card visual style."),
         DefaultValue(GetType(MASCardVisualStyle), "Default")>
        Public Property VisualStyle As MASCardVisualStyle
            Get
                Return _visualStyle
            End Get
            Set(value As MASCardVisualStyle)
                If _visualStyle = value Then Return
                _visualStyle = value
                RequestSurfaceInvalidate()
            End Set
        End Property

        <Category("Nexamas UI"),
         Description("Optional Surface Treatment material key. Auto preserves the current card visual."),
         DefaultValue(GetType(String), "auto")>
        Public Property SurfaceMaterial As String
            Get
                Return _surfaceMaterialKey
            End Get
            Set(value As String)
                Dim key As String = MASSurfaceTreatmentMaterialKeyNormalizer.NormalizeForStorage(value)
                If String.Equals(_surfaceMaterialKey, key, StringComparison.OrdinalIgnoreCase) Then Return
                _surfaceMaterialKey = key
                RequestSurfaceInvalidate()
            End Set
        End Property

        Protected Overrides Sub RenderControl(canvas As SKCanvas,
                                              info As SKImageInfo,
                                              ctx As MASThemeContext)

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

            canvas.Clear(SKColors.Transparent)

            Dim rPx As New SKRect(0.0F, 0.0F, info.Width, info.Height)

            _painter.Draw(
                canvas:=canvas,
                ctx:=ctx,
                rPx:=rPx,
                dpi:=ctx.Dpi,
                visualStyle:=_visualStyle,
                surfaceMaterialKey:=_surfaceMaterialKey
            )
        End Sub

        Protected Overrides Sub Dispose(disposing As Boolean)
            If _disposed Then
                MyBase.Dispose(disposing)
                Return
            End If

            If disposing Then
                Try
                    _painter.Dispose()
                Catch masCaughtException1 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException1)
                End Try
            End If

            _disposed = True
            MyBase.Dispose(disposing)
        End Sub


#Region "Unified MASSize Fluent API"

        ''' <summary>
        ''' Strongly typed entry into the shared MASSize intent API.
        ''' This method keeps fluent chains on the concrete element while delegating all sizing decisions to MASControlBase/MASSize.
        ''' </summary>
        Public Shadows Function WithSize(sizeIntent As Nexamas.UI.Layout.MASSize) As MASCard
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region
    End Class

End Namespace
