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

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
STATE_DIR="${VIBE_DEV_STATE_DIR:-$ROOT/.vibe-dev}"
LOG_DIR="$STATE_DIR/logs"
PID_DIR="$STATE_DIR/pids"

BACKEND_HOST="${VIBE_BACKEND_HOST:-127.0.0.1}"
BACKEND_PORT="${VIBE_BACKEND_PORT:-8899}"
FRONTEND_HOST="${VIBE_FRONTEND_HOST:-127.0.0.1}"
FRONTEND_PORT="${VIBE_FRONTEND_PORT:-5899}"
if [[ -n "${PYTHON:-}" ]]; then
  PYTHON_BIN="$PYTHON"
elif [[ -x "$ROOT/.venv/bin/python" ]]; then
  PYTHON_BIN="$ROOT/.venv/bin/python"
elif [[ -x "$ROOT/agent/.venv/bin/python" ]]; then
  PYTHON_BIN="$ROOT/agent/.venv/bin/python"
else
  PYTHON_BIN="python3"
fi

mkdir -p "$LOG_DIR" "$PID_DIR"

usage() {
  cat <<USAGE
Usage: scripts/dev <command>

Commands:
  up                 Start backend and frontend dev servers
  stop               Stop dev servers started by this script
  restart [service]  Restart backend, frontend, or all services
  status             Show process status and URLs
  logs [service]     Tail logs for backend, frontend, or all
  open               Open the frontend in the default browser
  urls               Print local dev URLs

Environment:
  VIBE_BACKEND_PORT   Backend port (default: 8899)
  VIBE_FRONTEND_PORT  Frontend port (default: 5899)
  PYTHON              Python binary (default: local .venv, then python3)
USAGE
}

pid_file() {
  printf "%s/%s.pid" "$PID_DIR" "$1"
}

log_file() {
  printf "%s/%s.log" "$LOG_DIR" "$1"
}

is_running() {
  local service="$1"
  local file
  file="$(pid_file "$service")"
  [[ -f "$file" ]] && kill -0 "$(cat "$file")" 2>/dev/null
}

start_service() {
  local service="$1"
  shift
  if is_running "$service"; then
    printf "%s already running (pid %s)\n" "$service" "$(cat "$(pid_file "$service")")"
    return
  fi

  printf "starting %s...\n" "$service"
  nohup "$@" >"$(log_file "$service")" 2>&1 </dev/null &
  echo "$!" >"$(pid_file "$service")"
  printf "%s pid %s, log %s\n" "$service" "$(cat "$(pid_file "$service")")" "$(log_file "$service")"
}

stop_service() {
  local service="$1"
  local file
  file="$(pid_file "$service")"
  if ! [[ -f "$file" ]]; then
    printf "%s not started by scripts/dev\n" "$service"
    return
  fi

  local pid
  pid="$(cat "$file")"
  if kill -0 "$pid" 2>/dev/null; then
    printf "stopping %s (pid %s)...\n" "$service" "$pid"
    pkill -TERM -P "$pid" 2>/dev/null || true
    kill "$pid" 2>/dev/null || true
    sleep 0.5
    pkill -KILL -P "$pid" 2>/dev/null || true
    kill -KILL "$pid" 2>/dev/null || true
  fi
  rm -f "$file"
}

url_ok() {
  local url="$1"
  if command -v curl >/dev/null 2>&1; then
    curl -fsS --max-time 2 "$url" >/dev/null 2>&1
  else
    "$PYTHON_BIN" - "$url" >/dev/null 2>&1 <<'PY'
import sys
import urllib.request

urllib.request.urlopen(sys.argv[1], timeout=2).read(1)
PY
  fi
}

wait_for_url() {
  local service="$1"
  local url="$2"
  local attempts="${3:-30}"

  printf "waiting for %s at %s" "$service" "$url"
  for ((i = 1; i <= attempts; i++)); do
    if url_ok "$url"; then
      printf " ready\n"
      return 0
    fi
    if ! is_running "$service"; then
      printf "\n%s exited early; see %s\n" "$service" "$(log_file "$service")" >&2
      return 1
    fi
    printf "."
    sleep 1
  done
  printf "\n%s not ready after %ss; see %s\n" "$service" "$attempts" "$(log_file "$service")" >&2
  return 1
}

