#!/usr/bin/env bash
# S04 verification — npm pack tarball install smoke test
# Checks: dist integrity, SF_BUNDLED_EXTENSION_PATHS, prepublishOnly,
#         npm pack dry-run, tarball install, binary exists, launch (no extension
#         errors, "sf" branding), ~/.sf/ untouched, non-TTY warning/no exit 1.

set -uo pipefail

FAIL=0
pass() { echo "  PASS: $1"; }
fail() { echo "  FAIL: $1"; FAIL=1; }

SMOKE_PREFIX=/tmp/sf-smoke-prefix
TARBALL=""

# Capture ~/.sf/agent/sessions/ count before any smoke runs (for Check 9)
PI_SESSIONS_BEFORE=$(ls ~/.sf/agent/sessions/ 2>/dev/null | wc -l | tr -d ' ')

cleanup() {
  rm -rf "$SMOKE_PREFIX"
  if [ -n "$TARBALL" ] && [ -f "$TARBALL" ]; then
    rm -f "$TARBALL"
  fi
}
trap cleanup EXIT

echo "=== S04 Verification ==="
echo ""

# ----------------------------------------------------------------
# Check 1 — dist/loader.js exists and has NODE_PATH block
# ----------------------------------------------------------------
echo "--- Dist integrity ---"
if [ -f "dist/loader.js" ] && grep -q "NODE_PATH" dist/loader.js; then
  pass "1 — dist/loader.js exists and contains NODE_PATH block"
else
  fail "1 — dist/loader.js missing or NODE_PATH block absent"
fi

# ----------------------------------------------------------------
# Check 2 — SF_BUNDLED_EXTENSION_PATHS does NOT reference src/resources
# ----------------------------------------------------------------
# The variable must be present and must use agentDir-based paths only.
paths_line=$(grep "SF_BUNDLED_EXTENSION_PATHS" dist/loader.js | grep -v "src/resources" | head -1)
if [ -n "$paths_line" ]; then
  # Double-check: none of the actual join() lines (not comments) reference src/resources.
  # We look only at lines containing join( to avoid matching comment lines like "NOT src/resources".
  if grep -A 15 "SF_BUNDLED_EXTENSION_PATHS" dist/loader.js | grep "join(" | grep -q "src/resources"; then
    fail "2 — SF_BUNDLED_EXTENSION_PATHS still references src/resources path(s)"
  else
    pass "2 — SF_BUNDLED_EXTENSION_PATHS uses agentDir-based paths (no src/resources)"
  fi
else
  fail "2 — SF_BUNDLED_EXTENSION_PATHS line not found or still references src/resources"
fi

echo ""
echo "--- package.json hooks ---"

# ----------------------------------------------------------------
# Check 3 — prepublishOnly present in package.json
# ----------------------------------------------------------------
if node -e "const p=JSON.parse(require('fs').readFileSync('package.json','utf8')); process.exit(p.scripts?.prepublishOnly ? 0 : 1)" 2>/dev/null; then
  pass "3 — prepublishOnly hook present in package.json"
else
  fail "3 — prepublishOnly hook missing from package.json"
fi

echo ""
echo "--- npm pack dry-run ---"

# ----------------------------------------------------------------
# Check 4 — npm pack --dry-run lists expected files
# ----------------------------------------------------------------
dry_out=$(npm pack --dry-run 2>&1)
file_count=$(echo "$dry_out" | grep -c "npm notice" || true)
has_src=$(echo "$dry_out" | grep -q "src/resources" && echo "yes" || echo "no")
has_dist=$(echo "$dry_out" | grep -q "dist/" && echo "yes" || echo "no")
has_pkg=$(echo "$dry_out" | grep -q "pkg/" && echo "yes" || echo "no")

# Count actual files listed (lines with a path, not summary lines)
file_lines=$(echo "$dry_out" | grep "npm notice" | grep -v "=== Tarball" | grep -v "filename\|package size\|unpacked size\|shasum\|integrity\|total files" | wc -l | tr -d ' ')

if [ "$file_lines" -ge 100 ] && [ "$has_dist" = "yes" ] && [ "$has_pkg" = "yes" ]; then
  # src/resources check — warn but don't fail if absent (it's in "files" array but may not produce 100+ files on its own)
  if [ "$has_src" = "yes" ]; then
    pass "4 — dry-run: ${file_lines} files listed, dist/ present, pkg/ present, src/resources present"
  else
    fail "4 — dry-run: ${file_lines} files listed but src/resources NOT in pack output"
    echo "    (dry-run output tail:)"
    echo "$dry_out" | tail -10 | sed 's/^/    /'
  fi
elif [ "$file_lines" -lt 100 ]; then
  fail "4 — dry-run: only ${file_lines} files listed (expected >=100)"
  echo "$dry_out" | tail -10 | sed 's/^/    /'
else
  fail "4 — dry-run: dist/=${has_dist} pkg/=${has_pkg}"
  echo "$dry_out" | tail -10 | sed 's/^/    /'
fi

echo ""
echo "--- tarball pack ---"

# ----------------------------------------------------------------
# Check 5 — npm pack produces a tarball
# ----------------------------------------------------------------
# Note: prepublishOnly triggers a build here (expected).
npm pack --silent 2>/dev/null || npm pack 2>&1 | tail -5
TARBALL=$(ls glittercowboy-sf-*.tgz 2>/dev/null | head -1 || true)
if [ -n "$TARBALL" ] && [ -f "$TARBALL" ]; then
  pass "5 — tarball produced: $TARBALL"
