#!/usr/bin/env bash
# Behavioral test for codex_review_gate.sh. Uses local git remotes and stubbed
# commands only; never calls real Codex, GitHub, or the network.
set -uo pipefail

HERE="$(cd "$(dirname "$0")" && pwd)"
GATE="$HERE/../codex_review_gate.sh"
PASS=0
FAIL=0

ok() {
  echo "  OK: $1"
  PASS=$((PASS + 1))
}

no() {
  echo "  FAIL: $1"
  FAIL=$((FAIL + 1))
}

expect_exit() {
  local name="$1"
  local expected="$2"
  local mode="$3"
  local out="$WORK/out-$mode.txt"
  shift 3

  CODEX_STUB_MODE="$mode" HOME="$TEST_HOME" PATH="$BIN:$PATH" bash "$GATE" "$BRANCH" --spec "$SPEC" "$@" >"$out" 2>&1
  local rc=$?
  if [ "$rc" -eq "$expected" ]; then
    ok "$name exits $expected"
  else
    no "$name exited $rc, expected $expected"
    sed -n '1,120p' "$out"
  fi
}

test -f "$GATE" || { echo "FATAL: gate not found at $GATE"; exit 1; }

SBX="$(mktemp -d)"
trap 'rm -rf "$SBX"' EXIT

BIN="$SBX/bin"
ORIGIN="$SBX/origin.git"
WORK="$SBX/work"
TEST_HOME="$SBX/home"
BRANCH="codex/review-gate-test"
SPEC="$WORK/BUILD_SPEC.md"
mkdir -p "$BIN" "$TEST_HOME"

cat > "$BIN/gh" <<'STUB'
#!/usr/bin/env bash
exit 1
STUB

cat > "$BIN/codex" <<'STUB'
#!/usr/bin/env bash
if [ "${1:-}" != "exec" ]; then
  echo "unexpected codex command: $*" >&2
  exit 9
fi
shift
out_file=""
while [ "$#" -gt 0 ]; do
  case "$1" in
    --output-last-message|-o)
      shift
      out_file="${1:-}"
      ;;
  esac
  shift || break
done
[ -n "$out_file" ] || { echo "missing --output-last-message" >&2; exit 9; }
write_review() {
  {
    printf '%s\n' "$@"
  } > "$out_file"
}
echo "codex cli status before final message"
case "${CODEX_STUB_MODE:-approve}" in
  approve)
    write_review "No blocking findings." "VERDICT: APPROVE"
    ;;
  needs)
    write_review "Major: missing required behavior." "VERDICT: NEEDS-FIXES: missing required behavior"
    ;;
  noverdict)
    write_review "Review text without a final verdict."
    ;;
  trailing)
    write_review "No blocking findings." "VERDICT: APPROVE" "additional text after verdict"
    ;;
  malformed)
    write_review "No blocking findings." "VERDICT: APPROVE with extra text"
    ;;
  emptyreason)
    write_review "Major: missing required behavior." "VERDICT: NEEDS-FIXES: "
    ;;
  ambiguous)
    write_review "VERDICT: NEEDS-FIXES: earlier line" "No blocking findings." "VERDICT: APPROVE"
    ;;
  sleep)
    sleep 5
    write_review "VERDICT: APPROVE"
    ;;
  *)
    echo "unknown CODEX_STUB_MODE=${CODEX_STUB_MODE:-}" >&2
    exit 9
    ;;
esac
STUB

cat > "$BIN/timeout" <<'STUB'
#!/usr/bin/env bash
seconds="${1:-}"
shift || exit 125
if [ "${CODEX_STUB_MODE:-}" = "sleep" ]; then
  "$@" &
  pid=$!
  sleep 0.2
  kill "$pid" 2>/dev/null || true
  wait "$pid" 2>/dev/null || true
  exit 124
fi
exec "$@"
STUB

chmod +x "$BIN/gh" "$BIN/codex" "$BIN/timeout"

git init -q --bare "$ORIGIN"
git init -q "$WORK"
git -C "$WORK" config user.email "codex-review-gate@example.invalid"
git -C "$WORK" config user.name "Codex Review Gate Test"
printf 'base\n' > "$WORK/README.md"
cat > "$SPEC" <<'SPEC'
# BUILD_SPEC

Change README.md only.
SPEC
git -C "$WORK" add README.md BUILD_SPEC.md
git -C "$WORK" commit -qm "base"
git -C "$WORK" branch -M main
git -C "$WORK" remote add origin "$ORIGIN"
git -C "$WORK" push -q -u origin main

git -C "$WORK" checkout -q -b "$BRANCH"
printf 'feature\n' >> "$WORK/README.md"
git -C "$WORK" add README.md
git -C "$WORK" commit -qm "feature"
git -C "$WORK" push -q -u origin "$BRANCH"
HEAD_SHA="$(git -C "$WORK" rev-parse HEAD)"
BASE_SHA="$(git -C "$WORK" rev-parse main)"

cd "$WORK" || exit 1

expect_exit "APPROVE verdict" 0 approve
expect_exit "NEEDS-FIXES verdict" 1 needs
expect_exit "missing verdict" 2 noverdict
expect_exit "trailing text after verdict" 2 trailing
expect_exit "malformed final verdict" 2 malformed
expect_exit "empty NEEDS-FIXES reason" 2 emptyreason
expect_exit "multiple verdict lines are ambiguous" 2 ambiguous
expect_exit "expected head oid accepted" 0 approve --expected-head-oid "$HEAD_SHA"
expect_exit "wrong expected head oid refused" 2 approve --expected-head-oid "$BASE_SHA"
expect_exit "timeout fail-closed" 2 sleep

echo "--------"
echo "PASS=$PASS  FAIL=$FAIL"
[ "$FAIL" -eq 0 ]
