name: Build and Publish Python Bindings

on:
  workflow_dispatch:
    inputs:
      tag:
        description: "The tag to release"
        required: true
  push:
    tags:
      - "*"

defaults:
  run:
    working-directory: .

jobs:
  macos:
    runs-on: macos-latest
    if: startsWith(github.ref, 'refs/tags/')
    strategy:
      matrix:
        target: [x86_64, universal2-apple-darwin]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: 3.7
          architecture: x64

      - name: Set Cargo.toml version to match github tag
        shell: bash
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mv Cargo.toml Cargo.toml.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.toml.orig >Cargo.toml
          mv Cargo.lock Cargo.lock.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.lock.orig >Cargo.lock

      - uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly-2023-06-27
          override: true
          components: rustfmt, clippy

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --features python-bindings
      - name: Install built wheel
        run: |
          pip install ezkl --no-index --find-links dist --force-reinstall
          python -c "import ezkl"

      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: wheels
          path: dist

  windows:
    runs-on: windows-latest
    if: startsWith(github.ref, 'refs/tags/')
    strategy:
      matrix:
        target: [x64, x86]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: 3.7
          architecture: ${{ matrix.target }}

      - name: Set Cargo.toml version to match github tag
        shell: bash
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mv Cargo.toml Cargo.toml.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.toml.orig >Cargo.toml
          mv Cargo.lock Cargo.lock.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.lock.orig >Cargo.lock

      - uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly-2023-06-27
          override: true
          components: rustfmt, clippy

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --features python-bindings
      - name: Install built wheel
        run: |
          pip install ezkl --no-index --find-links dist --force-reinstall
          python -c "import ezkl"

      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: wheels
          path: dist

  linux:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    strategy:
      matrix:
        target: [x86_64, i686]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: 3.7
          architecture: x64

      - name: Set Cargo.toml version to match github tag
        shell: bash
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mv Cargo.toml Cargo.toml.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.toml.orig >Cargo.toml
          mv Cargo.lock Cargo.lock.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.lock.orig >Cargo.lock

      - name: Install required libraries
        shell: bash
        run: |
          sudo apt-get update && sudo apt-get install -y openssl pkg-config libssl-dev

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          manylinux: auto
          args: --release --out dist --features python-bindings

      - name: Install built wheel
        if: matrix.target == 'x86_64'
        run: |
          pip install ezkl --no-index --find-links dist --force-reinstall
          python -c "import ezkl"

      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: wheels
          path: dist

  # TODO: There's a problem with the maturin-action toolchain for arm arch leading to failed builds
  # linux-cross:
  #   runs-on: ubuntu-latest
  #   strategy:
  #     matrix:
  #       target: [aarch64, armv7]
  #   steps:
  #   - uses: actions/checkout@v4
  #   - uses: actions/setup-python@v4
  #     with:
  #       python-version: 3.7

  #   - name: Install cross-compilation tools for aarch64
  #     if: matrix.target == 'aarch64'
  #     run: |
  #       sudo apt-get update
  #       sudo apt-get install -y gcc make gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu libc6-dev-arm64-cross libusb-1.0-0-dev libatomic1-arm64-cross

  #   - name: Install cross-compilation tools for armv7
  #     if: matrix.target == 'armv7'
  #     run: |
  #       sudo apt-get update
  #       sudo apt-get install -y gcc make gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libc6-dev-armhf-cross libusb-1.0-0-dev libatomic1-armhf-cross

  #   - name: Build wheels
  #     uses: PyO3/maturin-action@v1
  #     with:
  #       target: ${{ matrix.target }}
  #       manylinux: auto
  #       args: --release --out dist --features python-bindings

  #   - uses: uraimo/run-on-arch-action@v2.5.0
  #     name: Install built wheel
  #     with:
  #       arch: ${{ matrix.target }}
  #       distro: ubuntu20.04
  #       githubToken: ${{ github.token }}
  #       install: |
  #         apt-get update
  #         apt-get install -y --no-install-recommends python3 python3-pip
  #         pip3 install -U pip
  #       run: |
  #         pip3 install ezkl --no-index --find-links dist/ --force-reinstall
  #         python3 -c "import ezkl"

  #   - name: Upload wheels
  #     uses: actions/upload-artifact@v3
  #     with:
  #       name: wheels
  #       path: dist

  musllinux:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    strategy:
      matrix:
        target:
          - x86_64-unknown-linux-musl
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: 3.7
          architecture: x64

      - name: Set Cargo.toml version to match github tag
        shell: bash
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mv Cargo.toml Cargo.toml.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.toml.orig >Cargo.toml
          mv Cargo.lock Cargo.lock.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.lock.orig >Cargo.lock

      - name: Install required libraries
        shell: bash
        run: |
          sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          manylinux: musllinux_1_2
          args: --release --out dist --features python-bindings

      - name: Install built wheel
        if: matrix.target == 'x86_64-unknown-linux-musl'
        uses: addnab/docker-run-action@v3
        with:
          image: alpine:latest
          options: -v ${{ github.workspace }}:/io -w /io
          run: |
            apk add py3-pip
            pip3 install -U pip
            python3 -m venv .venv
            source .venv/bin/activate            
            pip3 install ezkl --no-index --find-links /io/dist/ --force-reinstall
            python3 -c "import ezkl"

      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: wheels
          path: dist

  musllinux-cross:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    strategy:
      matrix:
        platform:
          - target: aarch64-unknown-linux-musl
            arch: aarch64
          - target: armv7-unknown-linux-musleabihf
            arch: armv7
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: 3.7

      - name: Set Cargo.toml version to match github tag
        shell: bash
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mv Cargo.toml Cargo.toml.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.toml.orig >Cargo.toml
          mv Cargo.lock Cargo.lock.orig
          sed "s/0\\.0\\.0/${RELEASE_TAG//v}/" Cargo.lock.orig >Cargo.lock

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          manylinux: musllinux_1_2
          args: --release --out dist --features python-bindings

      - uses: uraimo/run-on-arch-action@v2.5.0
        name: Install built wheel
        with:
          arch: ${{ matrix.platform.arch }}
          distro: alpine_latest
          githubToken: ${{ github.token }}
          run: |
            apk add py3-pip
            python3 -m venv .venv
            source .venv/bin/activate
            pip3 install -U pip
            pip3 install ezkl --no-index --find-links dist/ --force-reinstall
            python3 -c "import ezkl"

      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: wheels
          path: dist

  pypi-publish:
    name: Uploads release to PyPI
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    if: "startsWith(github.ref, 'refs/tags/')"
    # TODO: Uncomment if linux-cross is working
    # needs: [ macos, windows, linux, linux-cross, musllinux, musllinux-cross ]
    needs: [macos, windows, linux, musllinux, musllinux-cross]
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: wheels
      - name: List Files
        run: ls -R

      # Both publish steps will fail if there is no trusted publisher setup
      # On failure the publish step will then simply continue to the next one

      # publishes to PyPI
      - name: Publish package distributions to PyPI
        continue-on-error: true
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: ./

      # publishes to TestPyPI
      - name: Publish package distribution to TestPyPI
        continue-on-error: true
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          repository-url: https://test.pypi.org/legacy/
          packages-dir: ./
