#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TMP_DIR="$ROOT/.tmp/e2e"
mkdir -p "$TMP_DIR"
PLAYWRIGHT_ARGS=("$@")

GATEWAY_PORT="${JARVIS_E2E_GATEWAY_PORT:-8080}"
DASHBOARD_PORT="${JARVIS_E2E_DASHBOARD_PORT:-5174}"
GATEWAY_PID=""
DASHBOARD_PID=""

cleanup() {
  set +e
  if [[ -n "$DASHBOARD_PID" ]] && kill -0 "$DASHBOARD_PID" 2>/dev/null; then
    kill "$DASHBOARD_PID" 2>/dev/null || true
    wait "$DASHBOARD_PID" 2>/dev/null || true
  fi
  if [[ -n "$GATEWAY_PID" ]] && kill -0 "$GATEWAY_PID" 2>/dev/null; then
    kill "$GATEWAY_PID" 2>/dev/null || true
    wait "$GATEWAY_PID" 2>/dev/null || true
  fi
}
trap cleanup EXIT INT TERM

is_port_free() {
  python3 - "$1" <<'PY'
import socket, sys
port=int(sys.argv[1])
s=socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
    s.bind(('127.0.0.1', port))
except OSError:
    raise SystemExit(1)
finally:
    s.close()
PY
}

free_port() {
  python3 - <<'PY'
import socket
s=socket.socket()
s.bind(('127.0.0.1', 0))
print(s.getsockname()[1])
s.close()
PY
}

choose_port() {
  local label="$1"
  local requested="$2"
  if is_port_free "$requested"; then
    echo "$requested"
  else
    local alt
    alt="$(free_port)"
    echo "WARN: $label port $requested is already in use; using free port $alt. No foreign process was killed." >&2
    echo "$alt"
  fi
}

assert_safe_env() {
  local bad=0
  local names=(VITE_API_BASE_URL JARVIS_API_BASE_URL JARVIS_GATEWAY_URL JARVIS_RUNTIME_PATH FINANCE_DB_PATH HEALTH_DB_PATH ALLOW_EXACT_FINANCE_VALUES ALLOW_HEALTH_DETAIL_LINKS)
  for name in "${names[@]}"; do
    local value="${!name:-}"
    [[ -z "$value" ]] && continue
    if [[ "$name" == "ALLOW_EXACT_FINANCE_VALUES" && "$value" == "1" ]]; then echo "ERROR: $name=1 is forbidden for E2E smoke." >&2; bad=1; fi
    if [[ "$name" == "ALLOW_HEALTH_DETAIL_LINKS" && "$value" == "1" ]]; then echo "ERROR: $name=1 is forbidden for E2E smoke." >&2; bad=1; fi
    if [[ "$value" =~ 100\.[0-9]+\.[0-9]+\.[0-9]+ ]]; then echo "ERROR: $name contains a Tailscale-looking IP." >&2; bad=1; fi
    if [[ "$value" =~ (^|:|=)(/home/agent|/mnt/|/Volumes/|~/.hermes|jarvis_runtime) ]]; then echo "ERROR: $name contains a productive/local runtime path." >&2; bad=1; fi
    if [[ "$value" =~ (internal|prod|production|tailscale|tailnet) ]]; then echo "ERROR: $name contains a private/production-looking hostname marker." >&2; bad=1; fi
  done
  [[ "$bad" == "0" ]]
}

wait_url() {
  local url="$1"
  local label="$2"
  for _ in $(seq 1 80); do
    if python3 - "$url" <<'PY' >/dev/null 2>&1
from urllib.request import urlopen
import sys
with urlopen(sys.argv[1], timeout=1) as r:
    raise SystemExit(0 if 200 <= r.status < 500 else 1)
PY
    then
      echo "OK: $label reachable: $url"
      return 0
    fi
    sleep 0.25
  done
  echo "ERROR: $label did not become reachable: $url" >&2
  return 1
}

assert_safe_env
GATEWAY_PORT="$(choose_port gateway "$GATEWAY_PORT")"
DASHBOARD_PORT="$(choose_port dashboard "$DASHBOARD_PORT")"

echo "INFO: starting mock gateway on 127.0.0.1:$GATEWAY_PORT"
(
  cd "$ROOT/apps/api-gateway"
  JARVIS_DEMO_MODE=1 JARVIS_ENV=development PYTHONPATH=. python3 -m uvicorn jarvis_gateway.main:app --host 127.0.0.1 --port "$GATEWAY_PORT"
) >"$TMP_DIR/gateway.log" 2>&1 &
GATEWAY_PID="$!"

wait_url "http://127.0.0.1:$GATEWAY_PORT/api/healthz" "mock gateway healthz"

echo "INFO: starting dashboard on 127.0.0.1:$DASHBOARD_PORT"
(
  cd "$ROOT/apps/dashboard"
  VITE_API_BASE_URL="http://127.0.0.1:$GATEWAY_PORT" VITE_JARVIS_DEMO_MODE=1 npm run dev -- --host 127.0.0.1 --port "$DASHBOARD_PORT"
) >"$TMP_DIR/dashboard.log" 2>&1 &
DASHBOARD_PID="$!"

wait_url "http://127.0.0.1:$DASHBOARD_PORT/" "dashboard root"

echo "INFO: running Playwright against dashboard=http://127.0.0.1:$DASHBOARD_PORT gateway=http://127.0.0.1:$GATEWAY_PORT"
(
  cd "$ROOT/apps/dashboard"
  PLAYWRIGHT_BASE_URL="http://127.0.0.1:$DASHBOARD_PORT" npx playwright test "${PLAYWRIGHT_ARGS[@]}"
)

echo "PASS: local E2E visual smoke passed"
