#!/bin/bash
# kssh-tun — управление peer-ами WireGuard-сервера для keenetic_ssh-web tunnel.
# Установлен через tunnel/server-install.sh в /usr/local/bin/kssh-tun.
set -e

ENV_FILE="/etc/wireguard/.kssh-tun.env"
[ -f "$ENV_FILE" ] || { echo "Сервер не инициализирован. Запустите server-install.sh." >&2; exit 1; }
# shellcheck disable=SC1090
. "$ENV_FILE"

PEERS_DIR="$WG_DIR/peers"
CONF="$WG_DIR/$WG_IF.conf"

require_root() {
  if [ "$(id -u)" -ne 0 ]; then echo "Нужны права root (sudo)." >&2; exit 1; fi
}

regen_conf() {
  umask 077
  TMP="$(mktemp)"
  cat > "$TMP" <<EOF
[Interface]
Address = $WG_SERVER_CIDR
ListenPort = $WG_PORT
PrivateKey = $(cat "$WG_DIR/server_private.key")
SaveConfig = false

EOF
  if [ -d "$PEERS_DIR" ]; then
    for f in "$PEERS_DIR"/*.peer; do
      [ -f "$f" ] || continue
      ( . "$f"
        cat <<EOF >> "$TMP"
# peer: $NAME ($CLIENT_IP)
[Peer]
PublicKey = $CLIENT_PUB
AllowedIPs = $CLIENT_IP/32

EOF
      )
    done
  fi
  install -m 600 "$TMP" "$CONF"
  rm -f "$TMP"
  # Самый надёжный способ применить новый конфиг: рестарт wg-quick@WG_IF.
  # `wg syncconf` через process substitution падал молча на части систем.
  if command -v systemctl >/dev/null 2>&1 && \
     systemctl is-enabled "wg-quick@$WG_IF" >/dev/null 2>&1; then
    systemctl restart "wg-quick@$WG_IF" || \
      echo "warning: systemctl restart wg-quick@$WG_IF не удался" >&2
  elif ip link show "$WG_IF" >/dev/null 2>&1; then
    TMP_STRIP="$(mktemp)"
    if wg-quick strip "$WG_IF" > "$TMP_STRIP" 2>/dev/null; then
      wg syncconf "$WG_IF" "$TMP_STRIP" || \
        echo "warning: wg syncconf не удался — перезапустите wg-quick@$WG_IF" >&2
    fi
    rm -f "$TMP_STRIP"
  fi
}

next_ip() {
  USED="$WG_SERVER_IP"
  if [ -d "$PEERS_DIR" ]; then
    for f in "$PEERS_DIR"/*.peer; do
      [ -f "$f" ] || continue
      ip=$(. "$f"; echo "$CLIENT_IP")
      USED="$USED $ip"
    done
  fi
  for i in $(seq 2 254); do
    candidate="${WG_SUBNET_PREFIX}.$i"
    case " $USED " in *" $candidate "*) ;; *) echo "$candidate"; return 0;; esac
  done
  echo "Нет свободного IP в подсети ${WG_SUBNET_PREFIX}.0/24" >&2
  return 1
}

print_env_block() {
  PEER_FILE="$1"
  # shellcheck disable=SC1090
  . "$PEER_FILE"
  SERVER_PUB=$(cat "$WG_DIR/server_public.key")
  PUB_IP="$(curl -s4 -m 3 ifconfig.me 2>/dev/null || hostname -I | awk '{print $1}')"
  echo
  echo "============================================================"
  echo "Peer '$NAME' → $CLIENT_IP. Скопируйте 5 строк ниже на роутер"
  echo "(можно блоком, можно по одной — работает в любом shell):"
  echo
  cat <<EOF
export VPS_ENDPOINT=$PUB_IP:$WG_PORT
export VPS_PUBKEY='$SERVER_PUB'
export CLIENT_IP=$CLIENT_IP
export CLIENT_PRIVKEY='$CLIENT_PRIV'
export DNAT_PORTS='${DNAT_PORTS:-81,79}'
curl -fsSL https://raw.githubusercontent.com/${KSSH_REPO}/${KSSH_BRANCH}/tunnel/tunnel-install.sh | sh
EOF
  echo "============================================================"
}

cmd="${1:-}"
shift || true

case "$cmd" in
  add)
    require_root
    NAME="${1:-}"
    [ -z "$NAME" ] && { echo "usage: kssh-tun add <name>" >&2; exit 1; }
    shift || true
    DNAT_PORTS_ARG=""
    while [ $# -gt 0 ]; do
      case "$1" in
        --dnat)
          DNAT_PORTS_ARG="${2:-}"
          shift 2 || true
          ;;
        --dnat=*)
          DNAT_PORTS_ARG="${1#--dnat=}"
          shift || true
          ;;
        *)
          echo "Неизвестный аргумент: $1" >&2
          echo "usage: kssh-tun add <name> [--dnat 81,79]" >&2
          exit 1
          ;;
      esac
    done
    case "$NAME" in *[!a-zA-Z0-9_-]*) echo "Имя: только [a-zA-Z0-9_-]" >&2; exit 1;; esac
    mkdir -p "$PEERS_DIR"
    PEER_FILE="$PEERS_DIR/$NAME.peer"
    if [ -f "$PEER_FILE" ]; then
      echo "Peer '$NAME' уже существует — повторно вывожу ENV-блок:"
    else
      umask 077
      CLIENT_IP="$(next_ip)"
      CLIENT_PRIV="$(wg genkey)"
      CLIENT_PUB="$(echo "$CLIENT_PRIV" | wg pubkey)"
      cat > "$PEER_FILE" <<EOF
NAME="$NAME"
CLIENT_IP="$CLIENT_IP"
CLIENT_PRIV="$CLIENT_PRIV"
CLIENT_PUB="$CLIENT_PUB"
DNAT_PORTS="$DNAT_PORTS_ARG"
EOF
      chmod 600 "$PEER_FILE"
      regen_conf
      echo "Добавлен: $NAME → $CLIENT_IP"
    fi
    print_env_block "$PEER_FILE"
    ;;
  list)
    if [ ! -d "$PEERS_DIR" ]; then echo "(нет peer-ов)"; exit 0; fi
    printf "%-30s %s\n" "NAME" "IP"
    for f in "$PEERS_DIR"/*.peer; do
      [ -f "$f" ] || continue
      ( . "$f"; printf "%-30s %s\n" "$NAME" "$CLIENT_IP" )
    done
    ;;
  show)
    NAME="${1:-}"
    [ -z "$NAME" ] && { echo "usage: kssh-tun show <name>" >&2; exit 1; }
    PEER_FILE="$PEERS_DIR/$NAME.peer"
    [ -f "$PEER_FILE" ] || { echo "нет peer-а: $NAME" >&2; exit 1; }
    print_env_block "$PEER_FILE"
    ;;
  remove|rm|del)
    require_root
    NAME="${1:-}"
    [ -z "$NAME" ] && { echo "usage: kssh-tun remove <name>" >&2; exit 1; }
    PEER_FILE="$PEERS_DIR/$NAME.peer"
    [ -f "$PEER_FILE" ] || { echo "нет peer-а: $NAME" >&2; exit 1; }
    rm -f "$PEER_FILE"
    regen_conf
    echo "Удалён: $NAME"
    ;;
  _regen)
    require_root
    regen_conf
    ;;
  status)
    if command -v wg >/dev/null 2>&1; then
      wg show "$WG_IF" 2>/dev/null || echo "(wg-интерфейс $WG_IF не поднят)"
    fi
    ;;
  ""|help|-h|--help)
    cat <<EOF
kssh-tun — управление WireGuard-клиентами для keenetic_ssh-web tunnel.

  kssh-tun add <name> [--dnat 81,79]   добавить peer, вывести ENV-блок для роутера
  kssh-tun show <name>      повторно вывести ENV-блок
  kssh-tun list             список peer-ов
  kssh-tun remove <name>    удалить peer
  kssh-tun status           wg show $WG_IF

Конфиг: $WG_DIR/$WG_IF.conf  (регенерируется автоматически)
Peer-файлы: $PEERS_DIR/*.peer
EOF
    ;;
  *)
    echo "Неизвестная команда: $cmd. См. kssh-tun help" >&2
    exit 1
    ;;
esac
