source/Private/InteractiveMenuHelpers.ps1

# Interactive Menu Helper Functions
# Provides error handling, retry logic, and operation management for the interactive menu

function Test-PowerShellISE {

    return $Host.Name -eq "Windows PowerShell ISE Host"
}

function Invoke-RJOperationWithRetry {

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification='This function is intended for interactive use')]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [scriptblock]$Operation,

        [Parameter(Mandatory)]
        [string]$OperationName,

        [int]$MaxRetries = 3,

        [int]$RetryDelaySeconds = 2,

        [switch]$ShowProgress
    )

    $attempt = 0
    $lastError = $null

    while ($attempt -le $MaxRetries) {
        try {
            Write-Verbose "Executing $OperationName (Attempt $($attempt + 1)/$($MaxRetries + 1))"

            if ($ShowProgress -and $attempt -gt 0) {
                Write-Host "Retry attempt $attempt of $MaxRetries..." -ForegroundColor Yellow
            }

            # Execute the operation
            $result = & $Operation

            # Success - return the result
            Write-Verbose "$OperationName completed successfully"
            return $result
        }
        catch {
            $lastError = $_
            $attempt++

            # Check if this is an authentication error (don't retry)
            if ($_.Exception.Message -match 'authentication|unauthorized|forbidden|401|403') {
                Write-Host "Authentication error during $OperationName`: $($_.Exception.Message)" -ForegroundColor Red
                throw $_
            }

            # Check if we've exceeded max retries
            if ($attempt -gt $MaxRetries) {
                Write-Host "Failed after $MaxRetries retries: $OperationName" -ForegroundColor Red
                Write-Host "Last error: $($lastError.Exception.Message)" -ForegroundColor DarkRed

                # Offer manual retry option
                Write-Host ""
                Write-Host "Would you like to retry manually? (Y/N): " -ForegroundColor Yellow -NoNewline
                $response = Read-Host

                if ($response -eq 'Y' -or $response -eq 'y') {
                    $attempt = 0  # Reset attempts for manual retry
                    continue
                }

                throw $lastError
            }

            # Calculate backoff delay
            $delay = $RetryDelaySeconds * [Math]::Pow(2, $attempt - 1)

            Write-Host "Operation failed: $($_.Exception.Message)" -ForegroundColor Yellow
            Write-Host "Retrying in $delay seconds..." -ForegroundColor Gray

            Start-Sleep -Seconds $delay
        }
    }
}
function Show-RJGenericMenu {
    param(
        [Parameter(Mandatory)]
        [string]$Title,

        [Parameter(Mandatory)]
        [string]$Prompt,

        [Parameter(Mandatory)]
        [PSCustomObject[]]$Options,

        [switch]$AllowEscape,

        [string[]]$ExtraInstructions,

        [string]$EscapePrompt = "Press Esc to return to main menu"
    )

    $selectedIndex = 0
    $key = $null

    while ($key -ne 13) { # 13 = Enter key
        Clear-Host
        Write-Host $Title -ForegroundColor White
        Write-Host ("-" * 50) -ForegroundColor DarkGray
        Write-Host ""
        Write-Host $Prompt -ForegroundColor White
        Write-Host ""

        for ($i = 0; $i -lt $Options.Count; $i++) {
            if ($i -eq $selectedIndex) {
                Write-Host " > $($Options[$i].Display)" -ForegroundColor White -NoNewline
                Write-Host " - $($Options[$i].Description)" -ForegroundColor Gray
            } else {
                Write-Host " $($Options[$i].Display)" -ForegroundColor DarkGray -NoNewline
                Write-Host " - $($Options[$i].Description)" -ForegroundColor DarkGray
            }
        }

        Write-Host ""
        Write-Host ("-" * 50) -ForegroundColor DarkGray

        # Build instruction text
        $maxOption = $Options.Count
        $instructionText = "Use arrow keys to navigate, Enter to select, or press 1-$maxOption"
        Write-Host $instructionText -ForegroundColor DarkGray

        if ($AllowEscape) {
            Write-Host $EscapePrompt -ForegroundColor DarkGray
        }

        if ($ExtraInstructions) {
            foreach ($instruction in $ExtraInstructions) {
                Write-Host $instruction -ForegroundColor DarkGray
            }
        }

        $keyInput = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
        $key = $keyInput.VirtualKeyCode

        switch ($key) {
            38 { # Up arrow
                if ($selectedIndex -gt 0) {
                    $selectedIndex--
                }
            }
            40 { # Down arrow
                if ($selectedIndex -lt ($Options.Count - 1)) {
                    $selectedIndex++
                }
            }
            27 { # Escape key
                if ($AllowEscape) {
                    return $null
                }
            }
            default {
                # Handle number keys (49-57 = keys 1-9)
                $numberKey = $key - 48
                if ($numberKey -ge 1 -and $numberKey -le $Options.Count) {
                    $selectedIndex = $numberKey - 1
                    $key = 13 # Trigger selection
                }
            }
        }
    }

    return $Options[$selectedIndex].Key
}

