public/dialogs/Show-UiPromptDialog.ps1

function Show-UiPromptDialog {
    <#
    .SYNOPSIS
        Shows a multi-field prompt dialog.
    .DESCRIPTION
        Displays a themed dialog with dynamically generated input fields based on
        FieldDescription collection. Used to intercept $Host.UI.Prompt() calls.
    .PARAMETER Caption
        The caption/title of the dialog.
    .PARAMETER Message
        The message to display.
    .PARAMETER Descriptions
        Collection of FieldDescription objects defining fields to display.
    .EXAMPLE
        Show-UiPromptDialog -Caption "Input Required" -Message "Enter values" -Descriptions $fields
    #>

    [CmdletBinding()]
    param(
        [string]$Caption,
        [string]$Message,
        [System.Collections.ObjectModel.Collection[System.Management.Automation.Host.FieldDescription]]$Descriptions
    )

    Write-Debug "Caption='$Caption' FieldCount=$($Descriptions.Count)"

    $dialogTitle = if ($Caption) { $Caption } else { "Input Required" }
    $fieldControls = @{}

    # Create dialog window using shared helper with Edit icon
    $editIcon = [PsUi.ModuleContext]::GetIcon('Edit')
    $dlg = New-DialogWindow -Title $dialogTitle -Width 450 -MaxHeight 700 -AppIdSuffix 'PromptDialog' -OverlayGlyph $editIcon -TitleIcon $editIcon

    $window       = $dlg.Window
    $contentPanel = $dlg.ContentPanel
    $colors       = $dlg.Colors

    # Button panel at bottom
    $buttonPanel = [System.Windows.Controls.StackPanel]@{
        Orientation         = 'Horizontal'
        HorizontalAlignment = 'Right'
        Margin              = [System.Windows.Thickness]::new(0, 12, 0, 0)
    }
    [System.Windows.Controls.DockPanel]::SetDock($buttonPanel, 'Bottom')
    [void]$contentPanel.Children.Add($buttonPanel)

    # Scrollable content area
    $scrollViewer = [System.Windows.Controls.ScrollViewer]@{
        VerticalScrollBarVisibility   = 'Auto'
        HorizontalScrollBarVisibility = 'Disabled'
    }

    $mainStack = [System.Windows.Controls.StackPanel]::new()

    # Optional message at top
    if ($Message) {
        $msgText = [System.Windows.Controls.TextBlock]@{
            Text         = $Message
            TextWrapping = 'Wrap'
            FontSize     = 13
            Foreground   = ConvertTo-UiBrush $colors.ControlFg
            Margin       = [System.Windows.Thickness]::new(0, 0, 0, 15)
        }
        [void]$mainStack.Children.Add($msgText)
    }

    # Build input fields from descriptions
    foreach ($field in $Descriptions) {
        $fieldName = $field.Name
        $fieldLabel = if ($field.Label) { $field.Label } else { $fieldName }
        $isSecure = $field.ParameterTypeName -like '*SecureString*' -or $field.ParameterTypeName -like '*Password*'

        $label = [System.Windows.Controls.TextBlock]@{
            Text       = $fieldLabel
            FontSize   = 12
            Foreground = ConvertTo-UiBrush $colors.ControlFg
            Margin     = [System.Windows.Thickness]::new(0, 0, 0, 4)
        }
        [void]$mainStack.Children.Add($label)

        if ($field.HelpMessage) {
            $helpText = [System.Windows.Controls.TextBlock]@{
                Text       = $field.HelpMessage
                FontSize   = 10
                Foreground = ConvertTo-UiBrush $colors.SecondaryText
                Margin     = [System.Windows.Thickness]::new(0, 0, 0, 4)
                FontStyle  = 'Italic'
            }
            [void]$mainStack.Children.Add($helpText)
        }

        if ($isSecure) {
            $inputControl = [System.Windows.Controls.PasswordBox]@{
                Height      = 28
                FontSize    = 12
                Background  = ConvertTo-UiBrush $colors.ControlBg
                Foreground  = ConvertTo-UiBrush $colors.ControlFg
                BorderBrush = ConvertTo-UiBrush $colors.Border
                Padding     = [System.Windows.Thickness]::new(2, 0, 2, 0)
                Margin      = [System.Windows.Thickness]::new(0, 0, 0, 10)
            }
        }
        else {
            $inputControl = [System.Windows.Controls.TextBox]@{
                Height   = 28
                FontSize = 12
                Padding  = [System.Windows.Thickness]::new(2, 0, 2, 0)
                Margin   = [System.Windows.Thickness]::new(0, 0, 0, 10)
            }
            Set-TextBoxStyle -TextBox $inputControl

            if ($field.DefaultValue) {
                $inputControl.Text = $field.DefaultValue.ToString()
            }
        }

        [void]$mainStack.Children.Add($inputControl)
        $fieldControls[$fieldName] = @{
            Control  = $inputControl
            IsSecure = $isSecure
            Type     = $field.ParameterTypeName
        }
    }

    $scrollViewer.Content = $mainStack
    [void]$contentPanel.Children.Add($scrollViewer)

    # OK button (accent)
    $okBtn = [System.Windows.Controls.Button]@{
        Content   = "OK"
        Width     = 80
        Height    = 28
        Margin    = [System.Windows.Thickness]::new(4, 0, 0, 0)
        IsDefault = $true
    }
    Set-ButtonStyle -Button $okBtn -Accent
    $okBtn.Add_Click({ $window.Tag = 'OK'; $window.Close() })
    [void]$buttonPanel.Children.Add($okBtn)

    # Cancel button
    $cancelBtn = [System.Windows.Controls.Button]@{
        Content  = "Cancel"
        Width    = 80
        Height   = 28
        Margin   = [System.Windows.Thickness]::new(4, 0, 0, 0)
        IsCancel = $true
    }
    Set-ButtonStyle -Button $cancelBtn
    $cancelBtn.Add_Click({ $window.Tag = $null; $window.Close() })
    [void]$buttonPanel.Children.Add($cancelBtn)

    # Standard window behavior
    Initialize-UiWindowLoaded -Window $window

    # Focus first field
    $window.Add_Loaded({
        $firstField = $fieldControls.Values | Select-Object -First 1
        if ($firstField) { $firstField.Control.Focus() }
    }.GetNewClosure())

    Set-UiDialogPosition -Dialog $window

    Write-Debug "Showing modal dialog"
    [void]$window.ShowDialog()

    $result = [System.Collections.Generic.Dictionary[string,System.Management.Automation.PSObject]]::new()

    if ($window.Tag -eq 'OK') {
        foreach ($fieldName in $fieldControls.Keys) {
            $fieldInfo = $fieldControls[$fieldName]
            $control = $fieldInfo.Control

            if ($fieldInfo.IsSecure) {
                $value = $control.SecurePassword
            }
            else {
                $value = $control.Text
            }

            $result[$fieldName] = [PSObject]::AsPSObject($value)
        }
        Write-Debug "Result: $($result.Count) fields returned"
    }
    else {
        Write-Debug "Result: <cancelled>"
    }

    return $result
}