name: Release

on:
  push:
    tags:
      - "v*"
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

jobs:
  create-release:
    name: Create Release
    runs-on: ubuntu-latest
    permissions:
      contents: write
    outputs:
      release_id: ${{ steps.create_release.outputs.id }}
      upload_url: ${{ steps.create_release.outputs.upload_url }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Create Release
        id: create_release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          name: ${{ github.ref_name }}
          draft: true
          prerelease: ${{ contains(github.ref_name, '-') }}
          generate_release_notes: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  build-binaries:
    name: Build Binaries
    needs: create-release
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            name: linux-x64
            artifact_name: pysentry
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            name: linux-x64-musl
            artifact_name: pysentry
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            name: linux-arm64
            artifact_name: pysentry
          - target: x86_64-apple-darwin
            os: macos-latest
            name: macos-x64
            artifact_name: pysentry
          - target: aarch64-apple-darwin
            os: macos-latest
            name: macos-arm64
            artifact_name: pysentry
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            name: windows-x64
            artifact_name: pysentry.exe

    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4

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

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          prefix-key: "release-${{ matrix.target }}"
          shared-key: "pysentry"

      - name: Install cross
        if: matrix.target != 'x86_64-unknown-linux-gnu'
        run: cargo install cross

      - name: Build binary (native)
        if: matrix.target == 'x86_64-unknown-linux-gnu'
        run: cargo build --release --target ${{ matrix.target }} --bin pysentry

      - name: Build binary (cross-compile)
        if: matrix.target != 'x86_64-unknown-linux-gnu'
        run: cross build --release --target ${{ matrix.target }} --bin pysentry

      - name: Package binary (Unix)
        if: matrix.os != 'windows-latest'
        run: |
          name=pysentry-${{ matrix.name }}
          mkdir $name
          cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} $name/
          cp README.md $name/
          cp LICENSE $name/
          tar -czf $name.tar.gz $name
          echo "ASSET=$name.tar.gz" >> $GITHUB_ENV

      - name: Package binary (Windows)
        if: matrix.os == 'windows-latest'
        run: |
          $name = "pysentry-${{ matrix.name }}"
          mkdir $name
          cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} $name/
          cp README.md $name/
          cp LICENSE $name/
          Compress-Archive -Path $name -DestinationPath "$name.zip"
          echo "ASSET=$name.zip" | Out-File -FilePath $env:GITHUB_ENV -Append

      - name: Upload binary artifact
        uses: actions/upload-artifact@v4
        with:
          name: binary-${{ matrix.name }}
          path: ${{ env.ASSET }}

  upload-release-assets:
    name: Upload Release Assets
    runs-on: ubuntu-latest
    needs: build-binaries
    permissions:
      contents: write
    steps:
      - name: Download all binary artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: binary-*
          path: binaries
          merge-multiple: true

      - name: List downloaded files
        run: ls -la binaries/

      - name: Upload to GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          files: binaries/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  verify-all-builds:
    name: Verify All Builds Complete
    runs-on: ubuntu-latest
    needs:
      [build-binaries, upload-release-assets, build-python-wheels, build-sdist]
    if: always()
    steps:
      - name: Check build results
        run: |
          echo "Build Binaries: ${{ needs.build-binaries.result }}"
          echo "Upload Release Assets: ${{ needs.upload-release-assets.result }}"
          echo "Build Python Wheels: ${{ needs.build-python-wheels.result }}"
          echo "Build Source Distribution: ${{ needs.build-sdist.result }}"

          if [[ "${{ needs.build-binaries.result }}" != "success" ]]; then
            echo "❌ Build Binaries failed or was cancelled"
            exit 1
          fi

          if [[ "${{ needs.upload-release-assets.result }}" != "success" ]]; then
            echo "❌ Upload Release Assets failed or was cancelled"
            exit 1
          fi

          if [[ "${{ needs.build-python-wheels.result }}" != "success" ]]; then
            echo "❌ Build Python Wheels failed or was cancelled"
            exit 1
          fi

          if [[ "${{ needs.build-sdist.result }}" != "success" ]]; then
            echo "❌ Build Source Distribution failed or was cancelled"
            exit 1
          fi

          echo "✅ All builds completed successfully"

  publish-crates:
    name: Publish to Crates.io
    runs-on: ubuntu-latest
    needs: verify-all-builds
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4

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

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          prefix-key: "publish"
          shared-key: "pysentry"

      - name: Publish to crates.io
        run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}

  build-python-wheels:
    name: Build Python Wheels
    runs-on: ${{ matrix.osarch.os }}
    strategy:
      matrix:
        osarch:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
          - os: ubuntu-latest
            target: aarch64-unknown-linux-gnu
          - os: windows-latest
            target: x86_64-pc-windows-msvc
          - os: macos-latest
            target: x86_64-apple-darwin
          - os: macos-latest
            target: aarch64-apple-darwin
        python:
          ["3.9", "3.10", "3.11", "3.12", "3.13", "3.13t", "3.14", "3.14t"]
    steps:
      - uses: actions/checkout@v4

      - name: Install system dependencies (Ubuntu)
        if: startsWith(matrix.osarch.os, 'ubuntu')
        run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
          allow-prereleases: true

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

      - name: Set manylinux version
        id: manylinux
        if: startsWith(matrix.osarch.os, 'ubuntu')
        run: |
          if [[ "${{ matrix.osarch.target }}" == "aarch64-unknown-linux-gnu" ]]; then
            echo "version=2_28" >> $GITHUB_OUTPUT
          else
            echo "version=auto" >> $GITHUB_OUTPUT
          fi

      - name: Build wheels
        uses: PyO3/maturin-action@v1.49.4
        with:
          command: build
          args: --release --features python --out dist -i ${{ matrix.python }}
          sccache: "true"
          manylinux: ${{ steps.manylinux.outputs.version || 'auto' }}
          target: ${{ matrix.osarch.target }}

      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-${{ matrix.osarch.os }}-${{ matrix.osarch.target }}-${{ matrix.python }}
          path: dist/*.whl

  build-sdist:
    name: Build Source Distribution
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

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

      - name: Build sdist
        uses: PyO3/maturin-action@v1.49.4
        with:
          command: sdist
          args: --out dist

      - name: Upload sdist
        uses: actions/upload-artifact@v4
        with:
          name: sdist
          path: dist/*.tar.gz

  publish-pypi:
    name: Publish to PyPI
    runs-on: ubuntu-latest
    needs: verify-all-builds
    if: startsWith(github.ref, 'refs/tags/v')
    permissions:
      id-token: write
    steps:
      - name: Download wheel artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: wheels-*
          path: artifacts/wheels
          merge-multiple: true

      - name: Download sdist artifact
        uses: actions/download-artifact@v4
        with:
          name: sdist
          path: artifacts/sdist

      - name: Prepare packages for upload
        run: |
          mkdir -p dist
          cp artifacts/wheels/*.whl dist/
          cp artifacts/sdist/*.tar.gz dist/
          echo "📦 Packages to upload:"
          ls -la dist/

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@v1.13.0
        with:
          packages-dir: dist/

  update-release:
    name: Update Release
    runs-on: ubuntu-latest
    permissions:
      contents: write
    needs: [publish-crates, publish-pypi]
    if: success()
    steps:
      - name: Mark release as published
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          draft: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
