#!/usr/bin/env bash
# G1P smoke — vectord persistence across restart.
#
# Validates:
#   - Create index + add 50 vectors → Save fires (storaged shows
#     _vectors/persist_demo.json AND _vectors/persist_demo.hnsw)
#   - Search w-001 → recall=1 with distance ≈ 0
#   - Kill vectord → restart → initial Refresh enumerates persisted
#     indexes, Loads each back into the registry
#   - Same search post-restart → still recall=1 (state survived)
#   - DELETE → both files removed from storaged → restart → index gone
#
# Requires storaged + vectord both up.
#
# Usage: ./scripts/g1p_smoke.sh

set -euo pipefail
cd "$(dirname "$0")/.."

export PATH="$PATH:/usr/local/go/bin"

echo "[g1p-smoke] building storaged + vectord + gateway..."
go build -o bin/ ./cmd/storaged ./cmd/vectord ./cmd/gateway

pkill -f "bin/(storaged|vectord|gateway)" 2>/dev/null || true
sleep 0.3

PIDS=()
TMP="$(mktemp -d)"
cleanup() {
  echo "[g1p-smoke] cleanup"
  for p in "${PIDS[@]}"; do [ -n "$p" ] && kill "$p" 2>/dev/null || true; done
  rm -rf "$TMP"
}
trap cleanup EXIT INT TERM

poll_health() {
  local port="$1" deadline=$(($(date +%s) + 5))
  while [ "$(date +%s)" -lt "$deadline" ]; do
    if curl -sS --max-time 1 "http://127.0.0.1:$port/health" >/dev/null 2>&1; then return 0; fi
    sleep 0.05
  done
  return 1
}

NAME="persist_demo"
DIM=8

echo "[g1p-smoke] launching storaged..."
./bin/storaged > /tmp/storaged.log 2>&1 &
PIDS+=($!)
poll_health 3211 || { echo "storaged failed"; tail /tmp/storaged.log; exit 1; }

# Clean any prior persisted state for this index name.
curl -sS -o /dev/null -X DELETE "http://127.0.0.1:3211/storage/delete/_vectors/$NAME.lhv1" || true

launch_vectord() {
  ./bin/vectord > /tmp/vectord.log 2>&1 &
  VECTORD_PID=$!
  PIDS+=($VECTORD_PID)
  poll_health 3215 || { echo "vectord failed"; tail /tmp/vectord.log; return 1; }
}

launch_gateway() {
  ./bin/gateway > /tmp/gateway.log 2>&1 &
  PIDS+=($!)
  poll_health 3110 || { echo "gateway failed"; tail /tmp/gateway.log; return 1; }
}

echo "[g1p-smoke] launching vectord (round 1) → gateway..."
launch_vectord
launch_gateway

FAILED=0

echo "[g1p-smoke] create index + add 50 vectors:"
HTTP="$(curl -sS -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:3110/v1/vectors/index \
  -H 'Content-Type: application/json' \
  -d "{\"name\":\"$NAME\",\"dimension\":$DIM,\"distance\":\"cosine\"}")"
if [ "$HTTP" != "201" ]; then echo "  ✗ create → $HTTP"; FAILED=1; fi

# Build a 50-vector batch.
python3 - <<EOF > "$TMP/batch.json"
import json
items = []
for i in range(50):
    v = [0.0] * $DIM
    v[i % $DIM] = 1.0
    v[(i+1) % $DIM] = (i % 13) * 0.01
    items.append({"id": f"w-{i:03d}", "vector": v, "metadata": {"row": i}})
print(json.dumps({"items": items}))
EOF
LEN="$(curl -sS -X POST "http://127.0.0.1:3110/v1/vectors/index/$NAME/add" \
  -H 'Content-Type: application/json' \
  -d @"$TMP/batch.json" | jq -r '.length')"
if [ "$LEN" = "50" ]; then echo "  ✓ added 50 → length=50"; else echo "  ✗ add → length=$LEN"; FAILED=1; fi