else
  fail "5 — npm pack did not produce a tarball"
  echo "  Aborting remaining checks — no tarball available."
  echo ""
  echo "=== Results ==="
  echo "One or more checks FAILED."
  exit 1
fi

echo ""
echo "--- tarball install ---"

# ----------------------------------------------------------------
# Check 6 — tarball installs cleanly to temp prefix
# ----------------------------------------------------------------
rm -rf "$SMOKE_PREFIX"
if npm install -g --prefix "$SMOKE_PREFIX" "./$TARBALL" 2>&1 | tail -5; then
  pass "6 — tarball installed to $SMOKE_PREFIX (exit 0)"
else
  fail "6 — tarball install failed"
fi

# ----------------------------------------------------------------
# Check 7 — binary exists at expected path after install
# ----------------------------------------------------------------
if [ -f "$SMOKE_PREFIX/bin/sf" ] || [ -L "$SMOKE_PREFIX/bin/sf" ]; then
  pass "7 — $SMOKE_PREFIX/bin/sf exists after install"
else
  fail "7 — $SMOKE_PREFIX/bin/sf not found after install"
  ls -la "$SMOKE_PREFIX/bin/" 2>/dev/null || echo "    (bin/ dir does not exist)"
fi

echo ""
echo "--- launch smoke ---"

# ----------------------------------------------------------------
# Check 8 — launch: "sf" branding + zero extension load errors
# Use background kill pattern (macOS has no GNU timeout).
# Allow 8s for extensions to load.
# ----------------------------------------------------------------
smoke_out=$(mktemp)
(
  env -i HOME="$HOME" PATH="$PATH" \
    "$SMOKE_PREFIX/bin/sf" < /dev/null > "$smoke_out" 2>&1
) &
smoke_pid=$!
sleep 8
kill "$smoke_pid" 2>/dev/null || true
wait "$smoke_pid" 2>/dev/null || true

ext_errors=$(grep "Extension load error" "$smoke_out" 2>/dev/null | wc -l | tr -d ' ')
# Strip ANSI escape codes for branding check
plain_out=$(sed 's/\x1b\[[0-9;]*m//g' "$smoke_out" 2>/dev/null || cat "$smoke_out")
has_sf=$(echo "$plain_out" | grep -qi "sf\|get shit done" && echo "yes" || echo "no")

if [ "$ext_errors" -eq 0 ]; then
  pass "8a — zero Extension load errors on launch"
else
  fail "8a — ${ext_errors} Extension load error(s) on launch"
  grep "Extension load error" "$smoke_out" | head -5 | sed 's/^/    /'
fi

if [ "$has_sf" = "yes" ]; then
  pass "8b — \"sf\" / \"get shit done\" branding found in launch output"
else
  # Fallback: check if binary self-identifies differently (not "pi")
  has_pi_only=$(echo "$plain_out" | grep -qi "^pi\b" && echo "yes" || echo "no")
  if [ "$has_pi_only" = "no" ]; then
    pass "8b — output does not show \"pi\" branding (sf branding likely in ANSI sequences)"
  else
    fail "8b — output shows \"pi\" branding instead of \"sf\""
    head -5 "$smoke_out" | sed 's/^/    /'
  fi
fi
rm -f "$smoke_out"

echo ""
echo "--- ~/.sf/ isolation ---"

# ----------------------------------------------------------------
# Check 9 — ~/.sf/ session count unchanged before/after smoke run
# PI_SESSIONS_BEFORE captured at script start (before any binary invocation).
# ----------------------------------------------------------------
pi_after=$(ls ~/.sf/agent/sessions/ 2>/dev/null | wc -l | tr -d ' ')
if [ "$PI_SESSIONS_BEFORE" = "$pi_after" ]; then
  pass "9 — ~/.sf/agent/sessions/ count unchanged (${pi_after} sessions before and after)"
else
  fail "9 — ~/.sf/agent/sessions/ count changed: was ${PI_SESSIONS_BEFORE}, now ${pi_after}"
fi

echo ""
echo "--- non-TTY warning path ---"

# ----------------------------------------------------------------
# Check 10 — non-TTY missing optional keys → warning, no exit 1
# Run installed binary with minimal env (HOME + PATH only), piped from /dev/null.
# ----------------------------------------------------------------
tmp10=$(mktemp)
exit10_tmp=$(mktemp)
echo "" > "$exit10_tmp"
(
  env -i HOME="$HOME" PATH="$PATH" \
    "$SMOKE_PREFIX/bin/sf" < /dev/null > "$tmp10" 2>&1
  echo "$?" > "$exit10_tmp"
) &
pid10=$!
sleep 5
kill "$pid10" 2>/dev/null || true
wait "$pid10" 2>/dev/null || true

if grep -qi "warning\|optional" "$tmp10" 2>/dev/null; then
  pass "10a — non-TTY missing optional keys → warning emitted"
else
  fail "10a — non-TTY missing optional keys → no warning found in output"
  echo "    Output (first 5 lines):"
  head -5 "$tmp10" | sed 's/^/    /'
fi

exit10_code=$(cat "$exit10_tmp")
if [ "$exit10_code" = "1" ]; then
  fail "10b — non-TTY missing optional keys → exited with code 1 (should not)"
  echo "    Output: $(head -3 "$tmp10")"
else
  pass "10b — non-TTY missing optional keys → did NOT exit 1 (code: ${exit10_code:-killed})"
fi
rm -f "$tmp10" "$exit10_tmp"

echo ""
echo "=== Results ==="
if [ "$FAIL" -eq 0 ]; then
  echo "All checks passed."
  exit 0
else
  echo "One or more checks FAILED."
  exit 1
fi
