#!/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
}

out_file="$(mktemp -t flowlog_sigint_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]}"

# An infinite loop query (ISO: repeat/0 + fail/0) gives us time to deliver SIGINT.
# Print and flush a sentinel so we know the query is executing (not still reading input).
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 "sigint_repl_no_start"
fi

kill -INT "$pid"

# The REPL should stay alive, keep the loaded program, and accept more queries.
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 "sigint_repl_missing_true"
fi

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

# Read output until EOF (process exit), with an overall timeout.
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 "sigint_repl_timeout"
fi

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

echo "ok"
