#!/usr/bin/env bash
# dangerlab-reap — collect clones whose owner is gone or overdue. Runs from
# dangerlab-reaper.timer, so cleanup never depends on the agent that started the run.
source /home/user/dangerlab/dangerlab-lib.sh

now=$(date +%s)
reaped=0

lock_free() { ( exec 9>"$1"; flock -n 9 ) >/dev/null 2>&1; }

for k in $(slot_seq); do
  lock=$(slot_lock "$k"); dom=$(slot_dom "$k")
  state=$(vm_state "$dom")
  [[ -n "$state" || -f "$(slot_overlay "$k")" ]] || continue

  keep=$(cat "$(slot_keep "$k")" 2>/dev/null || true)
  if [[ -n "$keep" && "$keep" =~ ^[0-9]+$ ]] && (( now < keep )); then
    printf 'dangerlab-reap: slot%s pinned by --keep for %ss more\n' "$k" "$(( keep - now ))"
    continue
  fi

  reason=""
  if [[ -n "$keep" ]]; then
    reason="--keep pin expired"
  elif lock_free "$lock"; then
    reason="owner gone"
  else
    deadline=$(cat "$(slot_deadline "$k")" 2>/dev/null || true)
    if [[ ! "$deadline" =~ ^[0-9]+$ ]]; then
      # A live owner still holds the slot and there is nothing to judge it by. Leaving
      # it alone is the safe error: destroying a healthy run is worse than carrying one
      # clone until its owner exits and the lock-free branch collects it.
      printf 'dangerlab-reap: slot%s held with no deadline recorded — leaving it to its owner\n' "$k" >&2
    elif (( now > deadline + REAP_GRACE )); then
      reason="overdue by $(( now - deadline ))s with the owner still holding the slot"
    fi
  fi
  [[ -n "$reason" ]] || continue

  if clone_destroy "$k"; then
    rm -f "$(slot_deadline "$k")" "$(slot_keep "$k")"
    printf 'dangerlab-reap: REAPED slot%s (%s) domain=%s\n' "$k" "$reason" "${state:-undefined}"
    reaped=$(( reaped + 1 ))
  else
    printf 'dangerlab-reap: FAILED to reap slot%s (%s)\n' "$k" "$reason" >&2
    exit 1
  fi
done

printf 'dangerlab-reap: %s clone(s) collected\n' "$reaped"
