Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Components
Imports Nexamas.UI.FloatRuntime
Imports Nexamas.UI.Host
Imports SkiaSharp

Namespace Nexamas.UI.Application

    Partial Friend NotInheritable Class MASFileExplorerService

#Region "Owned request safety"

        Private Function ShowRequest(request As MASFloatRequest) As MASFloatHandle
            Return ToCompatibilityFloatHandle(ShowRequestEx(request))
        End Function

        Friend Function ShowRequestEx(request As MASFloatRequest) As MASFloatShowResult
            If request Is Nothing Then Throw New ArgumentNullException(NameOf(request))

            Dim safeRequest As MASFloatRequest = ProtectOwnedRequest(request)
            Dim safeOwnerKey As String = NormalizeOwnerKey(safeRequest.OwnerKey)
            Dim showResult As MASFloatShowResult = Nothing

            RegisterOwnerKey(safeOwnerKey)

            Try
                showResult = _rootHost.FloatRuntimeCore.ShowEx(safeRequest)

                If showResult Is Nothing Then
                    UnregisterOwnerKey(safeOwnerKey)
                    Return MASFloatShowResult.Rejected("FloatRuntime returned no show result.")
                End If

                If Not showResult.IsAccepted OrElse showResult.Status = MASFloatShowStatus.Reused Then
                    UnregisterOwnerKey(safeOwnerKey)
                End If
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException1)
                UnregisterOwnerKey(safeOwnerKey)
                Throw
            End Try

            If showResult.HasHandle Then
                _rootHost.RequestInvalidate()
            End If

            Return showResult
        End Function

        Private Function ProtectOwnedRequest(request As MASFloatRequest) As MASFloatRequest
            If request Is Nothing Then Throw New ArgumentNullException(NameOf(request))

            Dim safeOwnerKey As String = NormalizeOwnerKey(request.OwnerKey)
            Dim originalOnClosed As Action(Of MASFloatClosedEventArgs) = request.OnClosed

            request.OwnerKey = safeOwnerKey
            request.OnClosed =
                Sub(args As MASFloatClosedEventArgs)
                    Try
                        If originalOnClosed IsNot Nothing Then
                            originalOnClosed.Invoke(args)
                        End If
                    Finally
                        UnregisterOwnerKey(safeOwnerKey)
                    End Try
                End Sub

            Return request
        End Function

        Private Sub RegisterOwnerKey(ownerKey As String)
            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)

            SyncLock _ownerGate
                Dim count As Integer = 0
                _activeOwnerKeys.TryGetValue(safeOwnerKey, count)
                _activeOwnerKeys(safeOwnerKey) = count + 1
            End SyncLock
        End Sub

        Private Sub UnregisterOwnerKey(ownerKey As String)
            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)

            SyncLock _ownerGate
                Dim count As Integer = 0

                If Not _activeOwnerKeys.TryGetValue(safeOwnerKey, count) Then Return

                If count <= 1 Then
                    _activeOwnerKeys.Remove(safeOwnerKey)
                Else
                    _activeOwnerKeys(safeOwnerKey) = count - 1
                End If
            End SyncLock
        End Sub

        Private Function IsActiveOwnerKey(ownerKey As String) As Boolean
            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)

            SyncLock _ownerGate
                Return _activeOwnerKeys.ContainsKey(safeOwnerKey)
            End SyncLock
        End Function

        Private Shared Function ToCompatibilityFloatHandle(result As MASFloatShowResult) As MASFloatHandle
            If result Is Nothing Then Return Nothing

            If result.Status = MASFloatShowStatus.Rejected Then
                Throw New InvalidOperationException("Float show rejected: " & result.Reason)
            End If

            Return result.Handle
        End Function

#End Region

#Region "Close / state helpers"

        ''' <summary>
        ''' Returns whether the supplied Float handle still represents an open file-explorer surface.
        ''' This is a handle-scoped query; the service never assumes ownership of unrelated floats.
        ''' </summary>
        Friend Function IsOpen(handle As MASFloatHandle) As Boolean
            If handle Is Nothing Then Return False
            Return _rootHost.FloatRuntimeCore.IsOpen(handle)
        End Function

        ''' <summary>
        ''' Closes the supplied file-explorer Float handle through the Float runtime.
        ''' The close is handle-scoped and never closes an arbitrary current/global surface.
        ''' </summary>
        Friend Sub Close(handle As MASFloatHandle,
                         Optional reason As MASFloatCloseReason = MASFloatCloseReason.Programmatic)

            If handle Is Nothing Then Return

            _rootHost.FloatRuntimeCore.Close(handle, reason)
            _rootHost.RequestInvalidate()

        End Sub

        ''' <summary>
        ''' Closes file-explorer floats owned by this service owner key only when this service has tracked
        ''' the owner key as active. This preserves owner-safe close semantics for the public facade.
        ''' </summary>
        Friend Sub CloseByOwner(ownerKey As String,
                                Optional reason As MASFloatCloseReason = MASFloatCloseReason.Programmatic)

            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)

            If Not IsActiveOwnerKey(safeOwnerKey) Then Return

            _rootHost.FloatRuntimeCore.CloseByOwner(safeOwnerKey, reason)
            _rootHost.RequestInvalidate()

        End Sub

#End Region

#Region "Callbacks / owner"


        Private Shared Function ComposeExplorerClosedCallback(onClosed As Action(Of MASFloatClosedEventArgs),
                                                             onAccepted As Action(Of MASFileExplorerFloatResult),
                                                             onCancelled As Action) As Action(Of MASFloatClosedEventArgs)

            If onClosed Is Nothing AndAlso onAccepted Is Nothing AndAlso onCancelled Is Nothing Then
                Return Nothing
            End If

            Return Sub(args As MASFloatClosedEventArgs)
                       If onClosed IsNot Nothing Then
                           onClosed.Invoke(args)
                       End If

                       Dim result As MASFileExplorerFloatResult = TryGetAcceptedExplorerResult(args)

                       If result IsNot Nothing Then
                           If onAccepted IsNot Nothing Then
                               onAccepted.Invoke(result)
                           End If

                           Return
                       End If

                       If onCancelled IsNot Nothing Then
                           onCancelled.Invoke()
                       End If
                   End Sub
        End Function

        Private Shared Function TryGetAcceptedExplorerResult(args As MASFloatClosedEventArgs) As MASFileExplorerFloatResult
            If args Is Nothing Then Return Nothing
            If Not args.WasAccepted Then Return Nothing
            If args.Result Is Nothing OrElse args.Result.Value Is Nothing Then Return Nothing

            Return TryCast(args.Result.Value, MASFileExplorerFloatResult)
        End Function

        Private Shared Function ToClosedCallback(callback As Action) As Action(Of MASFloatClosedEventArgs)
            If callback Is Nothing Then Return Nothing

            Return Sub(args As MASFloatClosedEventArgs)
                       callback.Invoke()
                   End Sub
        End Function

        Private Shared Function NormalizeOwnerKey(ownerKey As String) As String
            If String.IsNullOrWhiteSpace(ownerKey) Then
                Return DefaultOwnerKey
            End If

            Return ownerKey.Trim()
        End Function

#End Region

    End Class

End Namespace
