#!/usr/bin/env bash
# Starts an ephemeral agent sandbox on a buildbox and collects its tool gaps when
# it exits. No agent compute, no container, and no browser ever runs here.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
REGISTRY="$SCRIPT_DIR/../lib/buildbox-registry.mjs"
GAP_STATE="${SANDBOX_GAP_STATE:-$HOME/.local/state/overdeck/sandbox/toolgap.jsonl}"
HOST=""
ID=""
PASSTHROUGH=()
CMD=()

usage() {
  cat >&2 <<'USAGE'
usage: agent-sandbox [--host <name>] --id <slug> [--memory 12g] [--pids 512] [--cpus 4] [-- <cmd...>]

Without a command the sandbox opens an interactive shell. The workspace lives at
/sandbox/workspaces/<slug> inside the container and survives across runs; the
container itself never does.
USAGE
  exit "${1:-2}"
}

while [ $# -gt 0 ]; do
  case "$1" in
    --host)   HOST="${2-}"; shift 2 ;;
    --id)     ID="${2-}"; PASSTHROUGH+=(--id "${2-}"); shift 2 ;;
    --memory) PASSTHROUGH+=(--memory "${2-}"); shift 2 ;;
    --pids)   PASSTHROUGH+=(--pids "${2-}"); shift 2 ;;
    --cpus)   PASSTHROUGH+=(--cpus "${2-}"); shift 2 ;;
    --)       shift; CMD=("$@"); break ;;
    -h|--help) usage 0 ;;
    *) echo "agent-sandbox: unknown arg: $1" >&2; usage ;;
  esac
done

[ -n "$ID" ] || { echo "agent-sandbox: --id is required" >&2; usage; }
[ -r "$REGISTRY" ] || { echo "agent-sandbox: buildbox registry resolver missing at $REGISTRY" >&2; exit 2; }

if [ -z "$HOST" ]; then
  HOST="$(node -e '
    import("'"$REGISTRY"'").then(({ loadRegistry, resolveHosts }) => {
      const registry = loadRegistry();
      const byName = new Map(registry.hosts.map((h) => [h.name, h]));
      const candidates = resolveHosts(registry, { order: "build" })
        .filter((name) => byName.get(name).roles.includes("agent-seat"));
      if (candidates.length === 0) throw new Error("no enabled registry host carries the agent-seat role");
      process.stdout.write(byName.get(candidates[0]).ssh_alias);
    }).catch((err) => { process.stderr.write(`agent-sandbox: ${err.message}\n`); process.exit(3); });
  ')"
fi
[ -n "$HOST" ] || exit 3

SSH_OPTS=(-F "$HOME/.ssh/config" -o BatchMode=yes)
if [ -t 0 ] && [ -t 1 ]; then
  SSH_OPTS+=(-t)
  PASSTHROUGH+=(--tty)
fi

REMOTE_CMD=(".local/share/overdeck-sandbox/bin/sandbox-run" "${PASSTHROUGH[@]}")
[ "${#CMD[@]}" -gt 0 ] && REMOTE_CMD+=(--)
for arg in ${CMD[@]+"${CMD[@]}"}; do REMOTE_CMD+=("$arg"); done

QUOTED=""
for arg in "${REMOTE_CMD[@]}"; do QUOTED+=" $(printf '%q' "$arg")"; done

set +e
ssh "${SSH_OPTS[@]}" "$HOST" "$QUOTED"
RC=$?
set -e

STATE_DIR="$(dirname "$GAP_STATE")"
mkdir -p "$STATE_DIR"
RSYNC_SSH="ssh -F $HOME/.ssh/config -o BatchMode=yes"
rsync -q -e "$RSYNC_SSH" "$HOST:.local/share/overdeck-sandbox/agent-image-tag" \
  "$STATE_DIR/agent-image-tag" 2>/dev/null || true
PER_HOST_DIR="$STATE_DIR/hosts"
mkdir -p "$PER_HOST_DIR"
if rsync -q -e "$RSYNC_SSH" "$HOST:sandbox/toolgap/gaps.jsonl" "$PER_HOST_DIR/$HOST.jsonl" 2>/dev/null; then
  cat "$PER_HOST_DIR"/*.jsonl >"$GAP_STATE.new"
  mv "$GAP_STATE.new" "$GAP_STATE"
fi

exit "$RC"
