#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  ralph-loop-run --repo DIR --tasks-file FILE [options]

Options:
  --repo DIR            Target repo/worktree. Required.
  --tasks-file FILE     Seed task file. Required.
  --count N             Iterations. Default: 10.
  --run-dir DIR         Output dir. Default: /home/sebas/runtime/ralph-loops/<timestamp>
  --provider NAME       pi provider. Default: openai-codex.
  --model MODEL         pi model. Default: gpt-5.4-mini.
  --thinking LEVEL      pi thinking. Default: low.
  --allow-extensions    Do not pass --no-extensions.
  -h, --help            Show help.

Behavior:
- blocking sequential loop
- file-based state in run dir
- each iteration gets a fresh pi invocation
- agents communicate only via TASKS.md and STATE.md in the run dir
EOF
}

REPO=""
TASKS_FILE=""
COUNT=10
RUN_DIR=""
PROVIDER="openai-codex"
MODEL="gpt-5.4-mini"
THINKING="low"
DISABLE_EXTENSIONS=1

while [[ $# -gt 0 ]]; do
  case "$1" in
    --repo) REPO="$2"; shift 2 ;;
    --tasks-file) TASKS_FILE="$2"; shift 2 ;;
    --count) COUNT="$2"; shift 2 ;;
    --run-dir) RUN_DIR="$2"; shift 2 ;;
    --provider) PROVIDER="$2"; shift 2 ;;
    --model) MODEL="$2"; shift 2 ;;
    --thinking) THINKING="$2"; shift 2 ;;
    --allow-extensions) DISABLE_EXTENSIONS=0; shift ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown arg: $1" >&2; usage >&2; exit 1 ;;
  esac
done

[[ -n "$REPO" ]] || { echo "--repo required" >&2; exit 1; }
[[ -n "$TASKS_FILE" ]] || { echo "--tasks-file required" >&2; exit 1; }
[[ -d "$REPO" ]] || { echo "repo not found: $REPO" >&2; exit 1; }
[[ -f "$TASKS_FILE" ]] || { echo "tasks file not found: $TASKS_FILE" >&2; exit 1; }
[[ "$COUNT" =~ ^[1-9][0-9]*$ ]] || { echo "--count must be positive integer" >&2; exit 1; }

STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
RUN_DIR="${RUN_DIR:-/home/sebas/runtime/ralph-loops/$STAMP}"
mkdir -p "$RUN_DIR/iterations"
REPO_ABS="$(cd "$REPO" && pwd)"
TASKS_SRC_ABS="$(cd "$(dirname "$TASKS_FILE")" && pwd)/$(basename "$TASKS_FILE")"

cp "$TASKS_SRC_ABS" "$RUN_DIR/TASKS.md"
cat > "$RUN_DIR/STATE.md" <<EOF
# Ralph loop state

Status: running
Iteration: 0/$COUNT
Rule: each agent must read TASKS.md and STATE.md first, then update both before exit.
Rule: communicate only through files in this directory.
Rule: work only in $REPO_ABS.
Rule: do not push or merge.

Current owner: none
Current focus: none
Last result: loop created
EOF

cat > "$RUN_DIR/run-meta.txt" <<EOF
created_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
repo=$REPO_ABS
tasks_source=$TASKS_SRC_ABS
count=$COUNT
provider=$PROVIDER
model=$MODEL
thinking=$THINKING
disable_extensions=$DISABLE_EXTENSIONS
EOF

log() {
  printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" | tee -a "$RUN_DIR/runner.log"
}

pi_args=()
[[ "$DISABLE_EXTENSIONS" -eq 1 ]] && pi_args+=(--no-extensions)
pi_args+=(--provider "$PROVIDER" --model "$MODEL" --thinking "$THINKING")

log "Ralph loop start"
log "Run dir: $RUN_DIR"
log "Repo: $REPO_ABS"
log "Count: $COUNT"

for ((i=1; i<=COUNT; i++)); do
  iter_dir="$RUN_DIR/iterations/iter-$(printf '%03d' "$i")"
  mkdir -p "$iter_dir"
  prompt_file="$iter_dir/prompt.txt"
  output_file="$iter_dir/output.log"
  status_file="$iter_dir/status.txt"

  perl -0pi -e "s/Iteration: .*\/$COUNT/Iteration: $i\/$COUNT/; s/Current owner: .*/Current owner: agent-$i/; s/Current focus: .*/Current focus: iteration $i running/" "$RUN_DIR/STATE.md"

  cat > "$prompt_file" <<EOF
You are iteration $i of $COUNT in a blocking Ralph loop.

Read these files first:
- $RUN_DIR/TASKS.md
- $RUN_DIR/STATE.md

Then do exactly this:
1. Pick the highest-value pending task from TASKS.md.
2. Mark it in_progress in TASKS.md and briefly note it in STATE.md.
3. Implement the work in $REPO_ABS.
4. Run appropriate validation commands for your change.
5. Update TASKS.md with done/pending state changes.
6. Update STATE.md with a concise result, validation outcome, and next suggested task.
7. Communicate only by editing those files.
8. Do not push, merge, or ask the user anything.
9. If blocked, write the blocker clearly in STATE.md and TASKS.md, then stop.

Be decisive. Prefer semantic HTML-first accessibility improvements.
EOF

  log "[$i/$COUNT] step 1: prompt built"
  log "[$i/$COUNT] step 2: launching pi"
  printf 'running\n' > "$status_file"
  date -u +%Y-%m-%dT%H:%M:%SZ > "$iter_dir/started_at.txt"

  set +e
  (
    cd "$REPO_ABS"
    pi "${pi_args[@]}" -p "$(cat "$prompt_file")"
  ) >"$output_file" 2>&1
  exit_code=$?
  set -e

  printf '%s\n' "$exit_code" > "$iter_dir/exit_code.txt"
  date -u +%Y-%m-%dT%H:%M:%SZ > "$iter_dir/finished_at.txt"
  if [[ "$exit_code" -eq 0 ]]; then
    printf 'succeeded\n' > "$status_file"
    log "[$i/$COUNT] step 3: pi finished ok"
  else
    printf 'failed\n' > "$status_file"
    log "[$i/$COUNT] step 3: pi failed with exit $exit_code"
  fi

  log "[$i/$COUNT] step 4: state after iteration"
  tail -n 20 "$RUN_DIR/STATE.md" >> "$RUN_DIR/runner.log" || true
  printf '\n' >> "$RUN_DIR/runner.log"
done

perl -0pi -e "s/Status: running/Status: finished/; s/Current owner: .*/Current owner: none/; s/Current focus: .*/Current focus: loop finished/" "$RUN_DIR/STATE.md"
log "Ralph loop finished"
log "Final state file: $RUN_DIR/STATE.md"
log "Final tasks file: $RUN_DIR/TASKS.md"
printf 'run_dir=%s\n' "$RUN_DIR"
