#!/usr/bin/env bash
# Переключение режима выхода в интернет через SSH SOCKS (macOS / Linux).
# См. docs/connectivity/vpn/SSH_EXIT_MODES.md

set -e

SSH_EXIT_MAIN_PORT="${SSH_EXIT_MAIN_PORT:-10809}"
SSH_EXIT_STOP_PORTS="${SSH_EXIT_STOP_PORTS:-10809 1081 1082}"
SSH_EXIT_RU_HOST="${SSH_EXIT_RU_HOST:-hsites-ahau}"
SSH_SSH_STABLE_OPTS="-o TCPKeepAlive=yes -o IPQoS=throughput -o ServerAliveInterval=60 -o ServerAliveCountMax=4"
SSH_SSH_RU_OPTS="-o TCPKeepAlive=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=6"

usage() {
  cat <<EOF
Usage: $(basename "$0") COMMAND

  local | off | stop   Остановить SSH SOCKS на портах: $SSH_EXIT_STOP_PORTS
                       (трафик без SOCKS — ваш локальный публичный IP).

  ru                   SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → выход с RU ($SSH_EXIT_RU_HOST).

  ru-do                SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → Mac → RU → DO → интернет
                       (telegram-socks-via-do). Без RU — ошибка (без прямого Mac→DO).

  status               Кто слушает порты из SSH_EXIT_STOP_PORTS.

  verify               Показать IP без SOCKS и через 127.0.0.1:$SSH_EXIT_MAIN_PORT.

Env:
  SSH_EXIT_MAIN_PORT   Порт SOCKS для ru / ru-do (по умолчанию 10809).
  SSH_EXIT_STOP_PORTS  Порты для команды local (пробелы).
  SSH_EXIT_RU_HOST     Хост только-RU (по умолчанию hsites-ahau).

Требуется ~/.ssh/config: $SSH_EXIT_RU_HOST, telegram-socks-via-do (шаблон — docs/connectivity/PROXY_GUIDE.md).
EOF
}

stop_dynamic_tunnels() {
  local p
  for p in $SSH_EXIT_STOP_PORTS; do
    pkill -f "ssh.*-D ${p} " 2>/dev/null || true
    pkill -f "ssh.*-D ${p}\$" 2>/dev/null || true
  done
  sleep 0.4
  for p in $SSH_EXIT_STOP_PORTS; do
    if command -v lsof >/dev/null 2>&1; then
      # shellcheck disable=SC2046
      lsof -ti ":$p" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
    fi
  done
}

cmd_local() {
  stop_dynamic_tunnels
  echo "SSH SOCKS на портах ($SSH_EXIT_STOP_PORTS) остановлены. Выход в интернет — с локального IP (если в приложениях отключён SOCKS-прокси)."
}

ensure_port_free() {
  if command -v lsof >/dev/null 2>&1; then
    if lsof -i :"$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN -t >/dev/null 2>&1; then
      echo "Порт $SSH_EXIT_MAIN_PORT занят — освобождаю..."
      pkill -f "ssh.*-D ${SSH_EXIT_MAIN_PORT} " 2>/dev/null || true
      sleep 0.4
      # shellcheck disable=SC2046
      lsof -ti ":$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
      sleep 0.3
    fi
  fi
  if lsof -i :"$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN -t >/dev/null 2>&1; then
    echo "Ошибка: порт $SSH_EXIT_MAIN_PORT всё ещё занят. Закройте процесс вручную или: $0 local"
    exit 1
  fi
}

cmd_ru() {
  ensure_port_free
  # shellcheck disable=SC2086
  ssh -D "$SSH_EXIT_MAIN_PORT" -f -N $SSH_SSH_RU_OPTS "$SSH_EXIT_RU_HOST"
  echo "SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → $SSH_EXIT_RU_HOST (выход с IP RU-прокси)."
}

cmd_ru_do() {
  ensure_port_free
  if ! ssh -o BatchMode=yes -o ConnectTimeout=6 -o ConnectionAttempts=1 "$SSH_EXIT_RU_HOST" "exit 0" 2>/dev/null; then
    echo "Ошибка: $SSH_EXIT_RU_HOST недоступен. Режим ru-do только Mac→RU→DO; прямой Mac→DO не используется." >&2
    exit 1
  fi
  # shellcheck disable=SC2086
  ssh -D "$SSH_EXIT_MAIN_PORT" -f -N $SSH_SSH_STABLE_OPTS telegram-socks-via-do
  echo "SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → $SSH_EXIT_RU_HOST → DO (telegram-socks-via-do). Снаружи виден IP DO."
}

cmd_status() {
  local p any=0
  if ! command -v lsof >/dev/null 2>&1; then
    echo "lsof не найден — статус портов недоступен."
    exit 1
  fi
  for p in $SSH_EXIT_STOP_PORTS; do
    if lsof -i :"$p" -sTCP:LISTEN -t >/dev/null 2>&1; then
      echo "--- :$p ---"
      lsof -i :"$p" -sTCP:LISTEN
      any=1
    fi
  done
  if [ "$any" = 0 ]; then
    echo "Ни один из портов не слушает: $SSH_EXIT_STOP_PORTS"
  fi
}

cmd_verify() {
  echo "Без прокси (локальный выход):"
  curl -sS --max-time 12 https://ipinfo.io/ip 2>/dev/null || echo "(ошибка curl)"
  echo ""
  echo "Через SOCKS socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT:"
  curl -sS --max-time 12 -x "socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT" https://ipinfo.io/ip 2>/dev/null || echo "(нет ответа — туннель не поднят или порт другой)"
  echo ""
  echo "Кратко через SOCKS (ip + страна):"
  curl -sS --max-time 12 -x "socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT" https://ipinfo.io/json 2>/dev/null \
    | sed -n 's/.*"ip": *"\([^"]*\)".*/IP: \1/p; s/.*"country": *"\([^"]*\)".*/country: \1/p' 2>/dev/null | head -4 || true
}

case "${1:-}" in
  local|off|stop) cmd_local ;;
  ru)             cmd_ru ;;
  ru-do|ru_do)    cmd_ru_do ;;
  status)         cmd_status ;;
  verify)         cmd_verify ;;
  -h|--help|help) usage ;;
  "")
    usage
    exit 1
    ;;
  *)
    echo "Неизвестная команда: $1"
    usage
    exit 1
    ;;
esac
