src/public/System/Install-AitherPackage.ps1

function Install-AitherPackage {
    <#
    .SYNOPSIS
        Installs a software package using the appropriate package manager for the OS.

    .DESCRIPTION
        Abstracts package management across Windows (Chocolatey, Winget, Scoop),
        Linux (APT, YUM/DNF, APK), and macOS (Homebrew).
        Detects the available package manager and installs the requested package.

    .PARAMETER Name
        The name of the package to install.

    .PARAMETER Provider
        Optional. Force a specific provider (e.g., 'apt', 'choco').
        If not specified, auto-detects the best available provider.

    .PARAMETER Version
        Optional. Specific version to install.

    .PARAMETER Force
        Re-install even if already present.

    .PARAMETER WingetId
        Optional. Specific package ID for Winget (e.g. 'Git.Git'). Overrides Name.

    .PARAMETER ChocoId
        Optional. Specific package ID for Chocolatey. Overrides Name.

    .PARAMETER BrewName
        Optional. Specific package name for Homebrew. Overrides Name.

    .PARAMETER AptName
        Optional. Specific package name for APT. Overrides Name.

    .PARAMETER YumName
        Optional. Specific package name for YUM/DNF. Overrides Name.

    .EXAMPLE
        Install-AitherPackage -Name "git" -WingetId "Git.Git"
        # Installs "Git.Git" on Winget, but "git" on other providers.

    .EXAMPLE
        Install-AitherPackage -Name "nodejs" -Provider "choco" -Version "18.0.0"
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name,

        [Parameter(Mandatory = $false)]
        [ValidateSet('apt', 'yum', 'dnf', 'apk', 'brew', 'choco', 'winget', 'scoop')]
        [string]$Provider,

        [Parameter(Mandatory = $false)]
        [string]$Version,

        [Parameter(Mandatory = $false)]
        [switch]$Force,

        [Parameter(Mandatory = $false)]
        [string]$WingetId,

        [Parameter(Mandatory = $false)]
        [string]$ChocoId,

        [Parameter(Mandatory = $false)]
        [string]$BrewName,

        [Parameter(Mandatory = $false)]
        [string]$AptName,

        [Parameter(Mandatory = $false)]
        [string]$YumName
    )

    process {
        try {
            # 1. Detect Provider if not specified
            if ([string]::IsNullOrWhiteSpace($Provider)) {
                if ($IsLinux) {
                    if (Get-Command apt-get -ErrorAction SilentlyContinue) { $Provider = 'apt' }
                    elseif (Get-Command dnf -ErrorAction SilentlyContinue) { $Provider = 'dnf' }
                    elseif (Get-Command yum -ErrorAction SilentlyContinue) { $Provider = 'yum' }
                    elseif (Get-Command apk -ErrorAction SilentlyContinue) { $Provider = 'apk' }
                }
                elseif ($IsMacOS) {
                    if (Get-Command brew -ErrorAction SilentlyContinue) { $Provider = 'brew' }
                }
                elseif ($IsWindows) {
                    # Prioritize Winget (modern), then Chocolatey
                    if (Get-Command winget -ErrorAction SilentlyContinue) { $Provider = 'winget' }
                    elseif (Get-Command choco -ErrorAction SilentlyContinue) { $Provider = 'choco' }
                }
            }

            if ([string]::IsNullOrWhiteSpace($Provider)) {
                Write-AitherLog -Level Warning -Message "No supported package manager found on this system. Skipping installation of '$Name'." -Source 'Install-AitherPackage'
                return
            }

            Write-Verbose "Using package provider: $Provider"

            # 2. Resolve Package Name
            $TargetName = $Name
            switch ($Provider) {
                'winget' { if (-not [string]::IsNullOrWhiteSpace($WingetId)) { $TargetName = $WingetId } }
                'choco'  { if (-not [string]::IsNullOrWhiteSpace($ChocoId)) { $TargetName = $ChocoId } }
                'brew'   { if (-not [string]::IsNullOrWhiteSpace($BrewName)) { $TargetName = $BrewName } }
                'apt'    { if (-not [string]::IsNullOrWhiteSpace($AptName)) { $TargetName = $AptName } }
                'yum'    { if (-not [string]::IsNullOrWhiteSpace($YumName)) { $TargetName = $YumName } }
                'dnf'    { if (-not [string]::IsNullOrWhiteSpace($YumName)) { $TargetName = $YumName } }
            }

            # 3. Construct Command
            $cmd = ""
            $args = @()

            switch ($Provider) {
                'apt' {
                    $cmd = "sudo"
                    $args = @("apt-get", "install", "-y", $TargetName)
                    if ($Version) { $args[$args.Count-1] = "$TargetName=$Version" }
                }
                'yum' { 
                    $cmd = "sudo"
                    $args = @("yum", "install", "-y", $TargetName)
                    if ($Version) { $args[$args.Count-1] = "$TargetName-$Version" }
                }
                'dnf' {
                    $cmd = "sudo"
                    $args = @("dnf", "install", "-y", $TargetName)
                }
                'apk' {
                    $cmd = "sudo"
                    $args = @("apk", "add", "--no-cache", $TargetName)
                }
                'brew' {
                    $cmd = "brew"
                    $args = @("install", $TargetName)
                }
                'choco' {
                    $cmd = "choco"
                    $args = @("install", $TargetName, "-y")
                    if ($Version) { $args += @("--version", $Version) }
                    if ($Force) { $args += "--force" }
                }
                'winget' {
                    $cmd = "winget"
                    # --id is crucial for automation to avoid ambiguity
                    $args = @("install", "-e", "--id", $TargetName, "--accept-source-agreements", "--accept-package-agreements")
                    if ($Version) { $args += @("-v", $Version) }
                }
            }

            # 4. Execute
            Write-AitherLog -Level Information -Message "Installing '$TargetName' via $Provider..." -Source 'Install-AitherPackage'
            
            if ($cmd -eq "sudo") {
                & $cmd $args
            } else {
                & $cmd $args
            }

            if ($LASTEXITCODE -eq 0) {
                Write-AitherLog -Level Information -Message "Successfully installed $TargetName." -Source 'Install-AitherPackage'
            } else {
                Write-AitherLog -Level Error -Message "Package installation failed with exit code $LASTEXITCODE" -Source 'Install-AitherPackage'
                # Don't throw by default to allow script continuation?
                # No, usually installation failure is critical.
                throw "Failed to install $TargetName"
            }
        }
        catch {
            Write-AitherLog -Level Error -Message "Failed to install package '$Name': $_" -Source 'Install-AitherPackage' -Exception $_
            throw $_
        }
    }
}