ProductivityTools.PublishModuleTo.psm1

function UpdateModuleVersion {
    [Cmdletbinding()]
    param(
        [string]$psd1Path
    )
    
    $psd1 = Get-Content $psd1Path
    # Cleaned up regex to be more resilient with spacing
    [version]$Version = [regex]::matches($psd1, "\s*ModuleVersion\s*=\s*'(\d+\.\d+\.\d+)'\s*").groups[1].value
    Write-Verbose "Old Version - $Version"
    [version]$NewVersion = "{0}.{1}.{2}" -f $Version.Major, $Version.Minor, ($Version.Build + 1)
    Write-Verbose "New Version - $NewVersion"
    $psd1 -replace [regex]::Escape($Version.ToString()), $NewVersion.ToString() | Out-File $psd1Path -Encoding utf8 -Force
}

function GetTypeOfModule {
     [Cmdletbinding()]
    param(
        [string]$psd1FullName
    )
    $psd1 = Get-Content $psd1FullName -Raw
    $rootModule = [regex]::matches($psd1, "\s*RootModule\s*=\s*'(.*)'\s*")
    $rootModuleName = $rootModule.groups[1].value
    
    if ($rootModuleName.EndsWith('.dll', [System.StringComparison]::OrdinalIgnoreCase)) {
        return "binary"
    }
    
    if ($rootModuleName.EndsWith('.psm1', [System.StringComparison]::OrdinalIgnoreCase)) {
        return "text"
    }
    
    throw "In the Root module no dll nor psm1 type is defined"  
}

function Buildapplication {
    [Cmdletbinding()]
    param()
    dotnet pack
}

function Publish-ModuleTo {
    [Cmdletbinding()]
    param(
        [string]$PSRepositoryName = "PSGallery",
        [string]$NuGetApiKey,
        [switch]$IncreaseModuleVersion 
    )   

    # Find the manifests, filter out anything in artifacts or bin directories early
    $psd1s = @(Get-ChildItem -Recurse "*.psd1" | Where-Object { $_.FullName -notlike "*\bin\*" -and $_.FullName -notlike "*\obj\*" }) 

    Write-Verbose "Found $($psd1s.Length) module manifests"

    foreach ($psd1 in $psd1s) {
        $psd1FullName = $psd1.FullName
        Write-Verbose "File analyzed $($psd1FullName)"

        $moduleType = GetTypeOfModule $psd1FullName
        
        if ($IncreaseModuleVersion.IsPresent) {
            Write-Verbose "Update Module Version"
            UpdateModuleVersion $psd1FullName
        }
        
        # Determine the target directory path containing the layout to publish
        if ($moduleType -eq "binary") {
            Write-Verbose "Binary module, so building the app"
            Buildapplication
            
            $psd1sForBin = @(Get-ChildItem -Recurse "*.psd1") 
            $binPsd1 = $psd1sForBin | Where-Object { $_.DirectoryName -like "*bin*" -and $_.Name -eq $psd1.Name } | Select-Object -First 1
            
            # The publishing cmdlets require the path to the DIRECTORY containing the manifest, not the file itself
            $publishPath = $binPsd1.DirectoryName
            Write-Verbose "Binary module directory to be published: $($publishPath)"
        }
        else { # text module
            $publishPath = $psd1.DirectoryName
            Write-Verbose "psm1 module directory to be published: $($publishPath)"
        }

        Write-Verbose "Publishing from Path: $publishPath"
        Write-Verbose "PSRepository: $PSRepositoryName"
        
        # Check if the modern PSResourceGet module is available (much safer on .NET 10 environment)
        if (Get-Module -ListAvailable Microsoft.PowerShell.PSResourceGet) {
            Write-Verbose "Using modern Publish-PSResource engine"
            Publish-PSResource -Path $publishPath -APIKey $NuGetApiKey -Repository $PSRepositoryName -Verbose:$VerbosePreference
        }
        else {
            Write-Verbose "Using legacy Publish-Module engine (Warning: Needs exact directory mappings)"
            # Note the change from -Name to -Path here!
            Publish-Module -Path $publishPath -NuGetApiKey $NuGetApiKey -Repository $PSRepositoryName -Verbose:$VerbosePreference
        }
    }
}

Export-ModuleMember Publish-ModuleTo