satellite.psm1

# Satellite module for Delta-Code
# Manages satellite discovery, registration, validation, and command execution

# Resolve module dependencies from the sibling directory when available (repository
# and flat-install layouts) and fall back to module-name resolution (PSGallery).
foreach ($dependencyName in @('delta-code')) {
    $dependencyManifest = Join-Path $PSScriptRoot "$dependencyName.psd1"
    if (Test-Path -LiteralPath $dependencyManifest) {
        Import-Module $dependencyManifest -ErrorAction Stop -DisableNameChecking
    }
    else {
        Import-Module $dependencyName -ErrorAction Stop -DisableNameChecking
    }
}
Remove-Variable dependencyName, dependencyManifest -ErrorAction SilentlyContinue

# Satellite registry - stores discovered/registered satellites
$script:SatelliteRegistry = @{}
$script:SatellitePaths = @()

function Get-DeltaCodeSatellite {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name
    )
    if ($script:SatelliteRegistry.ContainsKey($Name)) {
        return $script:SatelliteRegistry[$Name]
    }
    Write-Error "Satellite '$Name' not found in registry"
    return $null
}

function Get-DeltaCodeSatellites {
    [CmdletBinding()]
    param(
        [string[]]$Filter
    )
    $sats = $script:SatelliteRegistry.Values
    if ($Filter) {
        $sats = $sats | Where-Object { $Filter -contains $_.Category }
    }
    return $sats
}

function Register-DeltaCodeSatellite {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$Path,
        [Parameter(Mandatory = $false)]
        [string]$Category = 'General',
        [Parameter(Mandatory = $false)]
        [string]$Description = '',
        [Parameter(Mandatory = $false)]
        [hashtable]$Metadata = @{}
    )
    $normalizedPath = (Resolve-Path -LiteralPath $Path).ProviderPath
    if (-not (Test-Path $normalizedPath)) {
        Write-Error "Satellite path does not exist: $normalizedPath"
        return $false
    }

    $satellite = [PSCustomObject]@{
        Name        = $Name
        Path        = $normalizedPath
        Category    = $Category
        Description = $Description
        Metadata    = $Metadata
        Registered  = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
        Module      = $null
    }

    $script:SatelliteRegistry[$Name] = $satellite
    if ($script:SatellitePaths -notcontains $normalizedPath) {
        $script:SatellitePaths += $normalizedPath
    }
    Write-Verbose "Registered satellite '$Name' at $normalizedPath"
    return $true
}

function Test-DeltaCodeSatellite {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name
    )
    $sat = Get-DeltaCodeSatellite -Name $Name
    if (-not $sat) { return $false }

    $modulePath = Join-Path $sat.Path "$Name.psm1"
    $manifestPath = Join-Path $sat.Path "$Name.psd1"

    $valid = $true
    $issues = @()

    if (-not (Test-Path $modulePath)) {
        $issues += "Missing module file: $modulePath"
        $valid = $false
    }
    if (-not (Test-Path $manifestPath)) {
        $issues += "Missing manifest file: $manifestPath"
        $valid = $false
    }
    if ($valid) {
        try {
            Import-Module $modulePath -PassThru | Out-Null
            $sat.Module = $modulePath
            $script:SatelliteRegistry[$Name] = $sat
        }
        catch {
            $issues += "Module import failed: $($_.Exception.Message)"
            $valid = $false
        }
    }

    if (-not $valid) {
        Write-Warning "Satellite '$Name' validation failed: $($issues -join '; ')"
    }
    else {
        Write-Verbose "Satellite '$Name' validated successfully"
    }
    return $valid
}

function Invoke-DeltaCodeSatellite {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$Command,
        [Parameter(ValueFromRemainingArguments = $true)]
        [string[]]$Args
    )
    $sat = Get-DeltaCodeSatellite -Name $Name
    if (-not $sat) {
        Write-Error "Satellite '$Name' not found"
        return $null
    }

    if (-not $sat.Module) {
        Test-DeltaCodeSatellite -Name $Name
        if (-not $sat.Module) {
            Write-Error "Satellite '$Name' is not loaded/valid"
            return $null
        }
    }

    $funcName = "Invoke-$Name$Command"
    if (-not (Get-Command $funcName -ErrorAction SilentlyContinue)) {
        Write-Error "Satellite '$Name' does not implement command '$Command' (expected function $funcName)"
        return $null
    }

    try {
        & $funcName @Args
    }
    catch {
        Write-Error "Satellite '$Name' command '$Command' failed: $($_.Exception.Message)"
        return $null
    }
}

function Initialize-DeltaCodeSatellites {
    [CmdletBinding()]
    param(
        [string[]]$SearchPaths
    )
    if (-not $SearchPaths) {
        $SearchPaths = @(
            "$PSScriptRoot\satellites",
            "$PSScriptRoot\..\satellites",
            (Join-Path $env:USERPROFILE ".delta-code\satellites")
        )
    }

    foreach ($basePath in $SearchPaths) {
        if (Test-Path $basePath) {
            $dirs = Get-ChildItem -Path $basePath -Directory
            foreach ($dir in $dirs) {
                $satName = $dir.Name
                $satPath = $dir.FullName
                $manifest = Join-Path $satPath "$satName.psd1"
                if (Test-Path $manifest) {
                    Register-DeltaCodeSatellite -Name $satName -Path $satPath
                }
            }
        }
    }

    # Auto-validate all registered
    $names = @($script:SatelliteRegistry.Keys)
    foreach ($name in $names) {
        Test-DeltaCodeSatellite -Name $name
    }
}

function Unregister-DeltaCodeSatellite {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name
    )
    if ($script:SatelliteRegistry.ContainsKey($Name)) {
        $script:SatelliteRegistry.Remove($Name)
        Write-Verbose "Unregistered satellite '$Name'"
        return $true
    }
    return $false
}

function Reset-DeltaCodeSatelliteRegistry {
    [CmdletBinding()]
    param()
    $script:SatelliteRegistry = @{}
    $script:SatellitePaths = @()
    Write-Verbose "Satellite registry reset"
}

Export-ModuleMember -Function @(
    'Get-DeltaCodeSatellite'
    'Get-DeltaCodeSatellites'
    'Register-DeltaCodeSatellite'
    'Test-DeltaCodeSatellite'
    'Invoke-DeltaCodeSatellite'
    'Initialize-DeltaCodeSatellites'
    'Unregister-DeltaCodeSatellite'
    'Reset-DeltaCodeSatelliteRegistry'
)