GoogleFonts.psm1

[CmdletBinding()]
param()
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$script:PSModuleInfo = Test-ModuleManifest -Path "$PSScriptRoot\$baseName.psd1"
$script:PSModuleInfo | Format-List | Out-String -Stream | ForEach-Object { Write-Debug $_ }
$scriptName = $script:PSModuleInfo.Name
Write-Debug "[$scriptName] - Importing module"
#region [classes] - [private]
Write-Debug "[$scriptName] - [classes] - [private] - Processing folder"
#region [classes] - [private] - [Scope]
Write-Debug "[$scriptName] - [classes] - [private] - [Scope] - Importing"
enum Scope {
    CurrentUser
    AllUsers
}
Write-Debug "[$scriptName] - [classes] - [private] - [Scope] - Done"
#endregion [classes] - [private] - [Scope]
Write-Debug "[$scriptName] - [classes] - [private] - Done"
#endregion [classes] - [private]
#region [functions] - [public]
Write-Debug "[$scriptName] - [functions] - [public] - Processing folder"
#region [functions] - [public] - [completers]
Write-Debug "[$scriptName] - [functions] - [public] - [completers] - Importing"
Register-ArgumentCompleter -CommandName Get-GoogleFont, Install-GoogleFont -ParameterName Name -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
    $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter
    Get-GoogleFont -Verbose:$false | Select-Object -ExpandProperty Name | Sort-Object -Unique | Where-Object { $_ -like "$wordToComplete*" } |
        ForEach-Object { [System.Management.Automation.CompletionResult]::new("'$_'", $_, 'ParameterValue', $_) }
}
Write-Debug "[$scriptName] - [functions] - [public] - [completers] - Done"
#endregion [functions] - [public] - [completers]
#region [functions] - [public] - [Get-GoogleFont]
Write-Debug "[$scriptName] - [functions] - [public] - [Get-GoogleFont] - Importing"
function Get-GoogleFont {
    <#
        .SYNOPSIS
        Get GoogleFonts asset list

        .DESCRIPTION
        Get GoogleFonts asset list, filtered by name, from the latest release.

        .EXAMPLE
        Get-GoogleFonts

        Get all the GoogleFonts.

        .EXAMPLE
        Get-GoogleFonts -Name 'Roboto'

        Get the GoogleFont asset with the name 'Roboto'.

        .EXAMPLE
        Get-GoogleFonts -Name 'Noto*'

        Get the GoogleFont asset with the name starting with 'Noto'.
    #>

    [Alias('Get-GoogleFonts')]
    [CmdletBinding()]
    param (
        # Name of the GoogleFont to get
        [Parameter()]
        [SupportsWildcards()]
        [string] $Name = '*'
    )

    Write-Verbose 'Selecting assets by:'
    Write-Verbose "Name: [$Name]"
    $script:GoogleFonts | Where-Object { $_.Name -like $Name }
}
Write-Debug "[$scriptName] - [functions] - [public] - [Get-GoogleFont] - Done"
#endregion [functions] - [public] - [Get-GoogleFont]
#region [functions] - [public] - [Install-GoogleFont]
Write-Debug "[$scriptName] - [functions] - [public] - [Install-GoogleFont] - Importing"
#Requires -Modules @{ ModuleName = 'Admin'; RequiredVersion = '1.1.1' }
#Requires -Modules @{ ModuleName = 'Fonts'; RequiredVersion = '1.1.11' }

