cciget.psm1

# cciget.psm1
# Loads functions from .\src, exports public ones (those not starting with '_').
# Mirrors the loader convention used by Cci.Vmware / Cci.Common.

Set-StrictMode -Version Latest

# PS 5.1 default protocol is SSL3/TLS1.0. PSGallery + AzDO require TLS 1.2+.
try {
    [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
} catch {
    Write-Verbose "[cciget] Could not raise SecurityProtocol to TLS 1.2: $_"
}

$moduleName = $ExecutionContext.SessionState.Module.Name
$srcPath    = Join-Path -Path $PSScriptRoot -ChildPath 'src'

# Module state. MUST be initialised here: the loader runs under
# Set-StrictMode -Version Latest, where reading an unassigned script-scope
# variable throws VariableIsUndefined (seen on a real machine build as a
# RuntimeException inside _Connect-CciBlobStore).
$Script:CciGetSource      = $null   # 'feed' | 'store' | $null, set by Connect-CciGet
$Script:CciGetBlobContext = $null   # distribution-store context (Account/Token/TenantId)
$Script:CciGetModuleCache = $null   # available modules, for tab completion

Write-Verbose "[$moduleName] Import starting. PSScriptRoot=$PSScriptRoot src=$srcPath"

if (-not (Test-Path -LiteralPath $srcPath)) {
    Write-Warning "[$moduleName] Source folder not found: $srcPath."
    return
}

$allFiles     = Get-ChildItem -LiteralPath $srcPath -Filter *.ps1 -Recurse | Sort-Object FullName
$privateFiles = $allFiles | Where-Object { $_.BaseName -match '^_' }
$publicFiles  = $allFiles | Where-Object { $_.BaseName -notmatch '^_' }

foreach ($file in @($privateFiles + $publicFiles)) {
    Write-Verbose "[$moduleName] Loading $($file.FullName)"
    . $file.FullName
}

$publicNames = $publicFiles.BaseName | Sort-Object -Unique
if ($publicNames) {
    Export-ModuleMember -Function $publicNames
    Write-Verbose "[$moduleName] Exported: $($publicNames -join ', ')"
}

# Tab completion for module names. Registered here rather than in src/ because
# the source-file convention is one function per file; the scriptblock closes
# over module session state, so it can reach the private helper.
$moduleNameCompleter = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    $word = "$wordToComplete".Trim("'`"")
    foreach ($m in (_Get-CciModuleCompletionSource)) {
        foreach ($candidate in @($m.Name, $m.Full) | Sort-Object -Unique) {
            if ($candidate -like "$word*") {
                [System.Management.Automation.CompletionResult]::new(
                    $candidate, $candidate, 'ParameterValue', "$($m.Full) $($m.Version)")
                break
            }
        }
    }
}
Register-ArgumentCompleter -CommandName Install-CciModule, Save-CciModule, Update-CciModule, Find-CciModule, Get-CciModule `
    -ParameterName Name -ScriptBlock $moduleNameCompleter

$tenantCompleter = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    $word = "$wordToComplete".Trim("'`"")
    try {
        foreach ($f in (Get-CciGetConfig).feeds) {
            if ($f.name -like "$word*") {
                [System.Management.Automation.CompletionResult]::new(
                    $f.name, $f.name, 'ParameterValue', $f.description)
            }
        }
    } catch { }
}
Register-ArgumentCompleter -CommandName Install-CciModule, Save-CciModule, Update-CciModule, Find-CciModule, Connect-CciGet, Publish-CciModuleToBlob `
    -ParameterName Tenant -ScriptBlock $tenantCompleter