Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports SkiaSharp

Namespace Nexamas.UI.FloatRuntime

    ' ============================================================
    ' MASFloatRuntime Contract
    ' Class: MASFloatHostState
    '
    ' Purpose:
    '   Stores visual-host-side state for active Float lifecycle records.
    '
    ' Responsibility:
    '   Tracks hosted records and their resolved pixel-space bounds without
    '   owning lifecycle authorization, policy, transitions, or input routing.
    '
    ' Owns:
    '   Hosted record list.
    '   Resolved pixel-space bounds per handle id/generation.
    '   Current available host bounds in pixel-space.
    '
    ' Does Not Own:
    '   Show authorization.
    '   Close authorization.
    '   Lifecycle transitions.
    '   Queue state.
    '   Result delivery.
    '   Transition animation.
    '   Input routing.
    '   Focus ownership.
    '   ThemeContext.
    '
    ' Allowed Dependencies:
    '   MASFloatLifecycleRecord.
    '   MASFloatHandle.
    '   SkiaSharp.SKRect.
    '   System.Collections.Generic.
    '
    ' Forbidden Dependencies:
    '   Legacy Overlay classes.
    '   OverlayHost.
    '   OverlayManager.
    '   OverlayContent.
    '   OverlayLayer.
    '   OverlayService.
    '   BlockingControlsOverlayContent.
    '   Feature-owned lifecycle services.
    '
    ' Lifecycle Role:
    '   Host-side container used after Coordinator accepts a lifecycle step.
    '   It does not decide whether a Float may be shown or closed.
    '
    ' Threading:
    '   Mutated only on the runtime/UI path.
    '   Caller owns UI-thread marshaling before mutation.
    '
    ' Mutation Rules:
    '   Friend/internal mutable state only.
    '   Records must be added/removed only by runtime-owned flow.
    '   Bounds must always be pixel-space.
    '
    ' Invariants:
    '   Bounds keys include both Id and Generation to prevent stale-handle
    '   mutation.
    '   AvailableBoundsPx is always pixel-space.
    '   HostState must not reference legacy Overlay infrastructure.
    '
    ' Failure Rules:
    '   Missing records are rejected.
    '   Stale id/generation mismatches must not mutate newer Float bounds.
    ' ============================================================
    Friend NotInheritable Class MASFloatHostState

        Private ReadOnly _records As New List(Of MASFloatLifecycleRecord)()

        Private ReadOnly _boundsByIdentity As New Dictionary(Of String, SKRect)(
            StringComparer.Ordinal
        )

        Friend Property AvailableBoundsPx As SKRect = SKRect.Empty

        Friend ReadOnly Property Records As IReadOnlyList(Of MASFloatLifecycleRecord)
            Get
                Return _records.AsReadOnly()
            End Get
        End Property

        Friend ReadOnly Property Count As Integer
            Get
                Return _records.Count
            End Get
        End Property

        Friend Sub AddRecord(record As MASFloatLifecycleRecord, boundsPx As SKRect)
            If record Is Nothing Then
                Throw New ArgumentNullException(NameOf(record))
            End If

            If Contains(record.Handle) Then
                Throw New InvalidOperationException(
                    "The Float handle is already hosted."
                )
            End If

            _records.Add(record)
            _boundsByIdentity(GetIdentityKey(record.Handle)) = boundsPx
        End Sub

        Friend Function RemoveRecord(handle As MASFloatHandle) As Boolean
            If handle Is Nothing Then
                Return False
            End If

            Dim removed As Boolean = False

            For index As Integer = _records.Count - 1 To 0 Step -1
                If IsSameHandle(_records(index).Handle, handle) Then
                    _records.RemoveAt(index)
                    removed = True
                    Exit For
                End If
            Next

            _boundsByIdentity.Remove(GetIdentityKey(handle))
            Return removed
        End Function

        Friend Function Contains(handle As MASFloatHandle) As Boolean
            If handle Is Nothing Then
                Return False
            End If

            For Each record As MASFloatLifecycleRecord In _records
                If IsSameHandle(record.Handle, handle) Then
                    Return True
                End If
            Next

            Return False
        End Function

        Friend Function TryGetBoundsPx(
            handle As MASFloatHandle,
            ByRef boundsPx As SKRect
        ) As Boolean
            boundsPx = SKRect.Empty

            If handle Is Nothing Then
                Return False
            End If

            Return _boundsByIdentity.TryGetValue(GetIdentityKey(handle), boundsPx)
        End Function

        Friend Function TrySetBoundsPx(
            handle As MASFloatHandle,
            boundsPx As SKRect
        ) As Boolean
            If handle Is Nothing Then
                Return False
            End If

            Dim key As String = GetIdentityKey(handle)

            If Not _boundsByIdentity.ContainsKey(key) Then
                Return False
            End If

            _boundsByIdentity(key) = boundsPx
            Return True
        End Function

        Friend Sub Clear()
            _records.Clear()
            _boundsByIdentity.Clear()
        End Sub

        Private Shared Function IsSameHandle(
            left As MASFloatHandle,
            right As MASFloatHandle
        ) As Boolean
            If left Is Nothing OrElse right Is Nothing Then
                Return False
            End If

            Return left.Id = right.Id AndAlso
                   left.Generation = right.Generation
        End Function

        Private Shared Function GetIdentityKey(handle As MASFloatHandle) As String
            If handle Is Nothing Then
                Return String.Empty
            End If

            Return handle.Id.ToString(Globalization.CultureInfo.InvariantCulture) &
                   ":" &
                   handle.Generation.ToString(Globalization.CultureInfo.InvariantCulture)
        End Function

    End Class

End Namespace