functions/public/Add-KlippyPrinter.ps1

function Add-KlippyPrinter {
    <#
    .SYNOPSIS
        Adds a new Klipper printer to the local registry.

    .DESCRIPTION
        Registers a new Klipper printer configuration. Tests connectivity before adding.
        The first printer added is automatically set as default.

    .PARAMETER PrinterName
        The friendly name for the printer. Must be unique.

    .PARAMETER Uri
        The Moonraker API URI (e.g., http://192.168.1.100:7125).

    .PARAMETER ApiKey
        Optional API key for authentication.

    .PARAMETER Description
        Optional description of the printer.

    .PARAMETER IsDefault
        Set this printer as the default.

    .PARAMETER SkipConnectionTest
        Skip the connection test before adding.

    .PARAMETER Force
        Add the printer even if connection test fails.

    .EXAMPLE
        Add-KlippyPrinter -PrinterName "Voron" -Uri "http://192.168.1.100:7125"
        Adds a printer named "Voron" after testing connectivity.

    .EXAMPLE
        Add-KlippyPrinter -PrinterName "Ender3" -Uri "http://192.168.1.101:7125" -IsDefault
        Adds a printer and sets it as default.

    .OUTPUTS
        PSCustomObject - The newly created printer object.
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('^[a-zA-Z0-9_\-\.\s]+$')]
        [string]$PrinterName,

        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
            $uri = $null
            if ([System.Uri]::TryCreate($_, [System.UriKind]::Absolute, [ref]$uri)) {
                if ($uri.Scheme -in @('http', 'https')) {
                    return $true
                }
                throw "Uri must use http or https scheme."
            }
            throw "Invalid URI format."
        })]
        [string]$Uri,

        [Parameter()]
        [string]$ApiKey,

        [Parameter()]
        [string]$Description,

        [Parameter()]
        [switch]$IsDefault,

        [Parameter()]
        [switch]$SkipConnectionTest,

        [Parameter()]
        [switch]$Force
    )

    # Read existing printers
    $printers = Read-KlippyPrinterRegistry

    # Check for duplicate name (case-insensitive)
    $existingPrinter = $printers | Where-Object { $_.PrinterName -ieq $PrinterName }
    if ($existingPrinter) {
        throw "A printer with name '$PrinterName' already exists. Use Set-KlippyPrinter to modify or choose a different name."
    }

    # Normalize URI
    $normalizedUri = $Uri.TrimEnd('/')

    # Test connection unless skipped
    if (-not $SkipConnectionTest) {
        Write-Verbose "Testing connection to $normalizedUri..."

        $testResult = Test-KlippyPrinterConnection -Uri $normalizedUri -ApiKey $ApiKey -Full

        if (-not $testResult.MoonrakerReachable) {
            $errorMsg = "Connection test failed: $($testResult.ErrorMessage)"
            if ($Force) {
                Write-Warning $errorMsg
                Write-Warning "Adding printer anyway due to -Force."
            }
            else {
                throw "$errorMsg`nUse -Force to add anyway, or -SkipConnectionTest to skip testing."
            }
        }
        elseif (-not $testResult.KlipperReady) {
            Write-Warning "Moonraker is reachable but Klipper is not ready: $($testResult.ErrorMessage)"
            if (-not $Force) {
                Write-Warning "Printer will be added. Use -Force to suppress this warning."
            }
        }
        else {
            Write-Verbose "Connection test passed. Moonraker: $($testResult.MoonrakerVersion), Klipper: $($testResult.KlipperState)"
        }
    }

    # Determine if this should be default
    $setAsDefault = $IsDefault.IsPresent
    if ($printers.Count -eq 0) {
        $setAsDefault = $true
        Write-Verbose "First printer - automatically setting as default."
    }

    # If setting as default, clear existing default
    if ($setAsDefault -and $printers.Count -gt 0) {
        foreach ($p in $printers) {
            if ($p.IsDefault) {
                $p.IsDefault = $false
                $p.ModifiedAt = [datetime]::UtcNow
            }
        }
    }

    # Create new printer object
    $now = [datetime]::UtcNow
    $newPrinter = [PSCustomObject]@{
        PSTypeName   = 'KlippyCLI.Printer'
        Id           = [System.Guid]::NewGuid().ToString()
        PrinterName  = $PrinterName
        Uri          = $normalizedUri
        ApiKey       = $ApiKey
        Description  = $Description
        IsDefault    = $setAsDefault
        CreatedAt    = $now
        ModifiedAt   = $now
    }

    if ($PSCmdlet.ShouldProcess($PrinterName, "Add printer")) {
        # Add to collection and save
        $printers.Add($newPrinter)
        Write-KlippyPrinterRegistry -Printers $printers

        Write-Verbose "Printer '$PrinterName' added successfully."

        if ($setAsDefault) {
            Write-Verbose "Printer '$PrinterName' set as default."
        }

        return $newPrinter
    }
}