cmd_up() {
  start_service backend env PYTHONPATH="$ROOT/agent" "$PYTHON_BIN" "$ROOT/agent/cli.py" serve \
    --host "$BACKEND_HOST" \
    --port "$BACKEND_PORT"
  start_service frontend bash -lc '
    set -euo pipefail
    cd "$1"
    if ! [[ -d node_modules ]]; then
      npm install
    fi
    exec npm run dev -- --host "$2" --port "$3"
  ' bash "$ROOT/frontend" "$FRONTEND_HOST" "$FRONTEND_PORT"
  if ! wait_for_url backend "http://127.0.0.1:$BACKEND_PORT/health" 30 || \
     ! wait_for_url frontend "http://127.0.0.1:$FRONTEND_PORT" 30; then
    cmd_stop
    exit 1
  fi
  cmd_urls
}

cmd_stop() {
  stop_service frontend
  stop_service backend
}

cmd_restart() {
  local service="${1:-all}"
  case "$service" in
    backend)
      stop_service backend
      start_service backend env PYTHONPATH="$ROOT/agent" "$PYTHON_BIN" "$ROOT/agent/cli.py" serve \
        --host "$BACKEND_HOST" \
        --port "$BACKEND_PORT"
      wait_for_url backend "http://127.0.0.1:$BACKEND_PORT/health" 30
      ;;
    frontend)
      stop_service frontend
      start_service frontend bash -lc '
        set -euo pipefail
        cd "$1"
        if ! [[ -d node_modules ]]; then
          npm install
        fi
        exec npm run dev -- --host "$2" --port "$3"
      ' bash "$ROOT/frontend" "$FRONTEND_HOST" "$FRONTEND_PORT"
      wait_for_url frontend "http://127.0.0.1:$FRONTEND_PORT" 30
      ;;
    all)
      cmd_stop
      cmd_up
      ;;
    *)
      printf "unknown service: %s\n" "$service" >&2
      exit 2
      ;;
  esac
}

cmd_status() {
  for service in backend frontend; do
    if is_running "$service"; then
      printf "%-8s running pid=%s log=%s\n" "$service" "$(cat "$(pid_file "$service")")" "$(log_file "$service")"
    else
      printf "%-8s stopped\n" "$service"
    fi
  done
  cmd_urls
}

cmd_logs() {
  local service="${1:-all}"
  case "$service" in
    backend|frontend)
      touch "$(log_file "$service")"
      tail -f "$(log_file "$service")"
      ;;
    all)
      touch "$(log_file backend)" "$(log_file frontend)"
      tail -f "$(log_file backend)" "$(log_file frontend)"
      ;;
    *)
      printf "unknown service: %s\n" "$service" >&2
      exit 2
      ;;
  esac
}

cmd_open() {
  local url="http://127.0.0.1:$FRONTEND_PORT"
  if command -v open >/dev/null 2>&1; then
    open "$url"
  else
    printf "%s\n" "$url"
  fi
}

cmd_urls() {
  cat <<URLS
Frontend: http://127.0.0.1:$FRONTEND_PORT
Backend:  http://127.0.0.1:$BACKEND_PORT
API docs: http://127.0.0.1:$BACKEND_PORT/docs
URLS
}

case "${1:-}" in
  up) cmd_up ;;
  stop) cmd_stop ;;
  restart) shift; cmd_restart "${1:-all}" ;;
  status) cmd_status ;;
  logs) shift; cmd_logs "${1:-all}" ;;
  open) cmd_open ;;
  urls) cmd_urls ;;
  -h|--help|help|"") usage ;;
  *)
    printf "unknown command: %s\n\n" "$1" >&2
    usage >&2
    exit 2
    ;;
esac
