name: Release

on:
  push:
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+"
      - "v[0-9]+.[0-9]+.[0-9]+-*" # Also match pre-release tags like v1.0.0-beta.1

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always

jobs:
  # Validate the release before creating it
  validate:
    name: Validate Release
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Strip path dependencies
        uses: ./.github/actions/strip-path-deps

      - name: Verify version matches tag
        run: |
          TAG_VERSION="${GITHUB_REF#refs/tags/v}"
          CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "text-typeset") | .version')
          if [[ "$TAG_VERSION" != "$CARGO_VERSION" ]]; then
            echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
            echo "::error::Update the version in Cargo.toml before tagging."
            exit 1
          fi
          echo "Version validated: $CARGO_VERSION"

      - name: Run tests
        run: cargo test --workspace

  # Publish to crates.io
  publish:
    name: Publish to crates.io
    needs: validate
    runs-on: ubuntu-latest
    timeout-minutes: 15
    # Skip for pre-release tags
    if: ${{ !contains(github.ref_name, '-') }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2

      - name: Strip path dependencies
        uses: ./.github/actions/strip-path-deps

      - name: Publish crates to crates.io
        run: cargo publish --workspace --allow-dirty
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  # Create the GitHub release
  release:
    name: Create Release
    needs: publish
    # Run even if publish was skipped (pre-release) but not if it failed
    if: ${{ always() && (needs.publish.result == 'success' || needs.publish.result == 'skipped') }}
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Download all artifacts
        uses: actions/download-artifact@v8
        with:
          path: artifacts

      - name: Prepare release files
        run: |
          mkdir -p release
          find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" \) -exec mv {} release/ \;
          ls -la release/

      - name: Generate checksums
        run: |
          cd release
          sha256sum * > SHA256SUMS.txt
          cat SHA256SUMS.txt

      - name: Extract release notes from CHANGELOG
        id: changelog
        run: |
          VERSION="${GITHUB_REF#refs/tags/v}"
          if [[ -f CHANGELOG.md ]]; then
            sed -n "/^## \[${VERSION}\]/,/^## \[/p" CHANGELOG.md | sed '1d;$d' > release_notes.md
            if [[ ! -s release_notes.md ]]; then
              echo "No changelog entry found for version ${VERSION}" > release_notes.md
            fi
          else
            echo "Release ${VERSION}" > release_notes.md
          fi

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          name: ${{ github.ref_name }}
          body_path: release_notes.md
          draft: false
          prerelease: ${{ contains(github.ref_name, '-') }}
          files: |
            release/*
          generate_release_notes: true
          fail_on_unmatched_files: true