function Install-GoogleFont {
    <#
        .SYNOPSIS
        Installs Google Fonts to the system.

        .DESCRIPTION
        Installs Google Fonts to the system.

        .EXAMPLE
        Install-GoogleFont -Name 'Roboto'

        Installs the font 'Roboto' to the current user.

        .EXAMPLE
        Install-GoogleFont -Name 'Roboto' -Scope AllUsers

        Installs the font 'Roboto' to all users. This requires to be run as administrator.

        .EXAMPLE
        Install-GoogleFont -All

        Installs all Google Fonts to the current user.
    #>

    [CmdletBinding(
        DefaultParameterSetName = 'Name',
        SupportsShouldProcess
    )]
    [Alias('Install-GoogleFonts')]
    param(
        # Specify the name of the Google Font(s) to install.
        [Parameter(
            ParameterSetName = 'Name',
            Mandatory
        )]
        [string[]] $Name,

        # Specify to install all Google Font(s).
        [Parameter(ParameterSetName = 'All', Mandatory)]
        [switch] $All,

        # Specify the scope of where to install the font(s).
        [Parameter()]
        [Scope] $Scope = 'CurrentUser'
    )

    begin {
        if ($Scope -eq 'AllUsers' -and -not (IsAdmin)) {
            $errorMessage = @'
Administrator rights are required to install fonts.
Please run the command again with elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command."
'@

            throw $errorMessage
        }
        $GoogleFontsToInstall = @()

        $guid = (New-Guid).Guid
        $tempPath = Join-Path -Path $HOME -ChildPath "GoogleFonts-$guid"
        if (-not (Test-Path -Path $tempPath -PathType Container)) {
            Write-Verbose "Create folder [$tempPath]"
            $null = New-Item -Path $tempPath -ItemType Directory
        }
    }

    process {
        if ($All) {
            $GoogleFontsToInstall = $script:GoogleFonts
        } else {
            foreach ($fontName in $Name) {
                Write-Verbose "[$fontName] - Searching for font"
                $filteredFonts = $script:GoogleFonts | Where-Object { $_.Name -like $fontName }
                Write-Verbose "[$fontName] - Found [$($filteredFonts.count)] fonts"
                $GoogleFontsToInstall += $filteredFonts
            }
        }

        Write-Verbose "[$Scope] - Installing [$($GoogleFontsToInstall.count)] fonts"

        foreach ($GoogleFont in $GoogleFontsToInstall) {
            $URL = $GoogleFont.URL
            $fontName = $GoogleFont.Name
            $fontVariant = $GoogleFont.Variant
            $fileName = "$fontName-$fontVariant.ttf"
            $downloadPath = Join-Path -Path $tempPath -ChildPath "$fileName"

            Write-Verbose "[$fontName] - Downloading to [$downloadPath]"
            if ($PSCmdlet.ShouldProcess($fontName, "Download $fontName")) {
                Invoke-WebRequest -Uri $URL -OutFile $downloadPath -Verbose:$false -RetryIntervalSec 5 -MaximumRetryCount 5
            }

            Write-Verbose "[$fontName] - Install to [$Scope]"
            if ($PSCmdlet.ShouldProcess($fontName, 'Install font')) {
                Install-Font -Path $downloadPath -Scope $Scope
                Remove-Item -Path $downloadPath -Force -Recurse
            }
        }
    }

    end {
        Write-Verbose "Remove folder [$tempPath]"
    }

    clean {
        Remove-Item -Path $tempPath -Force
    }
}
Write-Debug "[$scriptName] - [functions] - [public] - [Install-GoogleFont] - Done"
#endregion [functions] - [public] - [Install-GoogleFont]
Write-Debug "[$scriptName] - [functions] - [public] - Done"
#endregion [functions] - [public]
#region [variables] - [private]
Write-Debug "[$scriptName] - [variables] - [private] - Processing folder"
#region [variables] - [private] - [GoogleFonts]
Write-Debug "[$scriptName] - [variables] - [private] - [GoogleFonts] - Importing"
$script:GoogleFonts = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/PSModule/GoogleFonts/refs/heads/main/data/GoogleFonts.json'
Write-Debug "[$scriptName] - [variables] - [private] - [GoogleFonts] - Done"
#endregion [variables] - [private] - [GoogleFonts]
Write-Debug "[$scriptName] - [variables] - [private] - Done"
#endregion [variables] - [private]

#region Member exporter
$exports = @{
    Alias    = '*'
    Cmdlet   = ''
    Function = @(
        'Get-GoogleFont'
        'Install-GoogleFont'
    )
}
Export-ModuleMember @exports
#endregion Member exporter