'========================================================
' File: MASTileBox.vb  (SSOT + Fixes + Fluent SDK API)
'========================================================
Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Composition
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Motion
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Scroll
Imports Nexamas.UI.SkiaScroll
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Values
Imports Nexamas.UI.Virtualization
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>Public SDK tile surface control for virtualized icon, bitmap, and text tile collections.</summary>
    Partial Public NotInheritable Class MASTileBox
        Inherits MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract
        Implements IMASScrollContentSizeContract
        Implements IMASControlRuntimeServicesConsumer

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

        Private Shared ReadOnly _tileContract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASTileItemContract))

        Private ReadOnly _primitives As New MASVisualPrimitivesPainter()
        Private ReadOnly _shadow As New MASShadowPainter()


#Region "Fields"

        Private ReadOnly _items As New List(Of MASTileItem)()
        Private _itemsView As IReadOnlyList(Of MASTileItem) = Nothing

        Private _hoverIndex As Integer = -1
        Private _pressedIndex As Integer = -1

        Private _selectedId As Guid = Guid.Empty
        Private _selectedRef As MASTileItem = Nothing
        Private _selectionMotionRunner As MASMotionTimelineRunner
        Private _selectionMotionFromIndex As Integer = -1
        Private _selectionMotionToIndex As Integer = -1
        Private _selectionMotionProgress As Single = 1.0F
        Private _hasSelectionMotion As Boolean

        Private _lastWork As SKRect
        Private _lastCols As Integer = 1
        Private _lastRows As Integer = 0
        Private _lastTileSize As Single = 80.0F
        Private _lastShadowPad As Single = 3.0F
        Private _lastFoot As Single = 86.0F
        Private _lastGapX As Single = 12.0F
        Private _lastGapY As Single = 12.0F
        Private _lastContentH As Single = 0.0F

        Private _rowStepPx As Single = 0.0F
        Private _contentTopPadPx As Single = 0.0F
        Private _contentLeftPadPx As Single = 0.0F
        Private _workTopPx As Single = 0.0F
        Private _workLeftPx As Single = 0.0F

        Private _tilePainter As MASTileVisualPainter

        Private _scroll As SkiaScrollAdapter
        Private _runtimeServices As MASControlRuntimeServices
        Private _isOverScrollbar As Boolean
        Private ReadOnly _virtualization As New MASTileGridVirtualizationConsumerCoordinator()

        Private _itemCollectionRevision As Integer = 0
        Private _layoutRevision As Integer = 0
        Private _lastVirtualizationPlan As MASVirtualizationRealizationPlan = Nothing

        Private _lastHost As SKRect = SKRect.Empty
        Private _lastContent As SKRect = SKRect.Empty
        Private _scrollHost As SKRect = SKRect.Empty
        Private _lastLayoutPlan As MASTileBoxLayoutPlan = Nothing

        Private _scrollThemeRef As IMASAppTheme = Nothing
        Private _scrollThemeId As String = Nothing
        Private _scrollThemeVersion As Integer = Integer.MinValue
        Private _scrollThemeStamp As Integer = Integer.MinValue
        Private _pendingScrollOffset As Single = Single.NaN

        Private _cacheBitmap As SKBitmap = Nothing
        Private _cacheDirty As Boolean = True

        Private _cacheBoundsPx As SKRect = SKRect.Empty
        Private _cacheDpi As Single = -1.0F
        Private _cacheItemCount As Integer = -1
        Private _cacheHoverIndex As Integer = -2
        Private _cachePressedIndex As Integer = -2
        Private _cacheSelectedIndex As Integer = -2
        Private _cacheScrollOffset100 As Integer = -1
        Private _cacheIsOverScrollbar As Boolean = False

        Private _cacheThemeRef As IMASAppTheme = Nothing
        Private _cacheThemeId As String = Nothing
        Private _cacheThemeVersion As Integer = Integer.MinValue
        Private _cacheThemeStamp As Integer = Integer.MinValue

#End Region


#Region "Host Runtime Services"

        Friend Sub BindControlRuntimeServices(services As MASControlRuntimeServices) Implements IMASControlRuntimeServicesConsumer.BindControlRuntimeServices
            If Object.ReferenceEquals(_runtimeServices, services) Then Return

            If services Is Nothing AndAlso _scroll IsNot Nothing Then
                _scroll.CancelInteraction()
            End If

            _runtimeServices = services
        End Sub

        Private Function PostTileBoxScrollRepeatToUiThread(action As Action) As Boolean
            If action Is Nothing Then Return False
            If _runtimeServices Is Nothing Then Return False
            Return _runtimeServices.PostToUiThread(action, "MASTileBox.ScrollRepeatClock")
        End Function

