# sim-pool.sh: one Simulator per agent, leased from a pool. Source it after helpers.sh:  . ./helpers.sh; . ./sim-pool.sh
#
# DOCUMENTED, NOT MEASURED. The Mac used for the article had no iOS Simulator runtime, so these functions
# never ran against a real device. Commands follow `xcrun simctl help <command>` and `man xcodebuild` in
# Xcode 26.6. The control flow (lease, exit status, quarantine) was checked with stand-in xcrun/xcodebuild
# functions only. Test on your own Mac before relying on it.
#
# One-time setup (pin the runtime so every device in the pool is the same):
#   xcrun simctl list runtimes                     # pick an installed iOS runtime identifier
#   export SIM_POOL_DIR="$HOME/agents/sim-pool"
#   make_sim_pool com.apple.CoreSimulator.SimRuntime.iOS-26-5 com.apple.CoreSimulator.SimDeviceType.iPhone-17 3
#
# Every test run (any number of agents; each waits for a free device):
#   with_simulator test_on_leased_simulator ~/agents/agent-2 -workspace MyApp.xcworkspace -scheme MyApp

make_sim_pool() {   # make_sim_pool RUNTIME_ID DEVICE_TYPE_ID COUNT
  local runtime="$1" type="$2" count="${3:-3}" i udid
  [ -n "${SIM_POOL_DIR:-}" ] || { echo "make_sim_pool: export SIM_POOL_DIR first" >&2; return 2; }
  xcrun simctl list runtimes | grep -q -- "$runtime" || { echo "make_sim_pool: runtime $runtime is not installed" >&2; return 2; }
  [ ! -e "$SIM_POOL_DIR/pool.txt" ] || { echo "make_sim_pool: $SIM_POOL_DIR/pool.txt exists; delete those devices first" >&2; return 2; }
  mkdir -p "$SIM_POOL_DIR" || return 2
  : > "$SIM_POOL_DIR/pool.txt.new" || return 2
  for i in $(seq 1 "$count"); do
    udid=$(xcrun simctl create "agent-pool-$i" "$type" "$runtime") || { echo "make_sim_pool: create failed" >&2; return 2; }
    echo "$udid" >> "$SIM_POOL_DIR/pool.txt.new"
  done
  mv "$SIM_POOL_DIR/pool.txt.new" "$SIM_POOL_DIR/pool.txt"
}

# Runs inside with_simulator, so the device lock is held from boot to reset.
# test_on_leased_simulator AGENT_DIR XCODEBUILD_ARGS...   (SIM_UDID comes from with_simulator)
# Writes AGENT_DIR/runs/<id>/{boot.log,xcodebuild.log,test.xcresult,final-screen.png,erase.log}.
# Returns the boot or test exit status, even if the screenshot or the reset fails.
test_on_leased_simulator() {
  local agent="$1" run rc=0
  shift
  run="$agent/runs/$(date +%Y%m%d-%H%M%S)-$(uuidgen)"
  mkdir -p "$run" || return 2
  echo "$SIM_UDID" > "$run/device.txt"
  if xcrun simctl bootstatus "$SIM_UDID" -b > "$run/boot.log" 2>&1; then
    # Parallel testing would run test classes on clones of this device, outside the pool's accounting.
    if xcodebuild test "$@" \
        -destination "platform=iOS Simulator,id=$SIM_UDID" \
        -parallel-testing-enabled NO \
        -derivedDataPath "$agent/DerivedData" \
        -resultBundlePath "$run/test.xcresult" > "$run/xcodebuild.log" 2>&1; then rc=0; else rc=$?; fi
    # The device's screen now, after the tests; screenshots taken during tests belong in test attachments.
    xcrun simctl io "$SIM_UDID" screenshot "$run/final-screen.png" > /dev/null 2>&1 || echo "lease: screenshot failed" >&2
  else
    rc=$?
    echo "lease: boot failed, see $run/boot.log" >&2
  fi
  # Return the device clean. Shutdown fails harmlessly if it is already shut down; a failed erase quarantines it.
  xcrun simctl shutdown "$SIM_UDID" > /dev/null 2>&1 || true
  if ! xcrun simctl erase "$SIM_UDID" > "$run/erase.log" 2>&1; then
    echo "$SIM_UDID" >> "$SIM_POOL_DIR/quarantine.txt"
    echo "lease: erase failed, $SIM_UDID quarantined" >&2
  fi
  echo "$run"
  return "$rc"
}
