#!/usr/bin/env bash
# test_inject_extraction.sh — Tests the calculateParams body extraction logic in inject.sh.
# Verifies that the brace-depth counter correctly handles simple bodies and bodies
# containing nested if/else blocks.
# Exit: 0 if all tests pass, 1 if any fail.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

PASS=0
FAIL=0

run_extraction() {
  local sol_content="$1"
  python3 - <<PYEOF
import sys

push3 = """$sol_content"""

fn_start = push3.find("function calculateParams")
if fn_start == -1:
    sys.exit("calculateParams not found")
brace_start = push3.find("{", fn_start)
body_start = push3.index("\n", brace_start) + 1

lines = push3[body_start:].split("\n")
body_lines = []
depth = 1
for line in lines:
    depth += line.count("{") - line.count("}")
    if depth <= 0:
        break
    body_lines.append(line)
else:
    sys.exit("error: calculateParams body: closing brace never found (EOF)")

print("\n".join(body_lines))
PYEOF
}

assert_contains() {
  local name="$1"
  local output="$2"
  local expected="$3"
  if echo "$output" | grep -qF "$expected"; then
    echo "  PASS: $name"
    PASS=$((PASS + 1))
  else
    echo "  FAIL: $name"
    echo "    expected to contain: $expected"
    echo "    actual output:"
    echo "$output" | sed 's/^/      /'
    FAIL=$((FAIL + 1))
  fi
}

assert_not_line() {
  # Asserts no line in output matches the given ERE pattern exactly (anchored).
  local name="$1"
  local output="$2"
  local pattern="$3"
  if echo "$output" | grep -qE "^${pattern}$"; then
    echo "  FAIL: $name"
    echo "    expected no line matching: ^${pattern}\$"
    echo "    actual output:"
    echo "$output" | sed 's/^/      /'
    FAIL=$((FAIL + 1))
  else
    echo "  PASS: $name"
    PASS=$((PASS + 1))
  fi
}

# ── Test 1: Simple body (no nested braces) ──────────────────────────────────
echo "Test 1: Simple body (no nested braces)"
SIMPLE_SOL='contract C {
    function calculateParams() public pure returns (uint256 ci) {
        uint256 x = 1;
        ci = x;
    }
}'

OUT=$(run_extraction "$SIMPLE_SOL")
assert_contains     "simple: includes body statement"      "$OUT" "uint256 x = 1;"
assert_contains     "simple: includes assignment"          "$OUT" "ci = x;"
assert_not_line     "simple: excludes function closing }" "$OUT" "    \}"

# ── Test 2: Nested if/else block ─────────────────────────────────────────────
echo "Test 2: Nested if/else block"
NESTED_SOL='contract C {
    function calculateParams() public pure returns (uint256 ci) {
        if (x > 0) {
            ci = 1;
        } else {
            ci = 0;
        }
    }
}'

OUT=$(run_extraction "$NESTED_SOL")
assert_contains     "nested: includes if condition"        "$OUT" "if (x > 0) {"
assert_contains     "nested: includes true branch"        "$OUT" "ci = 1;"
assert_contains     "nested: includes else clause"        "$OUT" "} else {"
assert_contains     "nested: includes false branch"       "$OUT" "ci = 0;"
assert_contains     "nested: includes closing if brace"   "$OUT" "        }"
assert_not_line     "nested: excludes function closing }" "$OUT" "    \}"

# ── Test 3: Multiple levels of nesting ───────────────────────────────────────
echo "Test 3: Multiple nesting levels"
DEEP_SOL='contract C {
    function calculateParams() public pure returns (uint256 ci) {
        if (a) {
            if (b) {
                ci = 2;
            } else {
                ci = 1;
            }
        } else {
            ci = 0;
        }
    }
}'

OUT=$(run_extraction "$DEEP_SOL")
assert_contains "deep: outer if"     "$OUT" "if (a) {"
assert_contains "deep: inner if"     "$OUT" "if (b) {"
assert_contains "deep: inner value"  "$OUT" "ci = 2;"
assert_contains "deep: outer else"   "$OUT" "ci = 0;"

# ── Test 4: EOF without closing brace triggers non-zero exit ─────────────────
echo "Test 4: EOF without closing brace"
BAD_SOL='contract C {
    function calculateParams() public pure returns (uint256 ci) {
        uint256 x = 1;'

if python3 - <<PYEOF 2>/dev/null; then
import sys
push3 = """$BAD_SOL"""
fn_start = push3.find("function calculateParams")
brace_start = push3.find("{", fn_start)
body_start = push3.index("\n", brace_start) + 1
lines = push3[body_start:].split("\n")
body_lines = []
depth = 1
for line in lines:
    depth += line.count("{") - line.count("}")
    if depth <= 0:
        break
    body_lines.append(line)
else:
    sys.exit("error: calculateParams body: closing brace never found (EOF)")
PYEOF
  echo "  FAIL: EOF case should have exited non-zero"
  FAIL=$((FAIL + 1))
else
  echo "  PASS: EOF case exits non-zero"
  PASS=$((PASS + 1))
fi

# ── Test 5: forge build on transpiled optimizer_seed.push3 ───────────────────
echo "Test 5: forge build on transpiled optimizer_seed.push3 (compile regression guard)"

REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
TMPDIR_I5=$(mktemp -d)
trap 'rm -rf "$TMPDIR_I5"' EXIT

if [ ! -d "$SCRIPT_DIR/node_modules" ]; then
  (cd "$SCRIPT_DIR" && npm install --silent)
fi

SOL_OUT="$TMPDIR_I5/OptimizerV3Push3.sol"
TRANSPILE_RC=0
(cd "$SCRIPT_DIR" && npx tsx src/index.ts \
  "$REPO_ROOT/tools/push3-transpiler/optimizer_seed.push3" "$SOL_OUT") \
  >/dev/null 2>&1 || TRANSPILE_RC=$?

if [ "$TRANSPILE_RC" -ne 0 ]; then
  echo "  FAIL: transpiler failed on optimizer_seed.push3"
  FAIL=$((FAIL + 1))
else
  FORGE_BIN="$(command -v forge 2>/dev/null || true)"
  if [ -z "$FORGE_BIN" ] && [ -x /root/.foundry/bin/forge ]; then
    FORGE_BIN=/root/.foundry/bin/forge
  fi

  if [ -z "$FORGE_BIN" ]; then
    echo "  SKIP: forge not found — add foundry bin to PATH to enable compile verification"
  else
    FORGE_DIR="$TMPDIR_I5/forge_verify"
    mkdir -p "$FORGE_DIR/src"
    printf '[profile.default]\nsrc = "src"\nout = "out"\nlibs = []\nvia_ir = true\n' > "$FORGE_DIR/foundry.toml"
    cp "$REPO_ROOT/onchain/src/IOptimizer.sol" "$FORGE_DIR/src/"
    cp "$SOL_OUT" "$FORGE_DIR/src/OptimizerV3Push3.sol"

    FORGE_OUT=""
    FORGE_RC=0
    FORGE_OUT=$(cd "$FORGE_DIR" && "$FORGE_BIN" build 2>&1) || FORGE_RC=$?

    if [ "$FORGE_RC" -eq 0 ]; then
      echo "  PASS: forge build succeeded on transpiled optimizer_seed.push3"
      PASS=$((PASS + 1))
    else
      echo "  FAIL: forge build failed on transpiled optimizer_seed.push3"
      echo "$FORGE_OUT" | sed 's/^/      /'
      FAIL=$((FAIL + 1))
    fi
  fi
fi

# ── Summary ──────────────────────────────────────────────────────────────────
echo ""
echo "Results: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]
