#!/usr/bin/env bash
# =============================================================================
# Clew Engine — End-to-End Verification Script
#
# Verifies the full stack: docker-compose up → ingest fixture → search → traverse
#
# Alpha Blocker: Pre-Release Hardening Item #5 (E2E Demo on Real Repo)
#
# Usage:
#   ./scripts/verify_e2e.sh                         # Use defaults
#   ./scripts/verify_e2e.sh --api-url <url>         # Custom API URL
#   ./scripts/verify_e2e.sh --skip-compose          # Skip docker-compose (already running)
#   ./scripts/verify_e2e.sh --skip-ingest           # Skip ingestion (already indexed)
#
# Prerequisites:
#   - Docker and docker-compose installed
#   - Environment variables set (or .env file present)
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# --- Configuration ---
API_URL="${CLEW_API_URL:-http://localhost:8000}"
FIXTURE_REPO_HOST="${PROJECT_ROOT}/tests/fixtures/sample_repo"
FIXTURE_REPO_CONTAINER="/app/repo/tests/fixtures/sample_repo"
FIXTURE_REPO_ID="e2e-fixture"
MAX_WAIT=120  # Max seconds to wait for services
SKIP_COMPOSE=false
SKIP_INGEST=false

# --- Color output ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

pass() { echo -e "${GREEN}[PASS]${NC} $1"; }
fail() { echo -e "${RED}[FAIL]${NC} $1"; FAILURES=$((FAILURES + 1)); }
info() { echo -e "${YELLOW}[INFO]${NC} $1"; }

FAILURES=0
TESTS=0

# --- Parse arguments ---
while [[ $# -gt 0 ]]; do
    case $1 in
        --skip-compose) SKIP_COMPOSE=true; shift ;;
        --skip-ingest) SKIP_INGEST=true; shift ;;
        --api-url) API_URL="$2"; shift 2 ;;
        *) shift ;;
    esac
done

echo "============================================================"
echo "  Clew Engine — End-to-End Verification"
echo "============================================================"
echo ""
info "API URL:       $API_URL"
info "Fixture repo:  $FIXTURE_REPO_HOST"
info "  (in container: $FIXTURE_REPO_CONTAINER)"
echo ""

# --- Step 1: Start services ---
if [ "$SKIP_COMPOSE" = false ]; then
    info "Step 1: Starting services with docker-compose..."
    docker-compose up -d 2>&1 | tail -5
    echo ""
else
    info "Step 1: Skipping docker-compose (--skip-compose flag set)"
fi

# --- Step 2: Wait for services to be healthy ---
info "Step 2: Waiting for API to be ready (max ${MAX_WAIT}s)..."
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
    if curl -sf "${API_URL}/health" > /dev/null 2>&1; then
        pass "API is healthy (${ELAPSED}s)"
        break
    fi
    sleep 2
    ELAPSED=$((ELAPSED + 2))
done

if [ $ELAPSED -ge $MAX_WAIT ]; then
    fail "API did not become healthy within ${MAX_WAIT}s"
    echo ""
    echo "Troubleshooting:"
    echo "  1. Check docker-compose logs: docker-compose logs"
    echo "  2. Verify .env file exists with correct settings"
    echo "  3. Ensure ports 8000, 6335, 6336, 7474, 7687 are available"
    exit 1
fi

# --- Step 3: Health check ---
TESTS=$((TESTS + 1))
info "Step 3: Verifying health endpoint..."
HEALTH=$(curl -sf "${API_URL}/health" 2>/dev/null || echo '{"status":"error"}')
if echo "$HEALTH" | grep -q '"ok"'; then
    pass "Health check returned OK"
    VERSION=$(echo "$HEALTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('version','unknown'))" 2>/dev/null || echo "unknown")
    info "  Version: $VERSION"
else
    fail "Health check failed: $HEALTH"
fi

# --- Step 4: Ingest fixture repo ---
if [ "$SKIP_INGEST" = false ]; then
    TESTS=$((TESTS + 1))
    info "Step 4: Ingesting fixture repo..."
    # Verify fixture exists on host before attempting container ingest
    if [ ! -d "$FIXTURE_REPO_HOST" ]; then
        fail "Fixture repo not found at $FIXTURE_REPO_HOST"
    else
        INGEST_EXIT=0
        # Use 'run --rm' (not 'exec') — the ingestion service is a batch job
        # that exits on startup, so there is no long-lived container to exec into.
        docker-compose run --rm ingestion python -m src.ingest "$FIXTURE_REPO_CONTAINER" "$FIXTURE_REPO_ID" 2>&1 | tail -10 || INGEST_EXIT=$?
        if [ $INGEST_EXIT -eq 0 ]; then
            pass "Fixture repo ingested successfully"
        else
            fail "Fixture repo ingestion failed (exit code: $INGEST_EXIT)"
        fi
    fi
