#!/usr/bin/env sh
# Roverly CI gate — paste into any pipeline. Needs only `curl` and `jq`.
#
# The zero-install half of D15. For builds to upload, PR context, richer
# errors and a written-out PR comment, use ./roverly instead — this is the
# smallest thing that correctly gates a pull request.
#
#   ROVERLY_API_KEY   a CI key with the 'trigger' and 'read' scopes
#   PROJECT_ID        the Roverly project to run against
#   RUN_TYPE          regression | feature   (learn is refused — D11)
#   GOAL              required for feature runs
#
# Exit 0 = check passes (or was superseded). Exit 1 = check fails.
set -eu

API="${ROVERLY_API:-https://api.roverly.ai}"
RUN_TYPE="${RUN_TYPE:-regression}"
# MUST stay under the backend's 1h stale-PENDING reaper: past that the run is
# marked FAILED for never being adopted, and polling on would report the
# reaper's verdict as if the app were broken.
TIMEOUT="${TIMEOUT:-2700}"
POLL="${POLL:-15}"

# Built with jq, NOT by pasting shell variables into a JSON string. GOAL comes
# from a pull-request title or description, and titles routinely contain a
# double quote — `Fix the "login" bug` would close the JSON string early and the
# API would 422, failing the check for a reason that has nothing to do with the
# code under test. jq is already required here, so this costs nothing.
# `del(..|select(. == null or . == ""))` drops the fields the caller didn't set.
body=$(jq -nc \
  --arg project_id "$PROJECT_ID" \
  --arg run_type "$RUN_TYPE" \
  --arg goal "${GOAL:-}" \
  --arg branch "${BRANCH:-}" \
  --arg commit_sha "${COMMIT_SHA:-}" \
  --arg pr_number "${PR_NUMBER:-}" \
  '{project_id: $project_id, run_type: $run_type, goal: $goal, branch: $branch,
    commit_sha: $commit_sha,
    pr_number: (if $pr_number == "" then null else ($pr_number | tonumber) end)}
   | with_entries(select(.value != null and .value != ""))')

run_id=$(curl -sS -X POST "$API/v1/runs" \
  -H "Authorization: Bearer $ROVERLY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "$body" | jq -er '.id') || {
    echo "roverly: could not start a run (check the key's scopes, the project id," >&2
    echo "  and — for regression — that a production run is pinned)." >&2
    exit 1
  }
echo "roverly: run $run_id queued"

waited=0
while [ "$waited" -lt "$TIMEOUT" ]; do
  sleep "$POLL"
  waited=$((waited + POLL))
  status=$(curl -sS "$API/v1/runs/$run_id" \
    -H "Authorization: Bearer $ROVERLY_API_KEY" | jq -er '.status')
  # Terminal set, NOT `!= running`: `processing` means the post-run analysis is
  # still deciding what the findings are, so stopping there reads the verdict
  # before the findings exist and passes a broken pull request.
  case "$status" in
    succeeded|failed|cancelled) break ;;
  esac
done

case "$status" in
  succeeded|failed|cancelled) ;;
  *)
    echo "roverly: gave up after ${TIMEOUT}s; run is still '$status'." >&2
    echo "  No paired desktop has picked it up — is one online?" >&2
    exit 1 ;;
esac

summary=$(curl -sS "$API/v1/runs/$run_id/summary" \
  -H "Authorization: Bearer $ROVERLY_API_KEY")
echo "$summary" | jq -r '.markdown'

# Superseded by a newer commit on the same PR: a deliberate skip, exit 0.
[ "$(echo "$summary" | jq -r '.superseded')" = "true" ] && exit 0
[ "$(echo "$summary" | jq -r '.status')" = "pass" ] && exit 0
exit 1
