#!/usr/bin/env bash
# scripts/e2e-full.sh
#
# Boots the full explorer stack (postgres, elasticsearch, redis, backend
# API, frontend), waits for readiness, runs the Playwright full-stack
# smoke spec against it, and tears everything down. Used by the
# `make e2e-full` target and by the e2e-full CI workflow.
#
# Env vars:
#   E2E_KEEP_STACK=1        # don't tear down on exit (for debugging)
#   E2E_SKIP_DOCKER=1       # assume backend + deps already running
#   EXPLORER_URL            # defaults to http://localhost:3000
#   EXPLORER_API_URL        # defaults to http://localhost:8080
#   E2E_SCREENSHOT_DIR      # defaults to test-results/screenshots
#   JWT_SECRET              # required; generated ephemerally if unset
#   CSP_HEADER              # required; a dev-safe default is injected

set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

COMPOSE="deployment/docker-compose.yml"
COMPOSE_PROJECT="${COMPOSE_PROJECT:-explorer-e2e}"

export EXPLORER_URL="${EXPLORER_URL:-http://localhost:3000}"
export EXPLORER_API_URL="${EXPLORER_API_URL:-http://localhost:8080}"
export E2E_SCREENSHOT_DIR="${E2E_SCREENSHOT_DIR:-$ROOT/test-results/screenshots}"
mkdir -p "$E2E_SCREENSHOT_DIR"

# Generate ephemeral JWT secret if the caller didn't set one. Real
# deployments use fail-fast validation (see PR #3); for a local run we
# want a fresh value each invocation so stale tokens don't bleed across
# runs.
export JWT_SECRET="${JWT_SECRET:-$(openssl rand -hex 32)}"
export CSP_HEADER="${CSP_HEADER:-default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' http://localhost:8080 ws://localhost:8080}"

log() { printf '[e2e-full] %s\n' "$*"; }

teardown() {
  local ec=$?
  if [[ "${E2E_KEEP_STACK:-0}" == "1" ]]; then
    log "E2E_KEEP_STACK=1; leaving stack running."
    return $ec
  fi
  log "tearing down stack"
  if [[ "${E2E_SKIP_DOCKER:-0}" != "1" ]]; then
    docker compose -p "$COMPOSE_PROJECT" -f "$COMPOSE" down -v --remove-orphans >/dev/null 2>&1 || true
  fi
  if [[ -n "${BACKEND_PID:-}" ]]; then kill "$BACKEND_PID" 2>/dev/null || true; fi
  if [[ -n "${FRONTEND_PID:-}" ]]; then kill "$FRONTEND_PID" 2>/dev/null || true; fi
  return $ec
}
trap teardown EXIT

wait_for() {
  local url="$1" label="$2" retries="${3:-60}"
  log "waiting for $label at $url"
  for ((i=0; i<retries; i++)); do
    if curl -fsS "$url" >/dev/null 2>&1; then
      log "  $label ready"
      return 0
    fi
    sleep 2
  done
  log "  $label never became ready"
  return 1
}

if [[ "${E2E_SKIP_DOCKER:-0}" != "1" ]]; then
  log "starting postgres, elasticsearch, redis via docker compose"
  docker compose -p "$COMPOSE_PROJECT" -f "$COMPOSE" up -d postgres elasticsearch redis

  log "waiting for postgres"
  for ((i=0; i<60; i++)); do
    if docker compose -p "$COMPOSE_PROJECT" -f "$COMPOSE" exec -T postgres pg_isready -U explorer >/dev/null 2>&1; then
      break
    fi
    sleep 2
  done
fi

export DB_HOST="${DB_HOST:-localhost}"
export DB_PORT="${DB_PORT:-5432}"
export DB_USER="${DB_USER:-explorer}"
export DB_PASSWORD="${DB_PASSWORD:-changeme}"
export DB_NAME="${DB_NAME:-explorer}"
export REDIS_HOST="${REDIS_HOST:-localhost}"
export REDIS_PORT="${REDIS_PORT:-6379}"
export ELASTICSEARCH_URL="${ELASTICSEARCH_URL:-http://localhost:9200}"

log "running migrations"
(cd backend && go run database/migrations/migrate.go) || {
  log "migrations failed; continuing so tests can report the real backend state"
}

log "starting backend API on :8080"
(cd backend/api/rest && go run . >/tmp/e2e-backend.log 2>&1) &
BACKEND_PID=$!

wait_for "$EXPLORER_API_URL/healthz" backend 120 || {
  log "backend log tail:"; tail -n 60 /tmp/e2e-backend.log || true
  exit 1
}

log "building frontend"
(cd frontend && npm ci --no-audit --no-fund --loglevel=error && npm run build)

log "starting frontend on :3000"
(cd frontend && PORT=3000 HOST=127.0.0.1 NEXT_PUBLIC_API_URL="$EXPLORER_API_URL" npm run start >/tmp/e2e-frontend.log 2>&1) &
FRONTEND_PID=$!

wait_for "$EXPLORER_URL" frontend 60 || {
  log "frontend log tail:"; tail -n 60 /tmp/e2e-frontend.log || true
  exit 1
}

log "running Playwright full-stack smoke"
npx playwright install --with-deps chromium >/dev/null
EXPLORER_URL="$EXPLORER_URL" EXPLORER_API_URL="$EXPLORER_API_URL" \
  npx playwright test scripts/e2e-full-stack.spec.ts --reporter=list

log "done; screenshots in $E2E_SCREENSHOT_DIR"
