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 Nexamas.UI.Theming
Imports SkiaSharp

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Message/dialog facade for one MASApplicationWindow.
    ''' This class is the public application-level entry point for dialog surfaces.
    ''' Legacy GroupBox-backed ShowPanel APIs and the former low-level public
    ''' ShowPanelShell composition API are intentionally not part of the SDK surface.
    ''' Nexamas UI-owned features may use internal high-level gateways such as ShowSelectionPanel.
    ''' </summary>
    Public NotInheritable Class MASApplicationWindowDialogs

        Private Const DefaultOwnerKey As String = "MAS.Application.Dialogs"
        Private ReadOnly _rootHost As MASSkiaRootHost

        Private ReadOnly Property RootHost As MASSkiaRootHost
            Get
                _rootHost.ThrowIfDisposedCore()
                Return _rootHost
            End Get
        End Property

        Friend Sub New(rootHost As MASSkiaRootHost)
            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))
            _rootHost = rootHost
        End Sub

        Public Function ConfirmAction(title As String,
                                      message As String,
                                      Optional detail As String = "",
                                      Optional ownerKey As String = DefaultOwnerKey,
                                      Optional onAccepted As Action = Nothing,
                                      Optional onCancelled As Action = Nothing,
                                      Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return Confirm(
                title:=title,
                message:=message,
                detail:=detail,
                ownerKey:=ownerKey,
                onClosed:=Sub(args As MASApplicationClosedEventArgs)

                              Dim accepted As Boolean = IsAcceptedDialogResult(args)

                              If accepted Then
                                  If onAccepted IsNot Nothing Then onAccepted.Invoke()
                              Else
                                  If onCancelled IsNot Nothing Then onCancelled.Invoke()
                              End If

                              If onClosed IsNot Nothing Then onClosed.Invoke(args)

                          End Sub)

        End Function

        Public Function DeleteConfirmAction(title As String,
                                            message As String,
                                            Optional detail As String = "",
                                            Optional confirmText As String = "Delete",
                                            Optional cancelText As String = "Cancel",
                                            Optional ownerKey As String = DefaultOwnerKey,
                                            Optional onAccepted As Action = Nothing,
                                            Optional onCancelled As Action = Nothing,
                                            Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Dim safeTitle As String = If(title, String.Empty)
            Dim safeMessage As String = If(message, String.Empty)
            Dim safeDetail As String = If(detail, String.Empty)
            Dim safeConfirmText As String = If(String.IsNullOrWhiteSpace(confirmText), "Delete", confirmText)
            Dim safeCancelText As String = If(String.IsNullOrWhiteSpace(cancelText), "Cancel", cancelText)

            Dim request As MessageBoxRequest =
                MessageBoxRequestBuilder.Create(MessageBoxKind.Delete) _
                    .WithTitle(safeTitle) _
                    .WithMessage(safeMessage) _
                    .WithDetail(safeDetail) _
                    .WithButtonsAndResults(
                        buttons:=New List(Of MASButtonSpec) From {
                            New MASButtonSpec(
                                text:=safeConfirmText,
                                personality:=MASButtonPersonality.Tal,
                                intent:=MASButtonIntent.Danger,
                                isDefault:=True),
                            New MASButtonSpec(
                                text:=safeCancelText,
                                personality:=MASButtonPersonality.Tal,
                                intent:=MASButtonIntent.Subtle)
                        },
                        results:=New List(Of MessageBoxResult) From {
                            MessageBoxResult.OK,
                            MessageBoxResult.Cancel
                        }) _
                    .WithDefaultResult(MessageBoxResult.Cancel) _
                    .WithEscapeResult(MessageBoxResult.Cancel) _
                    .WithCloseButton(True) _
                    .Build()

            Return ShowApplicationMessageBox(
                ownerKey:=ownerKey,
                messageBox:=request,
                onClosed:=Sub(args As MASApplicationClosedEventArgs)

                              Dim accepted As Boolean = IsDialogResult(args, MASApplicationDialogResult.OK)

                              If accepted Then
                                  If onAccepted IsNot Nothing Then onAccepted.Invoke()
                              Else
                                  If onCancelled IsNot Nothing Then onCancelled.Invoke()
                              End If

                              If onClosed IsNot Nothing Then onClosed.Invoke(args)

                          End Sub)

        End Function

        Friend Function Show(messageBox As MessageBoxRequest,
                             Optional ownerKey As String = DefaultOwnerKey,
                             Optional initialBoundsPx As SKRect = Nothing,
                             Optional showPolicy As MASFloatShowPolicy = MASFloatShowPolicy.QueueAfterCurrentClosed,
                             Optional shield As MASFloatShieldOptions = Nothing,
                             Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                             Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowEx(
                    messageBox:=messageBox,
                    ownerKey:=ownerKey,
                    initialBoundsPx:=initialBoundsPx,
                    showPolicy:=showPolicy,
                    shield:=shield,
                    onOpened:=onOpened,
                    onClosed:=onClosed))

        End Function

        Friend Function ShowEx(messageBox As MessageBoxRequest,
                               Optional ownerKey As String = DefaultOwnerKey,
                               Optional initialBoundsPx As SKRect = Nothing,
                               Optional showPolicy As MASFloatShowPolicy = MASFloatShowPolicy.QueueAfterCurrentClosed,
                               Optional shield As MASFloatShieldOptions = Nothing,
                               Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                               Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatShowResult

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

            Return RootHost.ShowMessageBoxFloatEx(
                ownerKey:=NormalizeOwnerKey(ownerKey),
                messageBox:=messageBox,
                initialBoundsPx:=initialBoundsPx,
                showPolicy:=showPolicy,
                shield:=shield,
                onOpened:=onOpened,
                onClosed:=onClosed)

        End Function

        Public Function Information(message As String,
                                    Optional title As String = "Information",
                                    Optional detail As String = "",
                                    Optional ownerKey As String = DefaultOwnerKey,
                                    Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(InformationEx(message, title, detail, ownerKey, onClosed))

        End Function

        Friend Function InformationEx(message As String,
                                      Optional title As String = "Information",
                                      Optional detail As String = "",
                                      Optional ownerKey As String = DefaultOwnerKey,
                                      Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowInformationMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    message,
                    title,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function

        Public Function Success(message As String,
                                Optional title As String = "Success",
                                Optional detail As String = "",
                                Optional ownerKey As String = DefaultOwnerKey,
                                Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(SuccessEx(message, title, detail, ownerKey, onClosed))

        End Function

        Friend Function SuccessEx(message As String,
                                  Optional title As String = "Success",
                                  Optional detail As String = "",
                                  Optional ownerKey As String = DefaultOwnerKey,
                                  Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowSuccessMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    message,
                    title,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function

        Public Function Warning(message As String,
                                Optional title As String = "Warning",
                                Optional detail As String = "",
                                Optional ownerKey As String = DefaultOwnerKey,
                                Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(WarningEx(message, title, detail, ownerKey, onClosed))

        End Function

        Friend Function WarningEx(message As String,
                                  Optional title As String = "Warning",
                                  Optional detail As String = "",
                                  Optional ownerKey As String = DefaultOwnerKey,
                                  Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowWarningMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    message,
                    title,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function

        Public Function [Error](message As String,
                                Optional title As String = "Error",
                                Optional detail As String = "",
                                Optional ownerKey As String = DefaultOwnerKey,
                                Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(ErrorEx(message, title, detail, ownerKey, onClosed))

        End Function

        Friend Function ErrorEx(message As String,
                                Optional title As String = "Error",
                                Optional detail As String = "",
                                Optional ownerKey As String = DefaultOwnerKey,
                                Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowErrorMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    message,
                    title,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function

        Public Function Question(title As String,
                                 message As String,
                                 Optional detail As String = "",
                                 Optional ownerKey As String = DefaultOwnerKey,
                                 Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(QuestionEx(title, message, detail, ownerKey, onClosed))

        End Function

        Friend Function QuestionEx(title As String,
                                   message As String,
                                   Optional detail As String = "",
                                   Optional ownerKey As String = DefaultOwnerKey,
                                   Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowQuestionMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    title,
                    message,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function

        Public Function Confirm(title As String,
                                message As String,
                                Optional detail As String = "",
                                Optional ownerKey As String = DefaultOwnerKey,
                                Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(ConfirmEx(title, message, detail, ownerKey, onClosed))

        End Function

        Friend Function ConfirmEx(title As String,
                                  message As String,
                                  Optional detail As String = "",
                                  Optional ownerKey As String = DefaultOwnerKey,
                                  Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(
                RootHost.ShowConfirmMessageBoxEx(
                    NormalizeOwnerKey(ownerKey),
                    title,
                    message,
                    detail,
                    ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue)))

        End Function


        ''' <summary>
        ''' Shows a high-level checklist/single-choice selection panel without exposing
        ''' PanelShell geometry, generated controls, or Skia layout primitives to SDK consumers.
        ''' </summary>
        Friend Function ShowSelectionPanel(ownerKey As String,
                                           options As MASSelectionPanelOptions,
                                           Optional showPolicy As MASApplicationDialogShowPolicy = MASApplicationDialogShowPolicy.CloseSameOwnerThenShow,
                                           Optional shield As MASApplicationDialogShieldOptions = Nothing,
                                           Optional onCompleted As Action(Of MASSelectionPanelResult) = Nothing,
                                           Optional onOpened As Action(Of MASApplicationOpenedEventArgs) = Nothing,
                                           Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(
                ShowSelectionPanelEx(
                    ownerKey:=ownerKey,
                    options:=options,
                    showPolicy:=showPolicy,
                    shield:=shield,
                    onCompleted:=onCompleted,
                    onOpened:=onOpened,
                    onClosed:=onClosed))

        End Function

        ''' <summary>
        ''' Shows a high-level checklist/single-choice selection panel and returns the
        ''' standard Application surface show result. PanelShell remains the internal renderer.
        ''' </summary>
        Friend Function ShowSelectionPanelEx(ownerKey As String,
                                             options As MASSelectionPanelOptions,
                                             Optional showPolicy As MASApplicationDialogShowPolicy = MASApplicationDialogShowPolicy.CloseSameOwnerThenShow,
                                             Optional shield As MASApplicationDialogShieldOptions = Nothing,
                                             Optional onCompleted As Action(Of MASSelectionPanelResult) = Nothing,
                                             Optional onOpened As Action(Of MASApplicationOpenedEventArgs) = Nothing,
                                             Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

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

            Dim panelOptions As MASApplicationPanelShellOptions =
                MASSelectionPanelRequestBuilder.Build(
                    options:=options,
                    completed:=onCompleted)

            Return ShowPanelShellEx(
                ownerKey:=ownerKey,
                options:=panelOptions,
                showPolicy:=showPolicy,
                shield:=shield,
                onOpened:=onOpened,
                onClosed:=onClosed)

        End Function

        ''' <summary>
        ''' Internal gateway for Nexamas UI-owned feature content inside the reusable
        ''' MASPanelShell FloatRuntime surface. External SDK callers must use the
        ''' public dialog gateways or Nexamas UI-owned internal feature gateways as appropriate.
        ''' </summary>
        Friend Function ShowPanelShell(ownerKey As String,
                                       options As MASApplicationPanelShellOptions,
                                       Optional showPolicy As MASApplicationDialogShowPolicy = MASApplicationDialogShowPolicy.CloseSameOwnerThenShow,
                                       Optional shield As MASApplicationDialogShieldOptions = Nothing,
                                       Optional onOpened As Action(Of MASApplicationOpenedEventArgs) = Nothing,
                                       Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Return ToCompatibilitySurfaceHandle(
                ShowPanelShellEx(
                    ownerKey:=ownerKey,
                    options:=options,
                    showPolicy:=showPolicy,
                    shield:=shield,
                    onOpened:=onOpened,
                    onClosed:=onClosed))

        End Function

        ''' <summary>
        ''' Internal gateway for Nexamas UI-owned feature content inside the reusable
        ''' MASPanelShell FloatRuntime surface. It accepts the low-level PanelShell options
        ''' produced by internal builders only.
        ''' </summary>
        Friend Function ShowPanelShellEx(ownerKey As String,
                                         options As MASApplicationPanelShellOptions,
                                         Optional showPolicy As MASApplicationDialogShowPolicy = MASApplicationDialogShowPolicy.CloseSameOwnerThenShow,
                                         Optional shield As MASApplicationDialogShieldOptions = Nothing,
                                         Optional onOpened As Action(Of MASApplicationOpenedEventArgs) = Nothing,
                                         Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceShowResult

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

            If options.AvailableBoundsPx.IsEmpty OrElse
               options.AvailableBoundsPx.Width <= 1.0F OrElse
               options.AvailableBoundsPx.Height <= 1.0F Then

                options.AvailableBoundsPx = RootHost.GetSurfaceViewportPx()
            End If

            Dim request As MASFloatRequest =
                MASPanelShellFloatRequestBuilder.CreateRequestCore(
                    rootHost:=_rootHost,
                    ownerKey:=NormalizeOwnerKey(ownerKey),
                    options:=options,
                    floatKey:=MASFloatKeys.Panel,
                    showPolicy:=ToFloatShowPolicy(showPolicy),
                    shield:=ToFloatShieldOptions(shield),
                    onOpened:=ToApplicationOpenedCallback(onOpened),
                    onClosed:=ToApplicationClosedCallback(onClosed, AddressOf ConvertPanelShellValue))

            Dim showResult As MASFloatShowResult = RootHost.FloatRuntimeCore.ShowEx(request)

            If showResult IsNot Nothing AndAlso showResult.HasHandle Then
                RootHost.RequestInvalidate()
            End If

            Return MASApplicationSurfaceShowResult.FromFloatShowResult(showResult)

        End Function

        Private Function ShowApplicationMessageBox(ownerKey As String,
                                                   messageBox As MessageBoxRequest,
                                                   Optional onClosed As Action(Of MASApplicationClosedEventArgs) = Nothing) As MASApplicationSurfaceHandle

            Dim handle As MASFloatHandle = Show(
                messageBox:=messageBox,
                ownerKey:=ownerKey,
                onClosed:=ToApplicationClosedCallback(onClosed, AddressOf ConvertMessageBoxValue))

            Return MASApplicationSurfaceHandle.FromFloatHandle(handle)

        End Function

        Private Shared Function ToApplicationOpenedCallback(onOpened As Action(Of MASApplicationOpenedEventArgs)) As Action(Of MASFloatHandle)
            If onOpened Is Nothing Then Return Nothing

            Return Sub(handle As MASFloatHandle)
                       Dim args As MASApplicationOpenedEventArgs =
                           MASApplicationOpenedEventArgs.FromFloatHandle(handle)

                       If args IsNot Nothing Then onOpened.Invoke(args)
                   End Sub

        End Function

        Private Shared Function ToApplicationClosedCallback(onClosed As Action(Of MASApplicationClosedEventArgs),
                                                            Optional valueConverter As Func(Of Object, Object) = Nothing) As Action(Of MASFloatClosedEventArgs)
            If onClosed Is Nothing Then Return Nothing

            Return Sub(args As MASFloatClosedEventArgs)
                       onClosed.Invoke(MASApplicationClosedEventArgs.FromFloatEventArgs(args, valueConverter))
                   End Sub

        End Function

        Private Shared Function IsAcceptedDialogResult(args As MASApplicationClosedEventArgs) As Boolean

            Dim result As MASApplicationDialogResult = MASApplicationDialogResult.None

            If Not TryGetDialogResult(args, result) Then
                Return False
            End If

            Return result = MASApplicationDialogResult.OK OrElse
                   result = MASApplicationDialogResult.Yes

        End Function

        Private Shared Function IsDialogResult(args As MASApplicationClosedEventArgs,
                                               expected As MASApplicationDialogResult) As Boolean

            Dim result As MASApplicationDialogResult = MASApplicationDialogResult.None

            If Not TryGetDialogResult(args, result) Then
                Return False
            End If

            Return result = expected

        End Function

        Private Shared Function TryGetDialogResult(args As MASApplicationClosedEventArgs,
                                                   ByRef result As MASApplicationDialogResult) As Boolean

            result = MASApplicationDialogResult.None

            If args Is Nothing OrElse
               args.Result Is Nothing OrElse
               args.Result.Value Is Nothing Then

                Return False
            End If

            Dim converted As Object = ConvertMessageBoxValue(args.Result.Value)

            If TypeOf converted Is MASApplicationDialogResult Then
                result = DirectCast(converted, MASApplicationDialogResult)
                Return result <> MASApplicationDialogResult.None
            End If

            Return False

        End Function

        Private Shared Function ConvertMessageBoxValue(value As Object) As Object

            If value Is Nothing Then Return Nothing

            If TypeOf value Is MASApplicationDialogResult Then
                Return value
            End If

            If TypeOf value Is MessageBoxResult Then
                Dim result As MessageBoxResult = DirectCast(value, MessageBoxResult)

                Select Case result
                    Case MessageBoxResult.OK
                        Return MASApplicationDialogResult.OK

                    Case MessageBoxResult.Cancel
                        Return MASApplicationDialogResult.Cancel

                    Case MessageBoxResult.Yes
                        Return MASApplicationDialogResult.Yes

                    Case MessageBoxResult.No
                        Return MASApplicationDialogResult.No

                    Case MessageBoxResult.Retry
                        Return MASApplicationDialogResult.Retry

                    Case MessageBoxResult.Abort
                        Return MASApplicationDialogResult.Abort

                    Case MessageBoxResult.Ignore
                        Return MASApplicationDialogResult.Ignore

                    Case MessageBoxResult.Close
                        Return MASApplicationDialogResult.Close

                    Case Else
                        Return MASApplicationDialogResult.None
                End Select
            End If

            Return value

        End Function

        Private Shared Function ConvertPanelShellValue(value As Object) As Object

            Dim panelResult As MASApplicationPanelResult =
                TryCast(value, MASApplicationPanelResult)

            If panelResult IsNot Nothing Then
                Return panelResult
            End If

            Return value

        End Function

        Private Shared Function ToFloatShowPolicy(policy As MASApplicationDialogShowPolicy) As MASFloatShowPolicy

            Select Case policy
                Case MASApplicationDialogShowPolicy.FailIfOccupied
                    Return MASFloatShowPolicy.FailIfOccupied

                Case MASApplicationDialogShowPolicy.ReplaceCurrent
                    Return MASFloatShowPolicy.ReplaceCurrent

                Case MASApplicationDialogShowPolicy.QueueAfterCurrentClosed
                    Return MASFloatShowPolicy.QueueAfterCurrentClosed

                Case MASApplicationDialogShowPolicy.ReuseIfSameOwner
                    Return MASFloatShowPolicy.ReuseIfSameOwner

                Case Else
                    Return MASFloatShowPolicy.CloseSameOwnerThenShow
            End Select

        End Function

        Private Shared Function ToFloatShieldOptions(shield As MASApplicationDialogShieldOptions) As MASFloatShieldOptions

            If shield Is Nothing Then Return MASFloatShieldOptions.None
            Return shield.ToFloatShieldOptions()

        End Function

        Private Shared Function ToCompatibilitySurfaceHandle(result As MASApplicationSurfaceShowResult) As MASApplicationSurfaceHandle

            If result Is Nothing Then Return Nothing

            If result.Status = MASApplicationSurfaceShowStatus.Rejected Then
                Throw New InvalidOperationException("Application surface show rejected: " & result.Reason)
            End If

            Return result.Handle

        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

        Private Shared Function NormalizeOwnerKey(ownerKey As String) As String

            Dim safe As String = If(ownerKey, String.Empty).Trim()
            If safe.Length = 0 Then Return DefaultOwnerKey
            Return safe

        End Function

    End Class

End Namespace