#!/bin/bash
scriptdir=$(cd $(dirname $0) && pwd)
set -eu # we don't want "pipefail" to implement idempotency

###
#
# Publishes all *.nupkg to NuGet
#
# Usage: ./publib-nuget [DIR]
#
# DIR is a directory with *.nupkg files (default is 'dist/dotnet')
#
# Two publishing modes are supported: Trusted Publisher (recommended) and API key (legacy).
# Set environment variables accordingly.
#
# Trusted Publisher (recommended):
# - NUGET_TRUSTED_PUBLISHER (required): set to any value
# - NUGET_USERNAME (required): the NuGet.org username of the package owner
# - NUGET_AUDIENCE (optional): OIDC audience for token generation (defaults to https://www.nuget.org)
# - NUGET_TOKEN_SERVICE_URL (optional): NuGet token service endpoint (defaults to https://www.nuget.org/api/v2/token)#
#
# API Key:
# - NUGET_API_KEY (required): API key for your account, created on nuget.org or use https://github.com/NuGet/login
#
# Generic options:
# - NUGET_SERVER (optional): different NuGet server URL to use
###

cd "${1:-"dist/dotnet"}"

# Evaluate trusted publisher flag once as boolean
use_trusted_publisher=false
if [ -n "${NUGET_TRUSTED_PUBLISHER:-}" ] && [ "${NUGET_TRUSTED_PUBLISHER}" != "false" ]; then
  use_trusted_publisher=true
fi

# Check for Trusted Publisher authentication
if [ "$use_trusted_publisher" = "true" ]; then
    echo "Using NuGet Trusted Publisher authentication"
    
    if [ -z "${NUGET_USERNAME:-}" ]; then
        echo "NUGET_USERNAME is required when using Trusted Publishers"
        exit 1
    fi
    
    # Install required packages
    python3 -m pip install --user --upgrade id
    
    # Generate OIDC token using the id package
    nuget_audience="${NUGET_AUDIENCE:-https://www.nuget.org}"
    oidc_token=$(python3 -m id "$nuget_audience")
    
    # Exchange OIDC token for NuGet API key
    nuget_token_service_url="${NUGET_TOKEN_SERVICE_URL:-https://www.nuget.org/api/v2/token}"
    token_request_body=$(jq -n --arg username "$NUGET_USERNAME" '{username: $username, tokenType: "ApiKey"}')
    
    NUGET_API_KEY=$(curl -s -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer ${oidc_token}" \
        -H "User-Agent: publib/nuget-publisher" \
        -d "$token_request_body" \
        "$nuget_token_service_url" | jq -r '.apiKey')
    
    if [ "$NUGET_API_KEY" = "null" ] || [ -z "$NUGET_API_KEY" ]; then
        echo "Failed to exchange OIDC token for NuGet API key"
        exit 1
    fi
elif [ -z "${NUGET_API_KEY:-}" ] && [ "$use_trusted_publisher" = "false" ]; then
    echo "NUGET_API_KEY is required or set NUGET_TRUSTED_PUBLISHER=1 with NUGET_USERNAME"
    exit 1
fi

packages=$(find . -name '*.nupkg' -not -iname '*.symbols.nupkg')
if [ -z "${packages}" ]; then
    echo "❌ No *.nupkg files found under $PWD. Nothing to publish"
    exit 1
fi

echo "Publishing NuGet packages..."

# Check for dry run
if [ "${PUBLIB_DRYRUN:-}" = "true" ]; then
  echo "🏜️ Dry run: skipping NuGet publish"
  for package_dir in ${packages}; do
    echo "  (would publish ${package_dir})"
  done
  echo "✅ All Done! (dry run)"
  exit 0
fi

nuget_source="${NUGET_SERVER:-"https://api.nuget.org/v3/index.json"}"
nuget_symbol_source="https://nuget.smbsrc.net/"

log=$(mktemp -d)/log.txt

for package_dir in ${packages}; do
    echo "📦  Publishing ${package_dir} to NuGet"
    (
        cd $(dirname $package_dir)
        nuget_package_name=$(basename $package_dir)
        nuget_package_base=${nuget_package_name%.nupkg}

        [ -f "${nuget_package_base}.snupkg" ] || echo "⚠️ No symbols package was found!"

        # The .snupkg will be published at the same time as the .nupkg if both are in the current folder (which is the case)
        dotnet nuget push $nuget_package_name -k ${NUGET_API_KEY} -s ${nuget_source} | tee ${log}
        exit_code="${PIPESTATUS[0]}"

        # If push failed, check if this was caused because we are trying to publish
        # the same version again, which is not an error by searching for a magic string in the log
        # ugly, yes!
        if cat ${log} | grep -q -e "already exists and cannot be modified" -e "409 (Conflict)"; then
            echo "⚠️ Artifact already published. Skipping"
        elif [ "${exit_code}" -ne 0 ]; then
            echo "❌ Release failed"
            exit 1
        fi
    )
done

echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "✅ All Done!"
