modules/HomeLab.UI/HomeLab.Ui.psm1

<#
.SYNOPSIS
    HomeLab.UI PowerShell Module
.DESCRIPTION
    A PowerShell module for managing HomeLab Azure infrastructure through a text-based UI.
.NOTES
    Author: Jurie Smit
    Date: March 9, 2025
#>


# ===== CRITICAL SECTION: PREVENT INFINITE LOOPS =====
# Save original preferences to restore later
$originalPSModuleAutoLoadingPreference = $PSModuleAutoLoadingPreference
$originalDebugPreference = $DebugPreference
$originalVerbosePreference = $VerbosePreference
$originalErrorActionPreference = $ErrorActionPreference

# Disable automatic module loading to prevent recursive loading
$PSModuleAutoLoadingPreference = 'None'
# Disable debugging which can cause infinite loops
$DebugPreference = 'SilentlyContinue'
# Control verbosity
$VerbosePreference = 'SilentlyContinue'
# Make errors non-terminating
$ErrorActionPreference = 'Continue'

# Create a guard to prevent recursive loading
if ($script:IsLoading) {
    Write-Warning "Module is already loading. Preventing recursive loading."
    # Restore original preferences
    $PSModuleAutoLoadingPreference = $originalPSModuleAutoLoadingPreference
    $DebugPreference = $originalDebugPreference
    $VerbosePreference = $originalVerbosePreference
    $ErrorActionPreference = $originalErrorActionPreference
    return
}
$script:IsLoading = $true

try {
    # Get the directory where this script is located
    $ModulePath = $PSScriptRoot
    $ModuleName = (Get-Item $PSScriptRoot).BaseName

    # Define the functions to export based on the manifest
    $FunctionsToExport = @(
        # Main functions
        'Show-DeploymentSummary',
        'Show-Menu',
        
        # Menu display functions
        'Show-DeployMenu',
        'Show-VpnCertMenu',
        'Show-VpnGatewayMenu',
        'Show-VpnClientMenu',
        'Show-NatGatewayMenu',
        'Show-DocumentationMenu',
        'Show-SettingsMenu',
        'Show-MainMenu',
        
        # Menu handler functions
        'Invoke-MainMenu',
        'Invoke-DeployMenu',
        'Invoke-VpnCertMenu',
        'Invoke-VpnGatewayMenu',
        'Invoke-VpnClientMenu',
        'Invoke-NatGatewayMenu',
        'Invoke-DocumentationMenu',
        'Invoke-SettingsMenu',
        
        # Utility functions
        'Write-ColorOutput',
        'Clear-CurrentLine',
        'Get-WindowSize',
        
        # Progress bar functions
        'Show-ProgressBar',
        'Start-ProgressTask',
        'Update-ProgressBar',
        
        # Deployment module functions
        'Invoke-FullDeployment',
        'Invoke-NetworkDeployment',
        'Invoke-VPNGatewayDeployment',
        'Invoke-NATGatewayDeployment',
        'Show-DeploymentStatus',
        'Show-BackgroundMonitoringStatus'
    )

    # Load private functions
    $privatePath = Join-Path -Path $ModulePath -ChildPath "Private"
    if (Test-Path -Path $privatePath) {
        $privateFiles = Get-ChildItem -Path $privatePath -Filter "*.ps1" -Recurse
        foreach ($file in $privateFiles) {
            try {
                . $file.FullName
                Write-Verbose "Imported private function file: $($file.Name)"
            }
            catch {
                Write-Error "Failed to import private function file: $($file.FullName): $_"
            }
        }
    }

    # Load public functions - handlers
    $handlersPath = Join-Path -Path $ModulePath -ChildPath "Public\Handlers"
    if (Test-Path -Path $handlersPath) {
        $handlerFiles = Get-ChildItem -Path $handlersPath -Filter "*.ps1" -Recurse
        foreach ($file in $handlerFiles) {
            try {
                . $file.FullName
                Write-Verbose "Imported handler function file: $($file.Name)"
            }
            catch {
                Write-Error "Failed to import handler function file: $($file.FullName): $_"
            }
        }
    }

    # Load public functions - menu
    $menuPath = Join-Path -Path $ModulePath -ChildPath "Public\Menu"
    if (Test-Path -Path $menuPath) {
        $menuFiles = Get-ChildItem -Path $menuPath -Filter "*.ps1" -Recurse
        foreach ($file in $menuFiles) {
            try {
                . $file.FullName
                Write-Verbose "Imported menu function file: $($file.Name)"
            }
            catch {
                Write-Error "Failed to import menu function file: $($file.FullName): $_"
            }
        }
    }
    
    # Load deployment module functions
    $deploymentModulePath = Join-Path -Path $ModulePath -ChildPath "Public\DeploymentModule"
    if (Test-Path -Path $deploymentModulePath) {
        $deploymentFiles = Get-ChildItem -Path $deploymentModulePath -Filter "*.ps1" -Recurse
        foreach ($file in $deploymentFiles) {
            try {
                . $file.FullName
                Write-Verbose "Imported deployment module function file: $($file.Name)"
            }
            catch {
                Write-Error "Failed to import deployment module function file: $($file.FullName): $_"
            }
        }
    }

    # Load other public functions
    $publicPath = Join-Path -Path $ModulePath -ChildPath "Public"
    $otherPublicFiles = Get-ChildItem -Path $publicPath -Filter "*.ps1" -Exclude "Handlers", "Menu", "DeploymentModule" -Recurse
    foreach ($file in $otherPublicFiles) {
        try {
            . $file.FullName
            Write-Verbose "Imported public function file: $($file.Name)"
        }
        catch {
            Write-Error "Failed to import public function file: $($file.FullName): $_"
        }
    }

    # Display functions defined in this module
    $moduleFunctions = Get-ChildItem -Path Function:\ | Where-Object {
        $_.ScriptBlock.File -and $_.ScriptBlock.File.Contains($ModulePath)
    } | Select-Object -ExpandProperty Name

    Write-Host "Functions defined in this module:" -ForegroundColor Cyan
    if ($moduleFunctions) {
        $moduleFunctions | ForEach-Object { Write-Host " - $_" -ForegroundColor Cyan }
    } else {
        # Fallback to listing all functions that match our export list
        $FunctionsToExport | ForEach-Object { 
            if (Get-Command -Name $_ -ErrorAction SilentlyContinue) {
                Write-Host " - $_" -ForegroundColor Cyan 
            }
        }
    }

    # Export public functions
    Export-ModuleMember -Function $FunctionsToExport
}
finally {
    # Reset module loading guard
    $script:IsLoading = $false
    
    # Restore original preferences
    $PSModuleAutoLoadingPreference = $originalPSModuleAutoLoadingPreference
    $DebugPreference = $originalDebugPreference
    $VerbosePreference = $originalVerbosePreference
    $ErrorActionPreference = $originalErrorActionPreference
}