functions/public/Get-KlippyFile.ps1

function Get-KlippyFile {
    <#
    .SYNOPSIS
        Gets files from a Klipper printer by root.

    .DESCRIPTION
        Lists files from a specified Moonraker file root such as gcodes,
        config, or logs. Supports wildcard filtering and recursive listing.

    .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 Root
        The file root to query (e.g., "gcodes", "config", "logs").

    .PARAMETER Path
        Path filter or subdirectory to list. Supports wildcards.

    .PARAMETER Recurse
        Include files from subdirectories.

    .EXAMPLE
        Get-KlippyFile -Root "config"
        Lists all config files.

    .EXAMPLE
        Get-KlippyFile -Root "logs" -Path "*.log"
        Lists log files matching a wildcard.

    .EXAMPLE
        Get-KlippyFile -Root "gcodes" -Path "benchy*" -Recurse
        Lists matching files including subdirectories.

    .OUTPUTS
        PSCustomObject[] with file information.
    #>

    [CmdletBinding(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)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('gcodes', 'config', 'logs')]
        [string]$Root,

        [Parameter(Position = 0)]
        [string]$Path,

        [Parameter()]
        [switch]$Recurse
    )

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

        $printer = Resolve-KlippyPrinterTarget @resolveParams

        try {
            Write-Verbose "[$($printer.PrinterName)] Fetching file list from '$Root'..."

            $files = Invoke-KlippyHttpRequest -Printer $printer -Endpoint "server/files/list" -QueryParameters @{ root = $Root }

            # Filter to files only (exclude directories)
            $fileList = $files | Where-Object { -not $_.Dirname }

            # Apply path filter if specified
            if ($Path) {
                $hasWildcard = $Path -match '[\*\?\[\]]'

                if ($hasWildcard) {
                    $fileList = $fileList | Filter-KlippyItemByWildcard -Pattern $Path
                }
                else {
                    $pathPrefix = $Path.TrimEnd('/')
                    $fileList = $fileList | Where-Object {
                        $_.Path -like "$pathPrefix/*" -or $_.Path -ieq $Path
                    }
                }
            }

            # Filter by recursion
            if (-not $Recurse -and -not $Path) {
                $fileList = $fileList | Where-Object { $_.Path -notmatch '/' }
            }

            $results = foreach ($file in $fileList) {
                [PSCustomObject]@{
                    PSTypeName  = 'KlippyCLI.File'
                    PrinterId   = $printer.Id
                    PrinterName = $printer.PrinterName
                    Root        = $Root
                    Path        = $file.Path
                    Name        = Split-Path $file.Path -Leaf
                    Size        = $file.Size
                    SizeMB      = [Math]::Round($file.Size / 1MB, 2)
                    Modified    = if ($file.Modified) { [DateTimeOffset]::FromUnixTimeSeconds([long]$file.Modified).LocalDateTime } else { $null }
                }
            }

            return $results
        }
        catch {
            Write-Error "[$($printer.PrinterName)] Failed to list files: $_"
        }
    }
}