echo "[g1p-smoke] verify storaged has the persistence file:"
FILE_KEY="_vectors/$NAME.lhv1"
FILE_HTTP="$(curl -sS -o /dev/null -w '%{http_code}' "http://127.0.0.1:3211/storage/get/$FILE_KEY")"
if [ "$FILE_HTTP" = "200" ]; then
  echo "  ✓ $FILE_KEY present in storaged"
else
  echo "  ✗ file=$FILE_HTTP"; FAILED=1
fi

echo "[g1p-smoke] search pre-restart:"
python3 - <<EOF > "$TMP/q.json"
import json
i = 1
v = [0.0] * $DIM
v[i % $DIM] = 1.0
v[(i+1) % $DIM] = (i % 13) * 0.01
print(json.dumps({"vector": v, "k": 1}))
EOF
TOP_PRE="$(curl -sS -X POST "http://127.0.0.1:3110/v1/vectors/index/$NAME/search" \
  -H 'Content-Type: application/json' -d @"$TMP/q.json" | jq -r '.results[0].id')"
if [ "$TOP_PRE" = "w-001" ]; then echo "  ✓ pre-restart top hit = w-001"; else echo "  ✗ top=$TOP_PRE"; FAILED=1; fi

echo "[g1p-smoke] kill + restart vectord (rehydrate path):"
kill $VECTORD_PID 2>/dev/null || true
wait $VECTORD_PID 2>/dev/null || true
sleep 0.3
launch_vectord
sleep 0.2  # let initial Refresh complete (no API to query rehydration done)

echo "[g1p-smoke] vectord rehydrated index list shows $NAME:"
NAMES_HTTP="$(curl -sS http://127.0.0.1:3110/v1/vectors/index | jq -r '.names | length')"
if [ "$NAMES_HTTP" = "1" ]; then echo "  ✓ list count=1 after restart"; else echo "  ✗ count=$NAMES_HTTP"; FAILED=1; fi

INFO_LEN="$(curl -sS "http://127.0.0.1:3110/v1/vectors/index/$NAME" | jq -r '.length')"
if [ "$INFO_LEN" = "50" ]; then echo "  ✓ length=50 after restart (state survived)"; else echo "  ✗ length=$INFO_LEN"; FAILED=1; fi

echo "[g1p-smoke] search post-restart:"
TOP_POST="$(curl -sS -X POST "http://127.0.0.1:3110/v1/vectors/index/$NAME/search" \
  -H 'Content-Type: application/json' -d @"$TMP/q.json" | jq -r '.results[0].id')"
DIST_POST="$(curl -sS -X POST "http://127.0.0.1:3110/v1/vectors/index/$NAME/search" \
  -H 'Content-Type: application/json' -d @"$TMP/q.json" | jq -r '.results[0].distance')"
if [ "$TOP_POST" = "w-001" ]; then
  echo "  ✓ post-restart top hit = w-001 (dist=$DIST_POST)"
else
  echo "  ✗ post-restart top=$TOP_POST"; FAILED=1
fi

echo "[g1p-smoke] DELETE then restart → index gone:"
curl -sS -o /dev/null -X DELETE "http://127.0.0.1:3110/v1/vectors/index/$NAME"
FILE_HTTP="$(curl -sS -o /dev/null -w '%{http_code}' "http://127.0.0.1:3211/storage/get/$FILE_KEY")"
if [ "$FILE_HTTP" = "404" ]; then
  echo "  ✓ persistence file removed from storaged"
else
  echo "  ✗ file=$FILE_HTTP after delete"; FAILED=1
fi
kill $VECTORD_PID 2>/dev/null || true
wait $VECTORD_PID 2>/dev/null || true
sleep 0.3
launch_vectord
sleep 0.2
NAMES_HTTP="$(curl -sS http://127.0.0.1:3110/v1/vectors/index | jq -r '.names | length')"
if [ "$NAMES_HTTP" = "0" ]; then echo "  ✓ post-delete restart list count=0"; else echo "  ✗ count=$NAMES_HTTP"; FAILED=1; fi

if [ "$FAILED" -eq 0 ]; then
  echo "[g1p-smoke] G1P acceptance gate: PASSED"
  exit 0
else
  echo "[g1p-smoke] G1P acceptance gate: FAILED"
  exit 1
fi