#End Region

#Region "Events"

        Public Event SelectionChanged As EventHandler
        Public Event ItemClicked As EventHandler(Of MASTileClickedEventArgs)

#End Region

#Region "Factories"

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

        Friend Shared Function [Default]() As MASTileBox
            Return New MASTileBox()
        End Function

#End Region





#Region "Fluent API - State"

        Public Function Show() As MASTileBox
            Me.Visible = True
            Return Me
        End Function

        Public Function Hide() As MASTileBox
            Me.Visible = False
            Return Me
        End Function

        Public Function Enable() As MASTileBox
            Me.Enabled = True
            Return Me
        End Function

        Public Function Disable() As MASTileBox
            Me.Enabled = False
            Return Me
        End Function

        Public Function WithVisible(value As Boolean) As MASTileBox
            Me.Visible = value
            Return Me
        End Function

        Public Function WithEnabled(value As Boolean) As MASTileBox
            Me.Enabled = value
            Return Me
        End Function

#End Region

#Region "Fluent API - Events"

        Friend Function OnSelectionChanged(handler As EventHandler) As MASTileBox

            If handler Is Nothing Then
                Throw New ArgumentNullException(NameOf(handler))
            End If

            AddHandler Me.SelectionChanged, handler

            Return Me

        End Function

        Friend Function OnSelectionChanged(handler As Action(Of MASTileBox)) As MASTileBox

            If handler Is Nothing Then
                Throw New ArgumentNullException(NameOf(handler))
            End If

            AddHandler Me.SelectionChanged,
                Sub(sender As Object, e As EventArgs)
                    handler(Me)
                End Sub

            Return Me

        End Function

        Friend Function OnItemClicked(handler As EventHandler(Of MASTileClickedEventArgs)) As MASTileBox

            If handler Is Nothing Then
                Throw New ArgumentNullException(NameOf(handler))
            End If

            AddHandler Me.ItemClicked, handler

            Return Me

        End Function

        Friend Function OnItemClicked(handler As Action(Of Integer)) As MASTileBox

            If handler Is Nothing Then
                Throw New ArgumentNullException(NameOf(handler))
            End If

            AddHandler Me.ItemClicked,
                Sub(sender As Object, e As MASTileClickedEventArgs)
                    If e IsNot Nothing Then
                        handler(e.Index)
                    End If
                End Sub

            Return Me

        End Function

#End Region




#Region "Render"

        Private Const UseOffscreenFrameCache As Boolean = False



#End Region




#Region "Helpers"

        Private Sub SafeInvalidate()

            Try
                MarkFrameCacheDirty()
                InvalidateVisual()
            Catch masCaughtException10 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRenderFallback(masCaughtException10)
            End Try

        End Sub

#End Region

#Region "Lifecycle / Dispose"

        Protected Overrides Sub OnDetached()
            MyBase.OnDetached()
            StopSelectionMotion()
            CancelVirtualizationLifecycleInteractions()
        End Sub

        Private Sub CancelVirtualizationLifecycleInteractions()
            _pressedIndex = -1
            _hoverIndex = -1
            _isOverScrollbar = False
            _lastVirtualizationPlan = Nothing

            Try
                If _scroll IsNot Nothing Then
                    _scroll.CancelInteraction()
                End If
            Catch masCaughtExceptionLifecycle As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtExceptionLifecycle)
            End Try

            MarkFrameCacheDirty()
        End Sub

        Protected Overrides Sub Dispose(disposing As Boolean)

            StopSelectionMotion()
            CancelVirtualizationLifecycleInteractions()
            MyBase.Dispose(disposing)

            If Not disposing Then Return

            If _scroll IsNot Nothing Then
                Try
                    _scroll.Dispose()
                Catch masCaughtException11 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException11)
                End Try

                _scroll = Nothing
            End If

            If _tilePainter IsNot Nothing Then
                Try
                    _tilePainter.Dispose()
                Catch masCaughtException12 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException12)
                End Try

                _tilePainter = Nothing
            End If

            Try
                For Each it As MASTileItem In _items
                    Try
                        it?.Dispose()
                    Catch masCaughtException13 As Exception
                        Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException13)
                    End Try
                Next
            Catch masCaughtException14 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException14)
            End Try

            DisposeFrameCache()

            Try
                _shadow.Dispose()
            Catch masCaughtException15 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException15)
            End Try

            Try
                _primitives.Dispose()
            Catch masCaughtException16 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException16)
            End Try

        End Sub

#End Region


#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 MASTileBox
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region
    End Class

End Namespace
