functions/public/Wait-KlippyPrintStarted.ps1

function Wait-KlippyPrintStarted {
    <#
    .SYNOPSIS
        Waits for a print job to start on a Klipper printer.

    .DESCRIPTION
        Monitors the print_stats state via WebSocket and waits until the
        print state becomes "printing".

    .PARAMETER Id
        The unique identifier of the printer.

    .PARAMETER PrinterName
        The friendly name of the printer.

    .PARAMETER InputObject
        A printer object from pipeline input.

    .PARAMETER Timeout
        Maximum time to wait in seconds. Default is 300 (5 minutes).

    .PARAMETER Quiet
        Suppress progress messages.

    .EXAMPLE
        Wait-KlippyPrintStarted -PrinterName "voronv2"
        Waits for a print to start.

    .EXAMPLE
        Start-KlippyPrint -Filename "test.gcode" | Wait-KlippyPrintStarted
        Starts a print and waits for it to begin.

    .OUTPUTS
        PSCustomObject with print state information.
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [string]$Id,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByName', Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$PrinterName,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByObject', ValueFromPipeline = $true)]
        [PSCustomObject]$InputObject,

        [Parameter()]
        [ValidateRange(1, 3600)]
        [int]$Timeout = 300,

        [Parameter()]
        [switch]$Quiet
    )

    process {
        # Resolve printer
        $resolveParams = @{}
        switch ($PSCmdlet.ParameterSetName) {
            'ById' { $resolveParams['Id'] = $Id }
            'ByName' { $resolveParams['PrinterName'] = $PrinterName }
            'ByObject' { $resolveParams['InputObject'] = $InputObject }
        }

        $printer = Resolve-KlippyPrinterTarget @resolveParams

        # Check current state
        try {
            $printStats = Get-KlippyObject -PrinterName $printer.PrinterName -ObjectName "print_stats"
            if ($printStats.State -eq 'printing') {
                if (-not $Quiet) {
                    Write-Host "[$($printer.PrinterName)] Already printing: $($printStats.Filename)"
                }
                return [PSCustomObject]@{
                    PSTypeName   = 'KlippyCLI.WaitResult'
                    PrinterId    = $printer.Id
                    PrinterName  = $printer.PrinterName
                    State        = 'printing'
                    Filename     = $printStats.Filename
                    WaitTime     = [TimeSpan]::Zero
                    Success      = $true
                }
            }
        }
        catch {
            Write-Verbose "Could not get current print state: $_"
        }

        if (-not $Quiet) {
            Write-Host "[$($printer.PrinterName)] Waiting for print to start..." -NoNewline
        }

        $startTime = [datetime]::UtcNow
        $ws = $null
        $lastState = 'unknown'
        $filename = ''

        try {
            $ws = New-KlippyWebSocketClient -Printer $printer
            $null = $ws.Subscribe(@{ print_stats = @('state', 'filename') })

            $deadline = [datetime]::UtcNow.AddSeconds($Timeout)

            while ([datetime]::UtcNow -lt $deadline) {
                $message = $ws.Receive(2000)

                if ($null -ne $message -and $message.method -eq 'notify_status_update' -and $message.params) {
                    $status = $message.params[0]

                    if ($status.print_stats) {
                        if ($status.print_stats.state) {
                            $lastState = $status.print_stats.state
                        }
                        if ($status.print_stats.filename) {
                            $filename = $status.print_stats.filename
                        }

                        if ($lastState -eq 'printing') {
                            if (-not $Quiet) {
                                Write-Host " Started! ($filename)"
                            }

                            return [PSCustomObject]@{
                                PSTypeName   = 'KlippyCLI.WaitResult'
                                PrinterId    = $printer.Id
                                PrinterName  = $printer.PrinterName
                                State        = 'printing'
                                Filename     = $filename
                                WaitTime     = [datetime]::UtcNow - $startTime
                                Success      = $true
                            }
                        }
                    }
                }

                if (-not $Quiet) {
                    Write-Host "." -NoNewline
                }
            }

            # Timeout
            if (-not $Quiet) {
                Write-Host " Timeout!"
            }

            Write-Warning "[$($printer.PrinterName)] Timeout waiting for print to start after $Timeout seconds. State: $lastState"

            return [PSCustomObject]@{
                PSTypeName   = 'KlippyCLI.WaitResult'
                PrinterId    = $printer.Id
                PrinterName  = $printer.PrinterName
                State        = $lastState
                Filename     = $filename
                WaitTime     = [datetime]::UtcNow - $startTime
                Success      = $false
            }
        }
        catch {
            if (-not $Quiet) {
                Write-Host " Error!"
            }
            Write-Error "[$($printer.PrinterName)] Error waiting for print to start: $_"

            return [PSCustomObject]@{
                PSTypeName   = 'KlippyCLI.WaitResult'
                PrinterId    = $printer.Id
                PrinterName  = $printer.PrinterName
                State        = $lastState
                Filename     = $filename
                WaitTime     = [datetime]::UtcNow - $startTime
                Success      = $false
                Error        = $_.Exception.Message
            }
        }
        finally {
            if ($ws) {
                $ws.Close()
            }
        }
    }
}