name: Release

# Runs only after the CI workflow completes, so a release is never published on a commit
# whose formatting, lint, build, or tests failed.
on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]
    branches: [master]
  workflow_dispatch:

permissions:
  contents: write

jobs:
  release:
    name: Create Release
    # Proceed only for a successful CI run on a master push, or a manual dispatch.
    if: >-
      github.event_name == 'workflow_dispatch' ||
      (github.event.workflow_run.conclusion == 'success' &&
       github.event.workflow_run.event == 'push' &&
       github.event.workflow_run.head_branch == 'master')
    runs-on: ubuntu-latest
    outputs:
      should_release: ${{ steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false' }}
      release_exists: ${{ steps.check_release.outputs.exists }}
      version: ${{ steps.version.outputs.version }}
      tag: ${{ steps.version.outputs.tag }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          # The exact commit CI tested (workflow_run), or the current tip (manual dispatch).
          ref: ${{ github.event.workflow_run.head_sha || github.sha }}

      - name: Check for src/ changes
        id: changes
        run: |
          if git rev-parse HEAD~1 >/dev/null 2>&1; then
            CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'src/' | wc -l)
          else
            CHANGED=1
          fi
          [ "$CHANGED" -gt 0 ] && echo "src_changed=true" >> "$GITHUB_OUTPUT" || echo "src_changed=false" >> "$GITHUB_OUTPUT"

      - name: Read version
        id: version
        run: |
          VERSION=$(grep -oP '(?<=<Version>)[^<]+' src/Directory.Build.props)
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"

      - name: Check if release exists
        id: check_release
        run: |
          if gh release view "${{ steps.version.outputs.tag }}" &>/dev/null; then
            echo "exists=true" >> "$GITHUB_OUTPUT"
          else
            echo "exists=false" >> "$GITHUB_OUTPUT"
          fi
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup .NET 10
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "10.0.x"

      - name: Publish Server win-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Server/EchoHub.Server.csproj -c Release -r win-x64 --self-contained true -o publish/server-win-x64

      - name: Publish Server linux-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Server/EchoHub.Server.csproj -c Release -r linux-x64 --self-contained true -o publish/server-linux-x64

      - name: Publish Server osx-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Server/EchoHub.Server.csproj -c Release -r osx-x64 --self-contained true -o publish/server-osx-x64

      - name: Publish Server osx-arm64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Server/EchoHub.Server.csproj -c Release -r osx-arm64 --self-contained true -o publish/server-osx-arm64

      - name: Publish Server linux-arm64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Server/EchoHub.Server.csproj -c Release -r linux-arm64 --self-contained true -o publish/server-linux-arm64

      - name: Publish Client win-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-win-x64

      - name: Publish Client linux-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-linux-x64

      - name: Publish Client osx-x64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-osx-x64

      - name: Publish Client osx-arm64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-osx-arm64

      - name: Publish Client linux-arm64
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-linux-arm64

      - name: Zip artifacts
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: |
          cd publish
          zip -r ../EchoHub-Server-win-x64.zip server-win-x64/
          zip -r ../EchoHub-Server-linux-x64.zip server-linux-x64/
          zip -r ../EchoHub-Server-osx-x64.zip server-osx-x64/
          zip -r ../EchoHub-Server-osx-arm64.zip server-osx-arm64/
          zip -r ../EchoHub-Server-linux-arm64.zip server-linux-arm64/
          zip -r ../EchoHub-Client-win-x64.zip client-win-x64/
          zip -r ../EchoHub-Client-linux-x64.zip client-linux-x64/
          zip -r ../EchoHub-Client-osx-x64.zip client-osx-x64/
          zip -r ../EchoHub-Client-osx-arm64.zip client-osx-arm64/
          zip -r ../EchoHub-Client-linux-arm64.zip client-linux-arm64/

      - name: Build release notes
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: |
          TAG="${{ steps.version.outputs.tag }}"
          CHANGELOG_URL="https://huebyte.github.io/EchoHub/changelog/${TAG}.html"
          REPO="https://github.com/${{ github.repository }}"
          PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${TAG}$" | head -n 1)

          {
            echo "📋 **[Full Changelog](${CHANGELOG_URL})**"
            echo ""
            echo "---"
            echo ""
            echo "### Commits"
            echo ""
            if [ -n "$PREV_TAG" ]; then
              git log "${PREV_TAG}..HEAD" --pretty=format:"- %s (%h)" --no-merges
            else
              git log HEAD --pretty=format:"- %s (%h)" --no-merges
            fi
            echo ""
            echo ""
            if [ -n "$PREV_TAG" ]; then
              echo "*Version diff: [${PREV_TAG}...${TAG}](${REPO}/compare/${PREV_TAG}...${TAG})*"
            else
              echo "*Version diff: [${TAG}](${REPO}/commits/${TAG})*"
            fi
          } > release-notes.md

      - name: Create GitHub Release
        if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
        run: |
          gh release create "${{ steps.version.outputs.tag }}" \
            --title "EchoHub ${{ steps.version.outputs.tag }}" \
            --notes-file release-notes.md \
            EchoHub-Server-win-x64.zip \
            EchoHub-Server-linux-x64.zip \
            EchoHub-Server-osx-x64.zip \
            EchoHub-Server-osx-arm64.zip \
            EchoHub-Server-linux-arm64.zip \
            EchoHub-Client-win-x64.zip \
            EchoHub-Client-linux-x64.zip \
            EchoHub-Client-osx-x64.zip \
            EchoHub-Client-osx-arm64.zip \
            EchoHub-Client-linux-arm64.zip
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  choco:
    name: Publish to Chocolatey
    needs: release
    if: needs.release.outputs.release_exists == 'true' || needs.release.outputs.should_release == 'true'
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - name: Check if version already published
        id: choco_check
        shell: pwsh
        run: |
          $version = "${{ needs.release.outputs.version }}"
          $result = choco search echohub --version $version --exact --source https://community.chocolatey.org/api/v2/ 2>&1
          if ($result -match "echohub $version") {
            echo "exists=true" >> $env:GITHUB_OUTPUT
            Write-Host "Chocolatey package echohub $version already published — skipping."
          } else {
            echo "exists=false" >> $env:GITHUB_OUTPUT
          }

      - name: Download release asset
        if: steps.choco_check.outputs.exists == 'false'
        run: gh release download "v${{ needs.release.outputs.version }}" --pattern "EchoHub-Client-win-x64.zip"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Pack and push
        if: steps.choco_check.outputs.exists == 'false'
        shell: pwsh
        run: |
          $version = "${{ needs.release.outputs.version }}"
          $checksum = (Get-FileHash EchoHub-Client-win-x64.zip -Algorithm SHA256).Hash.ToLower()

          # Stamp version and checksum into package templates
          (Get-Content packaging/choco/echohub.nuspec) -replace '__VERSION__', $version | Set-Content packaging/choco/echohub.nuspec
          (Get-Content packaging/choco/tools/chocolateyInstall.ps1) -replace '__VERSION__', $version | Set-Content packaging/choco/tools/chocolateyInstall.ps1
          (Get-Content packaging/choco/tools/chocolateyInstall.ps1) -replace '__CHECKSUM64__', $checksum | Set-Content packaging/choco/tools/chocolateyInstall.ps1

          cd packaging/choco
          choco pack echohub.nuspec --output-directory $env:TEMP
          $pkg = Get-ChildItem "$env:TEMP\echohub.*.nupkg" | Select-Object -First 1
          choco push $pkg.FullName --source https://push.chocolatey.org/ --api-key $env:CHOCO_API_KEY
        env:
          CHOCO_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }}
