Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Application

    Partial Friend NotInheritable Class MASFilePickerService

#Region "Owned request safety"

        ''' <summary>
        ''' Internal compatibility path for showing a prebuilt float request. SDK code should prefer ShowOpenFile/ShowSaveFile or Create/OpenFile/SaveFile/Pick*.
        ''' The request is normalized and owner-tracked so this service can close only floats that it currently owns.
        ''' </summary>
        Friend Function ShowRequest(request As MASFloatRequest) As MASFloatHandle
            Return ToCompatibilityFloatHandle(ShowRequestEx(request))
        End Function

        ''' <summary>
        ''' Internal result-bearing path for showing a prebuilt file-picker float request.
        ''' This preserves Opened/Queued/Reused/Rejected outcomes for the public *Ex facade without exposing FloatRuntime types.
        ''' </summary>
        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
                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"

        Friend Function IsOpen(handle As MASFloatHandle) As Boolean
            If handle Is Nothing Then Return False
            Return _rootHost.FloatRuntimeCore.IsOpen(handle)
        End Function

        Friend Sub Close(handle As MASFloatHandle,
                         Optional reason As MASFloatCloseReason = MASFloatCloseReason.Programmatic)

            If handle Is Nothing Then Return

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

        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)
            RequestInvalidate()
        End Sub

#End Region

#Region "Callbacks / owner"

        Private Shared Function ComposeFilePickerClosedCallback(onClosed As Action(Of MASFloatClosedEventArgs),
                                                               onAccepted As Action(Of MASFilePickerResult),
                                                               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 MASFilePickerResult = TryGetAcceptedFilePickerResult(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 TryGetAcceptedFilePickerResult(args As MASFloatClosedEventArgs) As MASFilePickerResult
            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

            Dim result As MASFilePickerResult = TryCast(args.Result.Value, MASFilePickerResult)
            If result Is Nothing Then Return Nothing
            If Not result.Accepted Then Return Nothing

            Return result
        End Function

        Private Shared Function NormalizeOwnerKey(ownerKey As String) As String
            Dim safe As String = If(ownerKey, String.Empty).Trim()
            If safe.Length = 0 Then Return "MAS.FilePicker.Service"
            Return safe
        End Function

#End Region

#Region "Bounds"

        Friend Function GetDefaultAvailableBoundsLogical() As SKRect
            Return _rootHost.PxToLogical(_rootHost.GetSurfaceViewportPx())
        End Function

        Private Sub ApplyDefaultBounds(picker As MASFilePickerControl)
            If picker Is Nothing Then Return

            Dim bounds As SKRect = GetDefaultAvailableBoundsLogical()

            If bounds.IsEmpty OrElse bounds.Width <= 1.0F OrElse bounds.Height <= 1.0F Then
                Return
            End If

            picker.SetLocalLayoutBoundsInternal(bounds)
        End Sub

#End Region

#Region "Invalidate"

        Private Sub RequestInvalidate()
            Try
                _rootHost.RequestInvalidate()
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException2)
            End Try
        End Sub

#End Region

    End Class

End Namespace
