name: Release
permissions:
  contents: write
  packages: write

on:
  pull_request:
  push:
    tags:
      - '**[0-9]+.[0-9]+.[0-9]+*'

jobs:
  plan:
    runs-on: ubuntu-22.04
    outputs:
      val: ${{ steps.plan.outputs.manifest }}
      tag: ${{ !github.event.pull_request && github.ref_name || '' }}
      tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
      publishing: ${{ !github.event.pull_request }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install dist
        shell: bash
        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.0/cargo-dist-installer.sh | sh"

      - name: Cache dist
        uses: actions/upload-artifact@v4
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/dist

      - id: plan
        run: |
          dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
          echo "dist ran successfully"
          cat plan-dist-manifest.json
          echo "manifest=$(jq -c . plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"

      - name: Upload dist-manifest.json
        uses: actions/upload-artifact@v4
        with:
          name: artifacts-plan-dist-manifest
          path: plan-dist-manifest.json

  build-local-artifacts:
    name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
    needs: [plan]
    if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
    runs-on: ${{ matrix.runner }}
    container: ${{ matrix.container && matrix.container.image || null }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
    steps:
      - name: enable windows longpaths
        run: git config --global core.longpaths true

      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Rust non-interactively if not already installed
        if: ${{ matrix.container }}
        run: |
          if ! command -v cargo > /dev/null 2>&1; then
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
            echo "$HOME/.cargo/bin" >> $GITHUB_PATH
          fi

      - name: Install dist
        run: ${{ matrix.install_dist.run }}

      - name: Fetch local artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: artifacts-*
          path: target/distrib/
          merge-multiple: true

      # ===== BEGIN: Injected ORT staging for cargo-dist bundling =====
      - run: echo "=== BUILD-SETUP START ==="

      # Unix shells
      - name: Prepare lib dir (Unix)
        if: runner.os != 'Windows'
        shell: bash
        run: |
          mkdir -p lib
          rm -f lib/*
      
      # Windows PowerShell
      - name: Prepare lib dir (Windows)
        if: runner.os == 'Windows'
        shell: pwsh
        run: |
          New-Item -ItemType Directory -Force -Path lib | Out-Null
          # remove contents if any
          Get-ChildItem -Path lib -Force | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue

      - name: Fetch ONNX Runtime (Linux)
        if: runner.os == 'Linux'
        env:
          ORT_VER: 1.22.0
        run: |
          set -euo pipefail
          ARCH="$(uname -m)"
          case "$ARCH" in
            x86_64)  URL="https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VER}/onnxruntime-linux-x64-${ORT_VER}.tgz" ;;
            aarch64) URL="https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VER}/onnxruntime-linux-aarch64-${ORT_VER}.tgz" ;;
            *) echo "Unsupported arch $ARCH"; exit 1 ;;
          esac
          curl -fsSL -o ort.tgz "$URL"
          tar -xzf ort.tgz
          cp -v onnxruntime-*/lib/libonnxruntime.so* lib/
          # normalize to stable name if needed
          [ -f lib/libonnxruntime.so ] || cp -v lib/libonnxruntime.so.* lib/libonnxruntime.so

      - name: Fetch ONNX Runtime (macOS)
        if: runner.os == 'macOS'
        env:
          ORT_VER: 1.22.0
        run: |
          set -euo pipefail
          curl -fsSL -o ort.tgz "https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VER}/onnxruntime-osx-universal2-${ORT_VER}.tgz"
          tar -xzf ort.tgz
          cp -v onnxruntime-*/lib/libonnxruntime*.dylib lib/
          [ -f lib/libonnxruntime.dylib ] || cp -v lib/libonnxruntime*.dylib lib/libonnxruntime.dylib

      - name: Fetch ONNX Runtime (Windows)
        if: runner.os == 'Windows'
        shell: pwsh
        env:
          ORT_VER: 1.22.0
        run: |
          $url = "https://github.com/microsoft/onnxruntime/releases/download/v$env:ORT_VER/onnxruntime-win-x64-$env:ORT_VER.zip"
          Invoke-WebRequest $url -OutFile ort.zip
          Expand-Archive ort.zip -DestinationPath ort
          $dll = Get-ChildItem -Recurse -Path ort -Filter onnxruntime.dll | Select-Object -First 1
          Copy-Item $dll.FullName lib\onnxruntime.dll

      - run: |
          echo "=== BUILD-SETUP END ==="
          echo "lib/ contents:"
          ls -l lib || dir lib
      # ===== END: Injected ORT staging =====

      - name: Install dependencies
        run: |
          ${{ matrix.packages_install }}

      - name: Build artifacts
        run: |
          dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
          echo "dist ran successfully"

      - id: cargo-dist
        name: Post-build
        shell: bash
        run: |
          echo "paths<<EOF" >> "$GITHUB_OUTPUT"
          dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"
          cp dist-manifest.json "$BUILD_MANIFEST_NAME"

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: artifacts-build-local-${{ join(matrix.targets, '_') }}
          path: |
            ${{ steps.cargo-dist.outputs.paths }}
            ${{ env.BUILD_MANIFEST_NAME }}

  build_and_push_docker_image:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    needs: [plan]
    if: ${{ needs.plan.outputs.publishing == 'true' }}
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  build-global-artifacts:
    needs: [plan, build-local-artifacts]
    runs-on: ubuntu-22.04
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install cached dist
        uses: actions/download-artifact@v4
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/
      - run: chmod +x ~/.cargo/bin/dist

      - name: Fetch local artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: artifacts-*
          path: target/distrib/
          merge-multiple: true

      - id: cargo-dist
        shell: bash
        run: |
          dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
          echo "dist ran successfully"
          echo "paths<<EOF" >> "$GITHUB_OUTPUT"
          jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"
          cp dist-manifest.json "$BUILD_MANIFEST_NAME"

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: artifacts-build-global
          path: |
            ${{ steps.cargo-dist.outputs.paths }}
            ${{ env.BUILD_MANIFEST_NAME }}

  host:
    needs: [plan, build-local-artifacts, build-global-artifacts]
    if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    runs-on: ubuntu-22.04
    outputs:
      val: ${{ steps.host.outputs.manifest }}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install cached dist
        uses: actions/download-artifact@v4
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/
      - run: chmod +x ~/.cargo/bin/dist

      - name: Fetch artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: artifacts-*
          path: target/distrib/
          merge-multiple: true

      - id: host
        shell: bash
        run: |
          dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
          echo "artifacts uploaded and released successfully"
          cat dist-manifest.json
          echo "manifest=$(jq -c . dist-manifest.json)" >> "$GITHUB_OUTPUT"

      - name: Upload dist-manifest.json
        uses: actions/upload-artifact@v4
        with:
          name: artifacts-dist-manifest
          path: dist-manifest.json

      - name: Download GitHub Artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: artifacts-*
          path: artifacts
          merge-multiple: true

      - name: Cleanup
        run: rm -f artifacts/*-dist-manifest.json

      - name: Create GitHub Release
        env:
          PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
          ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
          ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
          RELEASE_COMMIT: "${{ github.sha }}"
        run: |
          echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
          gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*

  announce:
    needs: [plan, host]
    if: ${{ always() && needs.host.result == 'success' }}
    runs-on: ubuntu-22.04
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
