private/OTP-UIManager.ps1

function Initialize-OTPUI {
    [CmdletBinding()]
    param()

    try {
        # Check if WPF is available
        if (-not (testWPFAvailable)) {
            Write-Warning "WPF UI is not available in this PowerShell environment. Falling back to console output."
            return $null
        }

        $script:codes = [System.Collections.ObjectModel.ObservableCollection[object]]::new()
        
        # Load XAML from file
        $xamlPath = Join-Path $PSScriptRoot 'OTP-UI.xaml'
        if (-not (Test-Path $xamlPath)) {
            throw "XAML file not found: $xamlPath"
        }

        $xamlContent = Get-Content -Path $xamlPath -Raw
        $stream = [System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($xamlContent))
        
        try {
            # Parse XAML
            $script:window = [System.Windows.Markup.XamlReader]::Load($stream)
            
            # Find controls
            $script:codesGrid = $script:window.FindName('CodesGrid')
            $script:timerText = $script:window.FindName('TimerText')
            $script:refreshButton = $script:window.FindName('RefreshButton')

            # Initialize UI state
            $script:codesGrid.ItemsSource = $script:codes

            # Create WPF UI wrapper class
            $wpfUI = [PSCustomObject]@{
                PSTypeName = 'OTP.WPFUI'
                Window = $script:window
                Codes = $script:codes
                Timer = $script:countdownTimer
            }

            # Add methods
            $wpfUI | Add-Member -MemberType ScriptMethod -Name 'AddCode' -Value {
                param(
                    [Parameter(Mandatory)]
                    [object]$Code
                )
                $this.Codes.Add($Code)
            }

            $wpfUI | Add-Member -MemberType ScriptMethod -Name 'ShowCodes' -Value {
                $script:countdownTimer.Start()
                $null = $this.Window.ShowDialog()
            }

            $wpfUI | Add-Member -MemberType ScriptMethod -Name 'Dispose' -Value {
                if ($this.Timer) {
                    $this.Timer.Stop()
                }
                $this.Window = $null
                $this.Codes.Clear()
            }

            # Add refresh button click handler
            $script:refreshButton.Add_Click({
                Update-OTPDisplay -ResetTimer
            })

            # Create dispatcher timer
            $script:countdownTimer = New-Object System.Windows.Threading.DispatcherTimer -ErrorAction Stop
            $script:countdownTimer.Interval = [TimeSpan]::FromSeconds(1)
            
            # Timer tick handler
            $script:countdownTimer.Add_Tick({
                Update-OTPTimer
            })

            # Window closed handler
            $script:window.Add_Closed({
                if ($wpfUI) {
                    $wpfUI.Dispose()
                }
            })

            if ($VerbosePreference -eq 'Continue') {
                Write-Verbose "WPF UI initialized successfully"
            }

            return $wpfUI
        }
        finally {
            $stream.Dispose()
        }
    }
    catch {
        Write-Warning "Failed to initialize WPF UI: $_"
        Write-Warning "Falling back to console output."
        return $null
    }
}

function Update-OTPDisplay {
    [CmdletBinding()]
    param(
        [switch]$ResetTimer
    )

    try {
        if ($ResetTimer) {
            $script:timerText.Text = "30"
        }
        
        # Update codes and refresh UI
        $updatedCodes = @(updateOtpCodes -inputCodes $script:codes)
        if ($updatedCodes) {
            # Clear existing items and add new ones in batch
            $script:codes.Clear()
            foreach ($code in $updatedCodes) {
                $script:codes.Add($code)
            }

            if ($VerbosePreference -eq 'Continue') {
                Write-Verbose "Updated display with $($updatedCodes.Count) codes at $(Get-Date -Format 'HH:mm:ss')"
            }
        }
    }
    catch {
        Write-Warning "Failed to update display: $_"
    }
}

function Update-OTPTimer {
    try {
        # Calculate remaining seconds until next 30-second interval
        $unixTime = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
        $remainingSeconds = 30 - ($unixTime % 30)
        
        if ($remainingSeconds -eq 30) {
            Update-OTPDisplay
        }
        
        $script:timerText.Text = $remainingSeconds.ToString()
    }
    catch {
        Write-Warning "Failed to update timer: $_"
    }
}

function Cleanup-OTPUI {
    try {
        $script:countdownTimer.Stop()
        $script:window = $null
        $script:codes.Clear()
        [System.GC]::Collect()
    }
    catch {
        Write-Warning "Error during UI cleanup: $_"
    }
}