name: Testing build (all platforms)

# Unsigned testing builds for Linux + Windows + macOS in one matrix. Click
# "Run workflow" in the Actions tab, or push a 0.0.0-testing-* tag. All three jobs
# publish to a single 0.0.0-testing-<short-sha> prerelease (distinct asset names).
#
# Per OS:
#   Linux   -> .deb
#   Windows -> NSIS installer (.exe)
#   macOS   -> .zip (arm64; dmg + signing are follow-ups)
#
# Unsigned: macOS is quarantined/Gatekeeper-blocked once downloaded
# (xattr -dr com.apple.quarantine "Agent Orchestrator.app"); Windows SmartScreen
# warns ("More info" -> "Run anyway"). Each OS builds on its own native runner so
# build-daemon.mjs compiles the bundled ao for that platform (host == target).

on:
  workflow_dispatch:
  push:
    tags:
      - "0.0.0-testing-*"

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: "@electron-forge/maker-deb"
          - os: windows-latest
            # Our custom NSIS maker's `name` (see makers/maker-nsis.ts); forge
            # `--targets` matches the configured maker instance by this name.
            target: "nsis"
          - os: macos-latest
            target: "@electron-forge/maker-zip"
    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    defaults:
      run:
        working-directory: frontend
    env:
      # Pure-Go sqlite (modernc) needs no cgo; on Linux this also keeps the daemon
      # static and portable across glibc.
      CGO_ENABLED: 0
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
          cache-dependency-path: frontend/package-lock.json
      - uses: actions/setup-go@v5
        with:
          go-version-file: backend/go.mod
          cache-dependency-path: backend/go.sum
      - run: npm ci
      - name: Build (unsigned)
        # `npm run make` keeps the premake daemon build; --targets restricts to this
        # platform's maker.
        run: npm run make -- --targets ${{ matrix.target }}
      # Smoke-install the NSIS installer on a clean, native x64 Windows runner.
      # This is a build-vs-host verdict: if it installs here it proves the artifact
      # is good and a failing user machine is host-side (AV/disk/signing); if it
      # fails here the build/NSIS config is wrong. continue-on-error so a failed
      # install never blocks publishing the artifacts. The runner has no real-time
      # AV blocking, so a clean install here does NOT prove SmartScreen/Defender
      # won't reject the unsigned binaries on end-user machines.
      - name: Smoke-install the Windows installer
        if: runner.os == 'Windows'
        continue-on-error: true
        timeout-minutes: 5
        shell: pwsh
        run: |
          $setup = Get-ChildItem -Path out/make -Recurse -Filter '*.exe' |
            Where-Object { $_.Name -like '*Setup*' } | Select-Object -First 1
          if (-not $setup) { $setup = Get-ChildItem -Path out/make -Recurse -Filter '*.exe' | Select-Object -First 1 }
          if (-not $setup) { Write-Host '::error::no NSIS installer (.exe) produced under out/make'; exit 1 }
          Write-Host "Running $($setup.FullName) /S (silent)"
          # electron-builder NSIS (assisted installer): /S installs silently.
          $proc = Start-Process -FilePath $setup.FullName -ArgumentList '/S' -PassThru -Wait
          Write-Host "Installer exit code: $($proc.ExitCode)"
          # Per-user assisted install lands under %LOCALAPPDATA%\Programs; a
          # per-machine install would land under Program Files.
          $installDir = @(
            (Join-Path $env:LOCALAPPDATA 'Programs\Agent Orchestrator'),
            (Join-Path ${env:ProgramFiles} 'Agent Orchestrator')
          ) | Where-Object { Test-Path $_ } | Select-Object -First 1
          if ($installDir) {
            Write-Host "INSTALL OK: $installDir created"
            Get-ChildItem $installDir | Select-Object Name | Format-Table -AutoSize
          } else {
            Write-Host "::warning::INSTALL: no known install dir found (checked LOCALAPPDATA\Programs and Program Files)"
          }
      - name: Publish to a 0.0.0-testing-<sha> prerelease
        shell: bash
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euo pipefail
          # Tag push: use the pushed tag. Manual run: mint 0.0.0-testing-<sha>.
          if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
            TAG="${GITHUB_REF_NAME}"
          else
            TAG="0.0.0-testing-${GITHUB_SHA::7}"
          fi
          # Matrix jobs race here; first one creates the release, the rest hit
          # "already exists" which is fine (|| true). Distinct asset names + --clobber
          # make uploads idempotent across re-runs.
          gh release create "$TAG" --prerelease --target "$GITHUB_SHA" --title "$TAG" \
            --notes "Unsigned testing build (Linux .deb / Windows NSIS .exe / macOS .zip). Not signed; for testing only." \
            || true
          # NUL-delimited to survive spaces in the app name ("Agent Orchestrator-...").
          find out/make -type f -print0 | while IFS= read -r -d '' f; do
            echo "uploading: $f"
            gh release upload "$TAG" "$f" --clobber
          done
