functions/public/Start-KlippyPrint.ps1

function Start-KlippyPrint {
    <#
    .SYNOPSIS
        Starts a print job on a Klipper printer.

    .DESCRIPTION
        Starts printing a G-code file from the printer's storage.
        Supports wildcards for filename matching (errors if multiple matches).

    .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 Filename
        The filename or path of the G-code file to print.
        Supports wildcards (* and ?). Errors if multiple files match.

    .PARAMETER Wait
        Wait for the print to start before returning.

    .PARAMETER WaitFinish
        Wait for the print to complete before returning.

    .EXAMPLE
        Start-KlippyPrint -Filename "test.gcode"
        Starts printing the specified file on the default printer.

    .EXAMPLE
        Start-KlippyPrint -PrinterName "voronv2" -Filename "*.gcode" -Wait
        Starts the only matching gcode file and waits for print to start.

    .EXAMPLE
        Start-KlippyPrint -Filename "benchy*" -WaitFinish
        Starts the matching file and waits for print to complete.

    .OUTPUTS
        PSCustomObject with print job information.
    #>

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

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

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

        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$Filename,

        [Parameter()]
        [switch]$Wait,

        [Parameter()]
        [switch]$WaitFinish
    )

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

        $printer = Resolve-KlippyPrinterTarget @resolveParams

        # Check if filename contains wildcards
        $resolvedFilename = $Filename
        if ($Filename -match '[\*\?]') {
            Write-Verbose "Resolving wildcard pattern: $Filename"

            # Get file list and match
            $files = Invoke-KlippyHttpRequest -Printer $printer -Endpoint "server/files/list" -QueryParameters @{root = "gcodes"}

            # Match against the pattern (case-insensitive, leaf name only)
            $pattern = $Filename
            $matches = $files | Where-Object {
                $leafName = Split-Path $_.Path -Leaf
                $leafName -like $pattern -or $_.Path -like $pattern
            }

            if ($matches.Count -eq 0) {
                throw "No files matching '$Filename' found on printer '$($printer.PrinterName)'."
            }

            if ($matches.Count -gt 1) {
                $matchList = ($matches | Select-Object -First 5 | ForEach-Object { $_.Path }) -join ", "
                throw "Multiple files match '$Filename': $matchList. Please be more specific."
            }

            $resolvedFilename = $matches[0].Path
            Write-Verbose "Resolved to: $resolvedFilename"
        }

        if ($PSCmdlet.ShouldProcess($printer.PrinterName, "Start print: $resolvedFilename")) {
            try {
                Write-Verbose "[$($printer.PrinterName)] Starting print: $resolvedFilename"

                # Use the print start endpoint
                $endpoint = "printer/print/start?filename=$([System.Uri]::EscapeDataString($resolvedFilename))"
                $null = Invoke-KlippyJsonRpc -Printer $printer -Method $endpoint

                $result = [PSCustomObject]@{
                    PSTypeName  = 'KlippyCLI.PrintJob'
                    PrinterId   = $printer.Id
                    PrinterName = $printer.PrinterName
                    Filename    = $resolvedFilename
                    Action      = 'Started'
                    Success     = $true
                }

                Write-Verbose "[$($printer.PrinterName)] Print started successfully"

                # Wait for print to start if requested
                if ($Wait -or $WaitFinish) {
                    $waitResult = Wait-KlippyPrintStarted -PrinterName $printer.PrinterName -Timeout 120
                    if (-not $waitResult.Success) {
                        Write-Warning "Print may not have started properly"
                    }
                }

                # Wait for print to finish if requested
                if ($WaitFinish) {
                    $finishResult = Wait-KlippyPrintFinished -PrinterName $printer.PrinterName -ShowProgress
                    $result | Add-Member -NotePropertyName 'FinalState' -NotePropertyValue $finishResult.State -Force
                    $result | Add-Member -NotePropertyName 'PrintDuration' -NotePropertyValue $finishResult.PrintDuration -Force
                    $result | Add-Member -NotePropertyName 'Completed' -NotePropertyValue $finishResult.Success -Force
                }

                return $result
            }
            catch {
                Write-Error "[$($printer.PrinterName)] Failed to start print: $_"

                return [PSCustomObject]@{
                    PSTypeName  = 'KlippyCLI.PrintJob'
                    PrinterId   = $printer.Id
                    PrinterName = $printer.PrinterName
                    Filename    = $resolvedFilename
                    Action      = 'StartFailed'
                    Success     = $false
                    Error       = $_.Exception.Message
                }
            }
        }
    }
}