functions/public/Move-KlippyGcodeItem.ps1

function Move-KlippyGcodeItem {
    <#
    .SYNOPSIS
        Moves or renames a G-code file or folder on a Klipper printer.

    .DESCRIPTION
        Moves a file or folder to a new location within the printer's gcodes storage.
        Can also be used to rename items by specifying a new name in the destination.
        Supports pipeline input from Get-KlippyGcodeFile or Get-KlippyGcodeFolder.

    .PARAMETER Id
        The unique identifier of the printer.

    .PARAMETER PrinterName
        The friendly name of the printer.

    .PARAMETER InputObject
        A GcodeFile or GcodeFolder object from pipeline input.

    .PARAMETER Path
        Source path of the item to move.

    .PARAMETER Destination
        Destination path for the item.

    .PARAMETER PassThru
        Return the moved item object.

    .EXAMPLE
        Move-KlippyGcodeItem -Path "benchy.gcode" -Destination "archive/benchy.gcode"
        Moves a file to a subfolder.

    .EXAMPLE
        Move-KlippyGcodeItem -Path "test.gcode" -Destination "test_v2.gcode"
        Renames a file.

    .EXAMPLE
        Get-KlippyGcodeFile -Path "*.tmp" | Move-KlippyGcodeItem -Destination "temp/"
        Moves all .tmp files to temp folder.

    .OUTPUTS
        PSCustomObject with item information (when -PassThru is used).
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $true)]
    [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, ParameterSetName = 'Default')]
        [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ById')]
        [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ByName')]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateNotNullOrEmpty()]
        [string]$Destination,

        [Parameter()]
        [switch]$PassThru
    )

    process {
        # Determine source path and printer
        if ($PSCmdlet.ParameterSetName -eq 'ByObject') {
            $printer = Resolve-KlippyPrinterTarget -Id $InputObject.PrinterId
            $sourcePath = $InputObject.Path
            $isDirectory = $InputObject.PSObject.TypeNames -contains 'KlippyCLI.GcodeFolder'
        }
        else {
            # Resolve printer
            $resolveParams = @{}
            switch ($PSCmdlet.ParameterSetName) {
                'ById' { $resolveParams['Id'] = $Id }
                'ByName' { $resolveParams['PrinterName'] = $PrinterName }
            }

            $printer = Resolve-KlippyPrinterTarget @resolveParams
            $sourcePath = $Path.TrimStart('/')
            $isDirectory = $false  # Will be determined by API
        }

        # Clean destination path
        $destPath = $Destination.TrimStart('/')

        # If destination ends with /, append source filename
        if ($destPath.EndsWith('/')) {
            $destPath = $destPath + (Split-Path $sourcePath -Leaf)
        }

        if ($PSCmdlet.ShouldProcess("$($printer.PrinterName):gcodes/$sourcePath -> gcodes/$destPath", "Move item")) {
            try {
                Write-Verbose "[$($printer.PrinterName)] Moving: $sourcePath -> $destPath"

                $response = Invoke-KlippyHttpRequest -Printer $printer -Endpoint "server/files/move" -Method POST -QueryParameters @{
                    source = "gcodes/$sourcePath"
                    dest   = "gcodes/$destPath"
                }

                Write-Verbose "[$($printer.PrinterName)] Item moved successfully"

                if ($PassThru) {
                    # Determine the actual result type
                    $resultItem = $response.Item
                    if ($resultItem.Path) {
                        $actualPath = $resultItem.Path -replace '^gcodes/', ''
                    }
                    else {
                        $actualPath = $destPath
                    }

                    if ($isDirectory -or ($resultItem -and $resultItem.Dirname)) {
                        [PSCustomObject]@{
                            PSTypeName  = 'KlippyCLI.GcodeFolder'
                            PrinterId   = $printer.Id
                            PrinterName = $printer.PrinterName
                            Path        = $actualPath
                            Name        = Split-Path $actualPath -Leaf
                            Modified    = Get-Date
                        }
                    }
                    else {
                        [PSCustomObject]@{
                            PSTypeName  = 'KlippyCLI.GcodeFile'
                            PrinterId   = $printer.Id
                            PrinterName = $printer.PrinterName
                            Path        = $actualPath
                            Name        = Split-Path $actualPath -Leaf
                            Size        = $resultItem.Size
                            SizeMB      = if ($resultItem.Size) { [Math]::Round($resultItem.Size / 1MB, 2) } else { $null }
                            Modified    = Get-Date
                        }
                    }
                }
            }
            catch {
                Write-Error "[$($printer.PrinterName)] Failed to move '$sourcePath': $_"
            }
        }
    }
}