else
    info "Step 4: Skipping ingestion (--skip-ingest flag set)"
fi

# --- Step 5: Search (should work even with empty index) ---
TESTS=$((TESTS + 1))
info "Step 5: Testing search endpoint..."
SEARCH_RESP=$(curl -sf -X POST "${API_URL}/v1/search/" \
    -H "Content-Type: application/json" \
    -d '{"query": "authentication", "limit": 5}' \
    2>/dev/null || echo "ERROR")

if [ "$SEARCH_RESP" = "ERROR" ]; then
    fail "Search endpoint returned an error"
else
    pass "Search endpoint responded successfully"
    RESULT_COUNT=$(echo "$SEARCH_RESP" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
    info "  Results returned: $RESULT_COUNT"
fi

# --- Step 6: Graph traverse ---
TESTS=$((TESTS + 1))
info "Step 6: Testing graph traverse endpoint..."
TRAVERSE_RESP=$(curl -sf -X POST "${API_URL}/v1/graph/traverse" \
    -H "Content-Type: application/json" \
    -d '{"start_node_id": "app.py", "depth": 2}' \
    2>/dev/null || echo "ERROR")

if [ "$TRAVERSE_RESP" = "ERROR" ]; then
    fail "Graph traverse endpoint returned an error"
else
    pass "Graph traverse endpoint responded successfully"
    NODE_COUNT=$(echo "$TRAVERSE_RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('nodes',[])))" 2>/dev/null || echo "0")
    info "  Nodes returned: $NODE_COUNT"
fi

# --- Step 7: Input validation ---
TESTS=$((TESTS + 1))
info "Step 7: Testing input validation..."
VAL_RESP=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${API_URL}/v1/search/" \
    -H "Content-Type: application/json" \
    -d '{"query": "", "limit": 5}' \
    2>/dev/null || echo "000")

if [ "$VAL_RESP" = "422" ]; then
    pass "Empty query correctly rejected (422)"
else
    fail "Empty query returned $VAL_RESP (expected 422)"
fi

# --- Step 8: Relationship type validation ---
TESTS=$((TESTS + 1))
info "Step 8: Testing relationship type allowlist..."
REL_RESP=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${API_URL}/v1/graph/traverse" \
    -H "Content-Type: application/json" \
    -d '{"start_node_id": "test", "relationship_types": ["INHERITS"]}' \
    2>/dev/null || echo "000")

if [ "$REL_RESP" = "422" ]; then
    pass "Invalid relationship type correctly rejected (422)"
else
    fail "Invalid relationship type returned $REL_RESP (expected 422)"
fi

# --- Step 9: Depth bounds validation ---
TESTS=$((TESTS + 1))
info "Step 9: Testing depth bounds validation..."
DEPTH_RESP=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${API_URL}/v1/graph/traverse" \
    -H "Content-Type: application/json" \
    -d '{"start_node_id": "test", "depth": 10}' \
    2>/dev/null || echo "000")

if [ "$DEPTH_RESP" = "422" ]; then
    pass "Depth > 3 correctly rejected (422)"
else
    fail "Depth > 3 returned $DEPTH_RESP (expected 422)"
fi

# --- Summary ---
echo ""
echo "============================================================"
echo "  E2E Verification Summary"
echo "============================================================"
echo ""
PASSED=$((TESTS - FAILURES))
echo "  Tests: $TESTS | Passed: $PASSED | Failed: $FAILURES"
echo ""

if [ $FAILURES -eq 0 ]; then
    echo -e "  ${GREEN}ALL TESTS PASSED${NC}"
    echo ""
    echo "  Next steps:"
    echo "    1. Try a search:   curl -X POST ${API_URL}/v1/search/ -H 'Content-Type: application/json' -d '{\"query\": \"your query\"}'"
    echo "    2. Run quality:    python tests/quality/measure_mrr.py --api-url ${API_URL}"
    echo ""
    exit 0
else
    echo -e "  ${RED}$FAILURES TEST(S) FAILED${NC}"
    echo ""
    echo "  Check docker-compose logs for details:"
    echo "    docker-compose logs --tail=50"
    echo ""
    exit 1
fi
