Option Strict On
Option Explicit On

Imports System
Imports System.IO
Imports System.Windows.Forms
Imports Nexamas.UI.Components
Imports Nexamas.UI.Components.DropDownMenu
Imports Nexamas.UI.FileSystem
Imports Nexamas.UI.General
Imports Nexamas.UI.Host
Imports Nexamas.UI.Theming
Imports SkiaSharp

Namespace Nexamas.UI.FloatRuntime

    ''' <summary>
    ''' Builds FilePicker browser context menus as standard MAS ContextMenu Floats.
    ''' </summary>
    ''' <remarks>
    ''' This builder owns menu construction and popup request creation only. It deliberately does not
    ''' execute file-system commands; MASFilePickerControl remains the command owner because only the
    ''' picker knows its current mode, selection policy, and refresh/navigation behavior.
    ''' </remarks>
    Friend NotInheritable Class MASFilePickerContextMenuFloatRequestBuilder

        Private Sub New()
        End Sub

        Friend Shared Function CreateItemRequest(rootHost As MASSkiaRootHost,
                                                 ownerKey As String,
                                                 entry As FileSystemEntry,
                                                 anchorRectPx As SKRect,
                                                 Optional parentHandle As MASFloatHandle = Nothing,
                                                 Optional onCommand As Action(Of String, FileSystemEntry) = Nothing,
                                                 Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatRequest

            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))
            If entry Is Nothing Then Return Nothing

            Dim builder As MASDropDownMenuBuilder = MASDropDownMenuBuilder.Create()
            BuildItemMenu(builder, entry)

            Return CreateMenuRequest(
                rootHost:=rootHost,
                ownerKey:=ownerKey,
                anchorRectPx:=anchorRectPx,
                parentHandle:=parentHandle,
                builder:=builder,
                executeCommand:=Sub(commandId As String)
                                    If onCommand IsNot Nothing Then
                                        onCommand.Invoke(commandId, entry)
                                    End If
                                End Sub,
                onClosed:=onClosed)
        End Function

        Friend Shared Function CreateBackgroundRequest(rootHost As MASSkiaRootHost,
                                                       ownerKey As String,
                                                       currentFolderPath As String,
                                                       anchorRectPx As SKRect,
                                                       Optional parentHandle As MASFloatHandle = Nothing,
                                                       Optional onCommand As Action(Of String) = Nothing,
                                                       Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatRequest

            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))

            Dim builder As MASDropDownMenuBuilder = MASDropDownMenuBuilder.Create()
            BuildBackgroundMenu(builder, currentFolderPath)

            Return CreateMenuRequest(
                rootHost:=rootHost,
                ownerKey:=ownerKey,
                anchorRectPx:=anchorRectPx,
                parentHandle:=parentHandle,
                builder:=builder,
                executeCommand:=Sub(commandId As String)
                                    If onCommand IsNot Nothing Then
                                        onCommand.Invoke(commandId)
                                    End If
                                End Sub,
                onClosed:=onClosed)
        End Function

        Private Shared Function CreateMenuRequest(rootHost As MASSkiaRootHost,
                                                  ownerKey As String,
                                                  anchorRectPx As SKRect,
                                                  parentHandle As MASFloatHandle,
                                                  builder As MASDropDownMenuBuilder,
                                                  executeCommand As Action(Of String),
                                                  onClosed As Action(Of MASFloatClosedEventArgs)) As MASFloatRequest

            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))
            If builder Is Nothing Then Return Nothing

            If String.IsNullOrWhiteSpace(ownerKey) Then
                Throw New ArgumentException("FilePicker context menu requires a non-empty ownerKey.", NameOf(ownerKey))
            End If

            If Not IsUsableRect(anchorRectPx) Then Return Nothing

            Dim ctx As MASThemeContext = ResolveContext(rootHost)
            If ctx Is Nothing Then Return Nothing

            Dim availablePx As SKRect = rootHost.GetSurfaceViewportPx()
            If Not IsUsableRect(availablePx) Then Return Nothing

            Dim model As MASDropDownMenuModel = builder.Build()
            If model Is Nothing OrElse model.IsEmpty Then Return Nothing

            Dim safeOwnerKey As String = ownerKey.Trim()

            Dim content As New DropDownMenuFloatContent(
                ctx:=ctx,
                model:=model,
                anchorRectPx:=anchorRectPx,
                executeCommand:=Sub(commandId As String)
                                    If executeCommand IsNot Nothing Then
                                        executeCommand.Invoke(commandId)
                                    End If
                                End Sub,
                contextProvider:=Function()
                                     Return ResolveContext(rootHost)
                                 End Function)

            Dim request As New MASFloatRequest() With {
                .FloatKey = MASFloatKeys.ContextMenu,
                .OwnerKey = safeOwnerKey,
                .Content = content,
                .RequestedSlot = MASFloatSlot.Popup,
                .RequestedLayer = ResolveMenuLayer(parentHandle),
                .RequestedPresentation = CreateMenuPresentation(),
                .ShowPolicy = MASFloatShowPolicy.CloseSameOwnerThenShow,
                .Shield = MASFloatShieldOptions.None,
                .AnchorRectPx = anchorRectPx,
                .AvailableBoundsPx = availablePx,
                .InitialBoundsPx = availablePx,
                .OnClosed = onClosed
            }

            If parentHandle IsNot Nothing Then
                request.ParentHandle = parentHandle
                request.RequestedScope = MASFloatScope.ParentFloat
            Else
                request.RequestedScope = MASFloatScope.Owner
            End If

            Return request
        End Function

        Private Shared Sub BuildItemMenu(builder As MASDropDownMenuBuilder,
                                         entry As FileSystemEntry)
            If builder Is Nothing Then Throw New ArgumentNullException(NameOf(builder))
            If entry Is Nothing Then Return

            Dim canOpenWithWindowsShell As Boolean = CanOpenInWindows(entry)
            Dim canCopyPath As Boolean = ResolveEntryPath(entry).Length > 0
            Dim canClipboard As Boolean = ResolveExistingPhysicalPath(entry).Length > 0
            Dim canModify As Boolean = CanModifyPhysicalEntry(entry)
            Dim canShowProperties As Boolean = ResolveExistingPhysicalPath(entry).Length > 0

            builder.AddAction(
                text:="Open",
                commandId:=MASFilePickerContextMenuCommands.Open,
                enabled:=True,
                shortcutText:="Enter")

            Select Case entry.EntryType
                Case FileSystemEntryType.FileItem,
                     FileSystemEntryType.Folder

                    builder.AddAction(
                        text:="Open in Windows",
                        commandId:=MASFilePickerContextMenuCommands.OpenInWindows,
                        enabled:=canOpenWithWindowsShell)

                    builder.AddSeparator()

                    builder.AddAction(
                        text:="Cut",
                        commandId:=MASFilePickerContextMenuCommands.Cut,
                        enabled:=canModify,
                        shortcutText:="Ctrl+X")

                    builder.AddAction(
                        text:="Copy",
                        commandId:=MASFilePickerContextMenuCommands.Copy,
                        enabled:=canClipboard,
                        shortcutText:="Ctrl+C")

                    builder.AddAction(
                        text:="Copy path",
                        commandId:=MASFilePickerContextMenuCommands.CopyPath,
                        enabled:=canCopyPath)

                    builder.AddSeparator()

                    builder.AddAction(
                        text:="Rename",
                        commandId:=MASFilePickerContextMenuCommands.Rename,
                        enabled:=canModify,
                        shortcutText:="F2")

                    builder.AddDangerAction(
                        text:="Delete",
                        commandId:=MASFilePickerContextMenuCommands.Delete,
                        enabled:=canModify,
                        shortcutText:="Del")

                    builder.AddSeparator()

                    builder.AddAction(
                        text:="Properties",
                        commandId:=MASFilePickerContextMenuCommands.Properties,
                        enabled:=canShowProperties)

                Case FileSystemEntryType.Drive

                    builder.AddAction(
                        text:="Open in Windows",
                        commandId:=MASFilePickerContextMenuCommands.OpenInWindows,
                        enabled:=canOpenWithWindowsShell)

                    builder.AddSeparator()

                    builder.AddAction(
                        text:="Copy path",
                        commandId:=MASFilePickerContextMenuCommands.CopyPath,
                        enabled:=canCopyPath)

                    builder.AddSeparator()

                    builder.AddAction(
                        text:="Properties",
                        commandId:=MASFilePickerContextMenuCommands.Properties,
                        enabled:=canShowProperties)

                Case Else

                    If canOpenWithWindowsShell Then
                        builder.AddAction(
                            text:="Open in Windows",
                            commandId:=MASFilePickerContextMenuCommands.OpenInWindows,
                            enabled:=True)
                    End If

                    If canCopyPath Then
                        builder.AddSeparator()

                        builder.AddAction(
                            text:="Copy path",
                            commandId:=MASFilePickerContextMenuCommands.CopyPath,
                            enabled:=True)
                    End If

                    If canShowProperties Then
                        builder.AddSeparator()

                        builder.AddAction(
                            text:="Properties",
                            commandId:=MASFilePickerContextMenuCommands.Properties,
                            enabled:=True)
                    End If
            End Select
        End Sub

        Private Shared Sub BuildBackgroundMenu(builder As MASDropDownMenuBuilder,
                                               currentFolderPath As String)
            If builder Is Nothing Then Throw New ArgumentNullException(NameOf(builder))

            Dim canPaste As Boolean = CanPasteIntoFolder(currentFolderPath)

            builder.AddAction(
                text:="Paste",
                commandId:=MASFilePickerContextMenuCommands.Paste,
                enabled:=canPaste,
                shortcutText:="Ctrl+V")

            builder.AddSeparator()

            builder.AddAction(
                text:="Refresh",
                commandId:=MASFilePickerContextMenuCommands.Refresh,
                enabled:=True,
                shortcutText:="F5")
        End Sub

        Private Shared Function CanPasteIntoFolder(folderPath As String) As Boolean
            Dim target As String = If(folderPath, String.Empty).Trim()
            If target.Length <= 0 Then Return False

            Try
                If Not Directory.Exists(target) Then Return False
                Return Clipboard.ContainsFileDropList()
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException1)
                Return False
            End Try
        End Function

        Private Shared Function CanOpenInWindows(entry As FileSystemEntry) As Boolean
            If entry Is Nothing Then Return False
            Return ResolveExistingPhysicalPath(entry).Length > 0
        End Function

        Private Shared Function CanModifyPhysicalEntry(entry As FileSystemEntry) As Boolean
            If entry Is Nothing Then Return False

            Select Case entry.EntryType
                Case FileSystemEntryType.FileItem,
                     FileSystemEntryType.Folder
                    ' Continue below.

                Case Else
                    Return False
            End Select

            Dim fullPath As String = ResolveExistingPhysicalPath(entry)
            If fullPath.Length <= 0 Then Return False

            Try
                Dim root As String = System.IO.Path.GetPathRoot(fullPath)
                Dim normalizedPath As String = fullPath.TrimEnd("\"c)
                Dim normalizedRoot As String = If(root, String.Empty).TrimEnd("\"c)

                If normalizedRoot.Length > 0 AndAlso
                   String.Equals(normalizedPath, normalizedRoot, StringComparison.OrdinalIgnoreCase) Then
                    Return False
                End If
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException2)
                Return False
            End Try

            Return True
        End Function

        Private Shared Function ResolveExistingPhysicalPath(entry As FileSystemEntry) As String
            Dim path As String = ResolveEntryPath(entry)
            If path.Length <= 0 Then Return String.Empty

            Try
                If File.Exists(path) OrElse Directory.Exists(path) Then
                    Return path
                End If
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException3)
            End Try

            Return String.Empty
        End Function

        Private Shared Function ResolveEntryPath(entry As FileSystemEntry) As String
            If entry Is Nothing Then Return String.Empty
            Return If(entry.FullPath, String.Empty).Trim()
        End Function

        Private Shared Function ResolveMenuLayer(parentHandle As MASFloatHandle) As MASFloatLayerLevel
            If parentHandle Is Nothing Then Return MASFloatLayerLevel.Interactive

            If parentHandle.Layer > MASFloatLayerLevel.Interactive Then
                Return parentHandle.Layer
            End If

            Return MASFloatLayerLevel.Interactive
        End Function

        Private Shared Function CreateMenuPresentation() As MASFloatPresentation
            Return MASFloatPresentationProfiles.AnchoredContextMenu()
        End Function

        Private Shared Function ResolveContext(rootHost As MASSkiaRootHost) As MASThemeContext
            If rootHost Is Nothing Then Return Nothing

            Try
                Return rootHost.ThemeHostCore.TryGetContext()
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException4)
                Return Nothing
            End Try
        End Function

        Private Shared Function IsUsableRect(rect As SKRect) As Boolean
            Return Not rect.IsEmpty AndAlso rect.Width > 1.0F AndAlso rect.Height > 1.0F
        End Function

    End Class

End Namespace
