name: Release

permissions:
  contents: write

on:
  workflow_run:
    workflows: ["CI"]
    types:
      - completed
    branches: [main]

jobs:
  check_release:
    runs-on: ubuntu-latest
    if: github.event.workflow_run.conclusion == 'success'
    outputs:
      releaseExists: ${{ steps.check_release.outputs.releaseExists }}
      version: ${{ steps.check_release.outputs.version }}
    steps:
      - uses: actions/checkout@v7
        with:
          # Build exactly the commit CI validated, not whatever main moved to.
          ref: ${{ github.event.workflow_run.head_sha }}

      - name: Check if release exists
        id: check_release
        uses: actions/github-script@v9
        with:
          script: |
            const { owner, repo } = context.repo;
            const fs = require("fs");
            const content = fs.readFileSync("Cargo.toml", "utf8");
            const match = content.match(/^version = "(.*?)"/m);
            const version = match ? match[1] : "";
            const tag = `v${version}`;

            console.log("Extracted version:", tag);
            core.setOutput("version", version);

            let releaseExists = false;
            try {
              await github.rest.repos.getReleaseByTag({ owner, repo, tag });
              releaseExists = true;
            } catch (error) {
              if (error.status !== 404) throw error;
            }

            console.log("Release exists:", releaseExists);
            core.setOutput("releaseExists", releaseExists);

  extract_changelog:
    needs: check_release
    if: needs.check_release.outputs.releaseExists == 'false'
    runs-on: ubuntu-latest
    outputs:
      changelog: ${{ steps.changelog.outputs.changelog }}
    steps:
      - uses: actions/checkout@v7
        with:
          # Build exactly the commit CI validated, not whatever main moved to.
          ref: ${{ github.event.workflow_run.head_sha }}

      - name: Extract changelog for version
        id: changelog
        run: |
          VERSION="${{ needs.check_release.outputs.version }}"
          # Extract content between [X.Y.Z] header and next ## header
          CHANGELOG=$(awk "/^## \\[${VERSION}\\]/{found=1; next} /^## \\[/{if(found) exit} found{print}" CHANGELOG.md)
          # If no versioned section found, try [Unreleased]
          if [ -z "$CHANGELOG" ]; then
            CHANGELOG=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
          fi
          echo "changelog<<CHANGELOG_EOF" >> "$GITHUB_OUTPUT"
          echo "$CHANGELOG" >> "$GITHUB_OUTPUT"
          echo "CHANGELOG_EOF" >> "$GITHUB_OUTPUT"

  release:
    needs: [check_release, extract_changelog]
    if: needs.check_release.outputs.releaseExists == 'false'
    strategy:
      matrix:
        target:
          - x86_64-unknown-linux-gnu
          - i686-unknown-linux-gnu
          - aarch64-unknown-linux-gnu
          - armv7-unknown-linux-gnueabihf
          - arm-unknown-linux-gnueabihf
          - powerpc64le-unknown-linux-gnu
          - s390x-unknown-linux-gnu
          - aarch64-apple-darwin
          - x86_64-apple-darwin
          - x86_64-pc-windows-gnu
    runs-on: ${{ (matrix.target == 'aarch64-apple-darwin' || matrix.target == 'x86_64-apple-darwin') && 'macos-latest' || 'ubuntu-latest' }}
    steps:
      - uses: actions/checkout@v7
        with:
          # Build exactly the commit CI validated, not whatever main moved to.
          ref: ${{ github.event.workflow_run.head_sha }}

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@v2
        with:
          key: release-${{ matrix.target }}

      - name: Install cross
        run: cargo install cross --git https://github.com/cross-rs/cross
        if: runner.os == 'Linux'

      - name: Install mingw-w64
        run: sudo apt install -y mingw-w64
        if: matrix.target == 'x86_64-pc-windows-gnu'

      - name: Build (cross)
        run: cross build --release --target ${{ matrix.target }}
        if: runner.os == 'Linux'

      - name: Build (native)
        run: cargo build --release --target ${{ matrix.target }}
        if: runner.os != 'Linux'

      - name: Package
        shell: bash
        run: |
          short_target=$(echo "${{ matrix.target }}" | sed 's/-unknown//')
          staging="killport-${short_target}"
          mkdir -p "$staging/completions" "$staging/man"

          # Binary
          if [[ "${{ matrix.target }}" == *"windows"* ]]; then
            cp "target/${{ matrix.target }}/release/killport.exe" "$staging/"
          else
            cp "target/${{ matrix.target }}/release/killport" "$staging/"
          fi

          # Shell completions and man page from build.rs output
          out_dir=$(find "target/${{ matrix.target }}/release/build/killport-"*/out -maxdepth 0 -type d 2>/dev/null | head -1)
          if [ -n "$out_dir" ]; then
            cp "$out_dir"/completions/* "$staging/completions/" 2>/dev/null || true
            cp "$out_dir"/man/* "$staging/man/" 2>/dev/null || true
          fi

          tar czvf "${staging}.tar.gz" "$staging"

      - name: Upload release assets
        uses: softprops/action-gh-release@v3
        with:
          tag_name: v${{ needs.check_release.outputs.version }}
          name: Release v${{ needs.check_release.outputs.version }}
          target_commitish: ${{ github.event.workflow_run.head_sha }}
          body: ${{ needs.extract_changelog.outputs.changelog }}
          files: 'killport-*.tar.gz'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish:
    needs: [check_release, release]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          # Build exactly the commit CI validated, not whatever main moved to.
          ref: ${{ github.event.workflow_run.head_sha }}
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo publish --token ${{ secrets.CRATES_IO }}
