functions/private/Filter-KlippyItemByWildcard.ps1

function Filter-KlippyItemByWildcard {
    <#
    .SYNOPSIS
        Filters file/folder items by wildcard pattern.

    .DESCRIPTION
        Performs case-insensitive wildcard matching on file/folder names.
        Matches against leaf name only (not full path).

    .PARAMETER Items
        Collection of items to filter.

    .PARAMETER Pattern
        Wildcard pattern to match.

    .PARAMETER PathProperty
        The property name containing the path. Default is 'Path'.

    .PARAMETER RequireSingle
        If true, throws an error if multiple items match.

    .OUTPUTS
        Filtered collection of items.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [AllowEmptyCollection()]
        $Items,

        [Parameter(Mandatory = $true)]
        [string]$Pattern,

        [Parameter()]
        [string]$PathProperty = 'Path',

        [Parameter()]
        [switch]$RequireSingle
    )

    begin {
        $allItems = [System.Collections.Generic.List[object]]::new()
    }

    process {
        foreach ($item in $Items) {
            $allItems.Add($item)
        }
    }

    end {
        # If pattern has no wildcards, match exactly
        $hasWildcard = $Pattern -match '[\*\?\[\]]'

        $matches = foreach ($item in $allItems) {
            $path = $item.$PathProperty
            if (-not $path) { continue }

            $leafName = Split-Path $path -Leaf

            if ($hasWildcard) {
                # Wildcard matching (case-insensitive)
                if ($leafName -like $Pattern -or $path -like $Pattern) {
                    $item
                }
            }
            else {
                # Exact matching (case-insensitive)
                if ($leafName -ieq $Pattern -or $path -ieq $Pattern) {
                    $item
                }
            }
        }

        # Convert to array
        $matchArray = @($matches)

        if ($RequireSingle) {
            if ($matchArray.Count -eq 0) {
                throw "No items matching '$Pattern' found."
            }
            if ($matchArray.Count -gt 1) {
                $names = ($matchArray | Select-Object -First 5 | ForEach-Object { $_.$PathProperty }) -join ', '
                throw "Multiple items match '$Pattern': $names. Please be more specific."
            }
            return $matchArray[0]
        }

        return $matchArray
    }
}