name: Publish to npm

on:
  push:
    tags:
#      - '[0-9]*'
      - 'npm[0-9]+.[0-9]+.[0-9]+'
  workflow_dispatch:
    inputs:
      skip_build:
        description: 'Skip native+wasm build and use artifacts from run ID'
        required: false
        default: ''

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

permissions:
  id-token: write
  contents: read

jobs:
  build-native:
    name: Build native (${{ matrix.target }})
    runs-on: ${{ matrix.runner }}
    if: ${{ !inputs.skip_build }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            runner: ubuntu-latest
            toolchain: stable
            features: x86_set
          - target: aarch64-unknown-linux-gnu
            runner: ubuntu-24.04-arm
            toolchain: nightly
            features: aarch64_set
          - target: aarch64-apple-darwin
            runner: macos-14
            toolchain: nightly
            features: aarch64_set
          - target: x86_64-pc-windows-msvc
            runner: windows-latest
            toolchain: stable
            features: x86_set

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

      - uses: actions/setup-node@v6
        with:
          node-version: '24'

      - name: Install @napi-rs/cli
        run: npm install -g @napi-rs/cli

      - name: Install build dependencies (Linux)
        if: matrix.target == 'x86_64-unknown-linux-gnu'
        run: |
          sudo apt-get update
          sudo apt-get install -y cmake nasm

      - name: Install cross-compilation tools (Linux aarch64)
        if: matrix.target == 'aarch64-unknown-linux-gnu'
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            cmake nasm \
            gcc-aarch64-linux-gnu \
            g++-aarch64-linux-gnu \
            binutils-aarch64-linux-gnu

      - name: Cache Cargo registry + build
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry/index
            ~/.cargo/registry/cache
            ~/.cargo/git/db
            target/
          key: cargo-${{ matrix.target }}-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            cargo-${{ matrix.target }}-${{ matrix.toolchain }}-
            cargo-${{ matrix.target }}-

      - name: Install build dependencies (macOS)
        if: runner.os == 'macOS'
        run: |
          brew install cmake nasm 

      - name: Install nasm (manual)
        if: runner.os == 'Windows'
        shell: powershell
        run: |
          Invoke-WebRequest -Uri "https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/win64/nasm-2.16.03-win64.zip" -OutFile nasm.zip
          Expand-Archive nasm.zip -DestinationPath C:\nasm
          echo "C:\nasm\nasm-2.16.03" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

      - name: Build native addon
        working-directory: pic-scale-js
        env:
          PKG_CONFIG_ALL_STATIC: ${{ runner.os != 'Windows' && '1' || '' }}
          MACOSX_DEPLOYMENT_TARGET: ${{ runner.os == 'macOS' && '11.0' || '' }}
        run: |
          napi build --release --platform --target ${{ matrix.target }} --features "napi,${{ matrix.features }}" --output-dir dist/

      - uses: actions/upload-artifact@v6
        with:
          name: native-${{ matrix.target }}
          path: pic-scale-js/dist/*.node
          retention-days: 1

  build-wasm:
    name: Build WASM
    runs-on: ubuntu-latest
    if: ${{ !inputs.skip_build }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: wasm32-unknown-unknown

      - name: Install wasm-pack
        run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

      - name: Build (bundler)
        working-directory: pic-scale-js
        run: |
          RUSTFLAGS="-C target-feature=+simd128" \
          wasm-pack build --release --target bundler \
            --out-dir wasm-pkg/bundler \
            --features wasm

      - name: Build (web)
        working-directory: pic-scale-js
        run: |
          RUSTFLAGS="-C target-feature=+simd128" \
          wasm-pack build --release --target web \
            --out-dir wasm-pkg/web \
            --features wasm

      - name: Build (nodejs)
        working-directory: pic-scale-js
        run: |
          RUSTFLAGS="-C target-feature=+simd128" \
          wasm-pack build --release --target nodejs \
            --out-dir wasm-pkg/nodejs \
            --features wasm

      - uses: actions/upload-artifact@v6
        with:
          name: wasm-pkg
          path: pic-scale-js/wasm-pkg/
          retention-days: 1

  publish:
    name: Publish to npm
    needs: [ build-native, build-wasm ]
    runs-on: ubuntu-latest
    if: success() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch')
    environment: Cargo
    permissions:
      contents: read
      id-token: write

    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: '24'
          registry-url: 'https://registry.npmjs.org'
          package-manager-cache: false

      - run: npm install -g npm@latest

      # Required for OIDC trusted publishing
      - name: Install dependencies
        working-directory: pic-scale-js
        run: npm install

      - name: Download artifacts (this run)
        if: ${{ !inputs.skip_build }}
        uses: actions/download-artifact@v6
        with:
          path: pic-scale-js/artifacts/

      - name: Download artifacts (previous run)
        if: ${{ inputs.skip_build != '' }}
        uses: actions/download-artifact@v6
        with:
          path: pic-scale-js/artifacts/
          run-id: ${{ inputs.skip_build }}
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract version from Cargo.toml
        id: version
        working-directory: pic-scale-js
        run: |
          VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Assemble dist/
        working-directory: pic-scale-js
        run: |
          VERSION="${{ steps.version.outputs.version }}"
          mkdir -p dist/wasm

          # ── native .node files ──────────────────────────────────────────────
          # napi-rs CLI generates index.js / index.d.ts / index.mjs that load
          # the right platform binary at runtime. Copy everything it produced.
          # ── native .node files ──────────────────────────────────────────────
          for node_file in artifacts/native-*/*.node; do
            [ -f "$node_file" ] || continue
            cp "$node_file" "dist/$(basename "$node_file")"
          done

          # ── WASM bundle ─────────────────────────────────────────────────────
          # Use the bundler build as the default WASM target (vite/webpack).
          rsync -a --exclude='package.json' --exclude='.gitignore' \
            artifacts/wasm-pkg/bundler/ dist/wasm/bundler/
          rsync -a --exclude='package.json' --exclude='.gitignore' \
            artifacts/wasm-pkg/web/ dist/wasm/web/
          rsync -a --exclude='package.json' --exclude='.gitignore' \
            artifacts/wasm-pkg/nodejs/ dist/wasm/nodejs/

          if [ -f dist/wasm/nodejs/pic_scale_js.js ]; then
             mv dist/wasm/nodejs/pic_scale_js.js dist/wasm/nodejs/pic_scale_js.cjs
          fi

          # ── loader files (generated by napi build) ──────────────────────────
          # napi build --output-dir dist/ already wrote index.js/mjs/d.ts there.
          # If not present, generate them now.
          if [ ! -f dist/index.js ]; then
            npx @napi-rs/cli artifacts --dist dist/
          fi

          cp README.md dist/README.md
          cp index.js dist/index.js
          cp index.mjs dist/index.mjs
          cp index.d.ts dist/index.d.ts

          sed "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" \
            package.json > dist/package.json
          jq 'del(.devDependencies)' dist/package.json \
            > dist/package.tmp && mv dist/package.tmp dist/package.json

      - name: Publish
        working-directory: pic-scale-js/dist
        run: npm install && npm ci && npm publish --provenance --access public