name: petdex-desktop release

on:
  push:
    tags:
      - "desktop-v*"
  workflow_dispatch:
    inputs:
      tag:
        description: "Tag to release (e.g. desktop-v0.1.0)"
        required: true

jobs:
  build:
    name: build ${{ matrix.target }}
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        include:
          - target: darwin-arm64
            runner: macos-14
          - target: darwin-x64
            runner: macos-13

    steps:
      - name: Checkout petdex
        uses: actions/checkout@v4
        with:
          # Manual workflow_dispatch must build from inputs.tag, not from
          # the branch the workflow file lives on. Tag pushes already
          # arrive with github.ref pointing at the tag.
          ref: ${{ inputs.tag || github.ref }}

      - name: Clone zero-native
        # build.zig resolves zero-native from -Dzero-native-path flag, the
        # ZERO_NATIVE_PATH env var, or ../../zero-native (in that order).
        # CI passes the checkout path explicitly via the env var so we
        # don't have to patch build.zig at runtime.
        #
        # Source defaults to Railly/zero-native:feature/window-resize because
        # the floating-window options + window.resize + focusable flag aren't
        # in vercel-labs/main yet. The feature/window-resize branch builds on
        # top of feature/floating-window (the PR currently in review). Update
        # ZERO_NATIVE_REMOTE / ZERO_NATIVE_BRANCH once everything merges
        # upstream so CI can switch to vercel-labs/main.
        env:
          ZERO_NATIVE_REMOTE: "https://github.com/Railly/zero-native.git"
          ZERO_NATIVE_BRANCH: "feature/window-resize"
        run: |
          set -euo pipefail
          git clone --depth 1 --branch "$ZERO_NATIVE_BRANCH" "$ZERO_NATIVE_REMOTE" "$GITHUB_WORKSPACE/zero-native"
          echo "ZERO_NATIVE_PATH=$GITHUB_WORKSPACE/zero-native/" >> "$GITHUB_ENV"

      - name: Install Zig 0.16.0
        uses: mlugg/setup-zig@v1
        with:
          version: "0.16.0"

      - name: Build petdex-desktop
        working-directory: packages/petdex-desktop
        run: |
          zig build -Doptimize=ReleaseSafe -Dzero-native-path="$ZERO_NATIVE_PATH"
          mv zig-out/bin/petdex-desktop "petdex-desktop-${{ matrix.target }}"
          ls -lh "petdex-desktop-${{ matrix.target }}"

      - name: Upload binary artifact
        uses: actions/upload-artifact@v4
        with:
          name: petdex-desktop-${{ matrix.target }}
          path: packages/petdex-desktop/petdex-desktop-${{ matrix.target }}

  sidecar:
    name: build sidecar (server.js)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout petdex
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag || github.ref }}

      - name: Install Bun
        uses: oven-sh/setup-bun@v2

      - name: Build sidecar
        working-directory: packages/petdex-desktop/sidecar
        run: |
          bun install --frozen-lockfile || bun install
          bun run build
          ls -lh server.js

      - name: Upload sidecar artifact
        uses: actions/upload-artifact@v4
        with:
          name: petdex-desktop-sidecar
          path: packages/petdex-desktop/sidecar/server.js

  build-windows:
    name: build win32-x64
    runs-on: windows-2022
    steps:
      - name: Checkout petdex
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag || github.ref }}

      - name: Install Rust stable (x86_64-pc-windows-msvc)
        # windows-2022 ships with Rust but pinning the toolchain + target
        # makes the job reproducible across runner image updates.
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-pc-windows-msvc

      - name: Cache Rust/Cargo build artefacts
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: packages/petdex-desktop-windows/src-tauri -> target

      - name: Install Tauri CLI
        # Install into the local cargo bin so the version is locked to what
        # tauri.conf.json declares, not whatever the runner image happens to
        # have. `--locked` ensures Cargo.lock is respected.
        run: cargo install tauri-cli --version "^2" --locked

      - name: Build petdex-desktop-win32-x64.exe
        # `--no-bundle` skips NSIS/WiX installer generation (we ship the
        # bare .exe per the CLI asset contract). `--bundles none` was
        # removed in tauri-cli 2.x; `--no-bundle` is the correct flag.
        # The binary name is driven by the [[bin]] entry in Cargo.toml.
        working-directory: packages/petdex-desktop-windows
        run: |
          cargo tauri build --no-bundle
          $exe = "src-tauri\target\release\petdex-desktop-win32-x64.exe"
          if (-not (Test-Path $exe)) { throw "Binary not found at $exe" }
          Write-Output "Binary size: $((Get-Item $exe).Length) bytes"
          Copy-Item $exe "petdex-desktop-win32-x64.exe"

      - name: Upload binary artifact
        uses: actions/upload-artifact@v4
        with:
          name: petdex-desktop-win32-x64
          path: packages/petdex-desktop-windows/petdex-desktop-win32-x64.exe

  release:
    name: publish github release
    needs: [build, build-windows, sidecar]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout petdex
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag || github.ref }}

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

      - name: Stage release assets
        run: |
          mkdir -p release
          find artifacts -type f -name "petdex-desktop-*" -exec cp {} release/ \;
          if [ -f artifacts/petdex-desktop-sidecar/server.js ]; then
            cp artifacts/petdex-desktop-sidecar/server.js release/petdex-desktop-sidecar.js
          fi
          test -f release/petdex-desktop-sidecar.js
          test -f release/petdex-desktop-darwin-arm64
          test -f release/petdex-desktop-darwin-x64
          test -f release/petdex-desktop-win32-x64.exe
          ls -lh release/

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          # `inputs.tag` is set on workflow_dispatch (manual run); on push of
          # a desktop-v* tag, `github.ref_name` carries the tag. The
          # `inputs.tag || github.ref_name` order works because `inputs.tag`
          # is null on tag pushes.
          tag_name: ${{ inputs.tag || github.ref_name }}
          files: release/*
          generate_release_notes: true
          fail_on_unmatched_files: true
          prerelease: ${{ contains(inputs.tag || github.ref_name, '-rc') }}