function Show-RJGenericMultiSelectMenu {
    param(
        [Parameter(Mandatory)]
        [string]$Title,

        [Parameter(Mandatory)]
        [string]$Prompt,

        [Parameter(Mandatory)]
        [PSCustomObject[]]$Items,

        [string[]]$DefaultSelected = @(),

        [switch]$NoClearHost,

        [string]$SelectedIndicator = "X",

        [string]$SelectedColor = "White",

        [string]$EscapePrompt = "Press ESC to return to main menu"
    )

    # Initialize selections
    $selections = @{}
    foreach ($item in $Items) {
        $selections[$item.Name] = $DefaultSelected -contains $item.Name
    }

    $itemNames = $Items | ForEach-Object { $_.Name }
    $selectedIndex = 0
    $key = $null

    while ($key -ne 13) { # 13 = Enter key
        if (-not $NoClearHost) {
            Clear-Host
        }
        Write-Host $Title -ForegroundColor White
        Write-Host ("-" * 50) -ForegroundColor DarkGray
        Write-Host ""
        Write-Host $Prompt -ForegroundColor White
        Write-Host ""

        for ($i = 0; $i -lt $itemNames.Count; $i++) {
            $itemName = $itemNames[$i]
            $item = $Items | Where-Object { $_.Name -eq $itemName }

            if ($i -eq $selectedIndex) {
                Write-Host " > " -NoNewline -ForegroundColor White
            } else {
                Write-Host " " -NoNewline
            }

            if ($selections[$itemName]) {
                Write-Host "[$SelectedIndicator] " -NoNewline -ForegroundColor $SelectedColor
            } else {
                Write-Host "[ ] " -NoNewline -ForegroundColor DarkGray
            }

            if ($i -eq $selectedIndex) {
                Write-Host "$itemName" -ForegroundColor White -NoNewline
            } else {
                Write-Host "$itemName" -ForegroundColor Gray -NoNewline
            }

            Write-Host " - $($item.Description)" -ForegroundColor DarkGray
        }

        Write-Host ""
        Write-Host ("-" * 50) -ForegroundColor DarkGray
        Write-Host "Space: Toggle | A: All | N: None | Enter: Continue | $EscapePrompt" -ForegroundColor DarkGray

        $keyInput = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
        $key = $keyInput.VirtualKeyCode

        switch ($key) {
            38 { # Up arrow
                if ($selectedIndex -gt 0) {
                    $selectedIndex--
                }
            }
            40 { # Down arrow
                if ($selectedIndex -lt ($itemNames.Count - 1)) {
                    $selectedIndex++
                }
            }
            32 { # Space bar
                $currentItem = $itemNames[$selectedIndex]
                $selections[$currentItem] = -not $selections[$currentItem]
            }
            65 { # 'A' key - Select all
                foreach ($itemName in $itemNames) {
                    $selections[$itemName] = $true
                }
            }
            78 { # 'N' key - Select none
                foreach ($itemName in $itemNames) {
                    $selections[$itemName] = $false
                }
            }
            27 { # Escape key
                return $null
            }
        }
    }

    # Return selected items
    $selectedItems = @()
    foreach ($itemName in $itemNames) {
        if ($selections[$itemName]) {
            $selectedItems += $itemName
        }
    }

    return $selectedItems
}