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

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

make -C "$ROOT" -s >/dev/null

BIN="$ROOT/flowlog"

fail() {
  echo "fail: $1" >&2
  exit 1
}

if ! kill -l INFO >/dev/null 2>&1; then
  echo "skip (no SIGINFO)"
  exit 0
fi

out_file="$(mktemp -t flowlog_siginfo_repl.XXXXXX)"
cleanup() {
  rm -f "$out_file"
}
trap cleanup EXIT

coproc "$BIN" --threads 2 2>&1
pid="$COPROC_PID"
infd="${COPROC[1]}"
outfd="${COPROC[0]}"

printf 'write(start), nl, flush_output, repeat, fail.\n' >&"$infd"

seen_start=0
for ((i = 0; i < 200; i++)); do
  if IFS= read -r -t 0.05 -u "$outfd" line 2>/dev/null; then
    line="${line%$'\r'}"
    printf '%s\n' "$line" >>"$out_file"
    if [[ "$line" == "start" ]]; then
      seen_start=1
      break
    fi
  fi
done

if [[ "$seen_start" -ne 1 ]]; then
  kill -KILL "$pid" 2>/dev/null || true
  fail "siginfo_repl_no_start"
fi

kill -INFO "$pid" 2>/dev/null || kill -SIGINFO "$pid" 2>/dev/null || true

seen_info=0
seen_pred=0
timeouts_after_info=0
for ((i = 0; i < 400; i++)); do
  if IFS= read -r -t 0.05 -u "$outfd" line 2>/dev/null; then
    line="${line%$'\r'}"
    printf '%s\n' "$line" >>"$out_file"
    timeouts_after_info=0
    if [[ "$line" == "Flowlog SIGINFO (status)" ]]; then
      seen_info=1
    elif [[ "$line" == "  predicate:"* ]]; then
      seen_pred=1
    fi
    continue
  else
    rc=$?
    if [[ "$rc" -eq 142 ]]; then
      if [[ "$seen_info" -eq 1 ]]; then
        timeouts_after_info=$((timeouts_after_info + 1))
        if [[ "$timeouts_after_info" -ge 5 ]]; then
          break
        fi
      fi
      continue
    fi
    break
  fi
done

if [[ "$seen_info" -ne 1 ]]; then
  kill -KILL "$pid" 2>/dev/null || true
  fail "siginfo_repl_no_status"
fi
if [[ "$seen_pred" -ne 1 ]]; then
  kill -KILL "$pid" 2>/dev/null || true
  fail "siginfo_repl_no_predicate"
fi

# Cancel the running query and ensure the REPL continues to accept input.
kill -INT "$pid"
printf 'true.\n' >&"$infd"

# Wait until the REPL produces output for the next query before closing stdin.
seen_true=0
for ((i = 0; i < 400; i++)); do
  if IFS= read -r -t 0.05 -u "$outfd" line 2>/dev/null; then
    line="${line%$'\r'}"
    printf '%s\n' "$line" >>"$out_file"
    if [[ "$line" == "   true." ]]; then
      seen_true=1
      break
    fi
    continue
  else
    rc=$?
    if [[ "$rc" -eq 142 ]]; then
      continue
    fi
    break
  fi
done

if [[ "$seen_true" -ne 1 ]]; then
  kill -KILL "$pid" 2>/dev/null || true
  echo "--- expected output containing ---" >&2
  echo "   true." >&2
  echo "--- got ---" >&2
  cat "$out_file" >&2
  fail "siginfo_repl_missing_true"
fi

printf 'halt.\n' >&"$infd"
exec {infd}>&-

seen_eof=0
for ((i = 0; i < 400; i++)); do
  if IFS= read -r -t 0.05 -u "$outfd" line 2>/dev/null; then
    line="${line%$'\r'}"
    printf '%s\n' "$line" >>"$out_file"
    continue
  else
    rc=$?
    if [[ "$rc" -eq 142 ]]; then
      continue
    fi
    seen_eof=1
    break
  fi
done

if [[ "$seen_eof" -ne 1 ]]; then
  kill -KILL "$pid" 2>/dev/null || true
  fail "siginfo_repl_timeout"
fi

wait "$pid" 2>/dev/null || true
{ exec {outfd}<&-; } 2>/dev/null || true

echo "ok"
