Functions/Public/Show-StopwatchSummary.ps1

function Show-StopwatchSummary {
    <#
    .SYNOPSIS
        Displays a formatted summary of all stopwatch timings.
 
    .DESCRIPTION
        Prints a nicely formatted table of all completed stopwatch results,
        sorted by duration (longest first). Useful for performance analysis
        and identifying bottlenecks.
 
    .PARAMETER Name
        Optional. Filter to show only stopwatches matching this pattern.
        Supports wildcards.
 
    .PARAMETER SortBy
        How to sort the results:
        - Duration (default): Longest to shortest
        - Name: Alphabetical order
        - StartTime: Chronological order
 
    .PARAMETER Descending
        Sort in descending order (default for Duration).
 
    .PARAMETER Ascending
        Sort in ascending order.
 
    .PARAMETER IncludeRunning
        Also shows currently running stopwatches (not yet stopped).
 
    .PARAMETER Title
        Custom title for the summary header.
        Default: "Performance Summary"
 
    .PARAMETER NoHeader
        Suppresses the header/title display.
 
    .OUTPUTS
        None. Writes formatted output to the host.
 
    .EXAMPLE
        Show-StopwatchSummary
        # Shows all completed stopwatch timings
 
    .EXAMPLE
        Show-StopwatchSummary -Name "API*" -Title "API Performance"
        # Shows only API-related timings with custom title
 
    .EXAMPLE
        Show-StopwatchSummary -IncludeRunning
        # Also shows stopwatches that haven't been stopped yet
 
    .EXAMPLE
        Show-StopwatchSummary -SortBy Name -Ascending
        # Shows results sorted alphabetically
 
    .NOTES
        Author: Sune Alexandersen Narud
        Version: 1.0.0
        Date: February 2026
 
    .LINK
        Start-Stopwatch
        Stop-Stopwatch
        Get-Stopwatch
        Reset-Stopwatch
    #>


    [CmdletBinding()]
    [OutputType([void])]
    param(
        [Parameter(Position = 0)]
        [SupportsWildcards()]
        [string]$Name = '*',

        [Parameter()]
        [ValidateSet('Duration', 'Name', 'StartTime')]
        [string]$SortBy = 'Duration',

        [Parameter()]
        [switch]$Descending,

        [Parameter()]
        [switch]$Ascending,

        [Parameter()]
        [switch]$IncludeRunning,

        [Parameter()]
        [string]$Title = 'Performance Summary',

        [Parameter()]
        [switch]$NoHeader
    )

    # Collect results
    $results = @()

    # Get completed stopwatches
    if ($Global:OrionStopwatchResults) {
        foreach ($key in $Global:OrionStopwatchResults.Keys) {
            if ($key -like $Name) {
                $result = $Global:OrionStopwatchResults[$key]
                $results += [PSCustomObject]@{
                    Name         = $result.Name
                    Status       = 'Completed'
                    StartTime    = $result.StartTime
                    Duration     = $result.Duration
                    TotalSeconds = $result.TotalSeconds
                }
            }
        }
    }

    # Optionally include running stopwatches
    if ($IncludeRunning -and $Global:OrionStopwatches) {
        $now = [DateTime]::Now
        foreach ($key in $Global:OrionStopwatches.Keys) {
            if ($key -like $Name) {
                $startTime = $Global:OrionStopwatches[$key]
                $elapsed = $now - $startTime
                $results += [PSCustomObject]@{
                    Name         = $key
                    Status       = 'Running'
                    StartTime    = $startTime
                    Duration     = $elapsed
                    TotalSeconds = $elapsed.TotalSeconds
                }
            }
        }
    }

    # Check if we have any results
    if ($results.Count -eq 0) {
        Write-Host ""
        Write-Host " No stopwatch data available." -ForegroundColor Yellow
        Write-Host " Use Start-Stopwatch and Stop-Stopwatch to record timings." -ForegroundColor DarkGray
        Write-Host ""
        return
    }

    # Determine sort order
    $sortDescending = switch ($SortBy) {
        'Duration' { -not $Ascending }  # Default descending for duration
        'Name' { $Descending }          # Default ascending for name
        'StartTime' { $Descending }     # Default ascending for time
    }

    # Sort results
    $sortProperty = switch ($SortBy) {
        'Duration' { 'TotalSeconds' }
        'Name' { 'Name' }
        'StartTime' { 'StartTime' }
    }
    $results = $results | Sort-Object -Property $sortProperty -Descending:$sortDescending

    # Calculate column widths
    $maxNameLength = ($results.Name | Measure-Object -Property Length -Maximum).Maximum
    $maxNameLength = [Math]::Max($maxNameLength, 4)  # Minimum width for "Name" header
    $timeWidth = 15  # Fixed width for time column
    $boxWidth = $maxNameLength + $timeWidth + 6  # 6 = "· " + " " spacing

    # Display header
    if (-not $NoHeader) {
        Write-Host ""
        $headerLine = "═" * $boxWidth
        Write-Host " ╔$headerLine╗" -ForegroundColor DarkCyan
        $paddedTitle = " $Title ".PadRight($boxWidth)
        Write-Host " ║" -ForegroundColor DarkCyan -NoNewline
        Write-Host "$paddedTitle" -ForegroundColor Cyan -NoNewline
        Write-Host "║" -ForegroundColor DarkCyan
        Write-Host " ╠$headerLine╣" -ForegroundColor DarkCyan
    }

    # Calculate total time
    $totalSeconds = ($results | Measure-Object -Property TotalSeconds -Sum).Sum

    # Display each row
    foreach ($item in $results) {
        $paddedName = $item.Name.PadRight($maxNameLength)
        
        # Format the duration
        $formattedTime = if (Get-Command -Name 'Format-TimeSpan' -ErrorAction SilentlyContinue) {
            Format-TimeSpan -TimeSpan $item.Duration
        }
        else {
            $ts = $item.TotalSeconds
            if ($ts -lt 60) {
                "$([math]::Round($ts, 1)) sec"
            }
            else {
                $m = [int]($ts / 60)
                $s = [int]($ts % 60)
                "$m min $s sec"
            }
        }
        $formattedTime = $formattedTime.PadLeft($timeWidth)

        # Status indicator and row content
        Write-Host " ║ " -ForegroundColor DarkCyan -NoNewline
        if ($item.Status -eq 'Running') {
            Write-Host "» " -ForegroundColor Yellow -NoNewline
        }
        else {
            Write-Host "· " -ForegroundColor Green -NoNewline
        }
        Write-Host "$paddedName" -ForegroundColor White -NoNewline
        Write-Host " $formattedTime" -ForegroundColor Yellow -NoNewline
        Write-Host " ║" -ForegroundColor DarkCyan
    }

    # Display footer with total
    if (-not $NoHeader) {
        $footerLine = "─" * $boxWidth
        Write-Host " ╠$footerLine╣" -ForegroundColor DarkCyan
        
        $totalFormatted = if (Get-Command -Name 'Format-TimeSpan' -ErrorAction SilentlyContinue) {
            Format-TimeSpan -TimeSpan ([TimeSpan]::FromSeconds($totalSeconds))
        }
        else {
            if ($totalSeconds -lt 60) {
                "$([math]::Round($totalSeconds, 1)) sec"
            }
            else {
                $m = [int]($totalSeconds / 60)
                $s = [int]($totalSeconds % 60)
                "$m min $s sec"
            }
        }
        
        $totalLabel = " TOTAL".PadRight($maxNameLength + 2)
        $totalFormatted = $totalFormatted.PadLeft($timeWidth)
        Write-Host " ║ " -ForegroundColor DarkCyan -NoNewline
        Write-Host "$totalLabel" -ForegroundColor Cyan -NoNewline
        Write-Host " $totalFormatted" -ForegroundColor Magenta -NoNewline
        Write-Host " ║" -ForegroundColor DarkCyan
        
        $closeLine = "═" * $boxWidth
        Write-Host " ╚$closeLine╝" -ForegroundColor DarkCyan
        Write-Host ""
    }
}