#!/bin/env bash
set -Eeuo pipefail

# Цвета для красивого вывода
COLOR_RESET='\033[0m'
COLOR_BLUE='\033[1;34m'
COLOR_GREEN='\033[1;32m'
COLOR_YELLOW='\033[1;33m'
COLOR_RED='\033[1;31m'

# Напоминание об утилите Amphetamine (выполняется до логирования)
clear
printf "${COLOR_YELLOW}===========================================================${COLOR_RESET}\n"
printf "${COLOR_YELLOW}⚠️  ВНИМАНИЕ: Включи Amphetamine на Mac, чтобы сессия не отпала! ⚠️${COLOR_RESET}\n"
printf "${COLOR_YELLOW}===========================================================${COLOR_RESET}\n"
read -r -p "После того как включишь, нажми [Enter] для продолжения..."

EMAIL="skysat331@gmail.com"
SSHD_CONFIG="/etc/ssh/sshd_config"
UFW_DEFAULT="/etc/default/ufw"
UFW_BEFORE="/etc/ufw/before.rules"
LOG_FILE="/var/log/bootstrap-remnawave.log"

SSH_PORT=""
INSTALL_NGINX="no"
BLOCK_IPV6="yes"
NODE_NAME=""

# Конфигурация спидтеста
IPERF_TIMEOUT=15
IPERF_TEST_DURATION=10
PARALLEL_STREAMS=8
INTER_TEST_DELAY=1
DEFAULT_IPERF_PORT_RANGE=(5201 5202 5203 5204 5205 5206 5207 5208 5209)

declare -A SERVERS=(
  ["Москва"]="spd-rudp.hostkey.ru"
  ["Санкт-Петербург"]="st.spb.ertelecom.ru"
  ["Нижний Новгород"]="st.nn.ertelecom.ru"
  ["Челябинск"]="st.chel.ertelecom.ru"
  ["Тюмень"]="st.tmn.ertelecom.ru"
  ["Омск"]="st.omsk.ertelecom.ru"
  ["Новосибирск"]="st.nsk.ertelecom.ru"
  ["Красноярск"]="st.krsk.ertelecom.ru"
  ["Иркутск"]="st.irkutsk.ertelecom.ru"
  ["Уфа"]="st.ufa.ertelecom.ru"
  ["Волгоград"]="st.volgograd.ertelecom.ru"
  ["Якутск"]="yktst.st.mtsws.net"
  ["Владивосток"]="vldvst.st.mtsws.net"
  ["Сахалин"]="sahst.st.mtsws.net"
  ["Норильск"]="norst.st.mtsws.net"
)

declare -A SERVER_FIXED_PORTS=(
  ["Якутск"]="3333"
  ["Владивосток"]="3333"
  ["Сахалин"]="3333"
  ["Норильск"]="3333"
)

declare -A FALLBACK_SERVERS=(
  ["Москва"]="st.tver.ertelecom.ru"
  ["Санкт-Петербург"]="st.yar.ertelecom.ru"
  ["Нижний Новгород"]="speed-nn.vtt.net"
  ["Челябинск"]="st.mgn.ertelecom.ru"
  ["Тюмень"]="st.krsk.ertelecom.ru"
  ["Омск"]="st.nsk.ertelecom.ru"
  ["Новосибирск"]="st.omsk.ertelecom.ru"
  ["Красноярск"]="st.irkutsk.ertelecom.ru"
  ["Иркутск"]="st.krsk.ertelecom.ru"
  ["Уфа"]="st.samara.ertelecom.ru"
  ["Волгоград"]="st.rostov.ertelecom.ru"
)

declare -A FALLBACK_CITIES=(
  ["Москва"]="Тверь"
  ["Санкт-Петербург"]="Ярославль"
  ["Нижний Новгород"]="Нижний Новгород"
  ["Челябинск"]="Магнитогорск"
  ["Тюмень"]="Красноярск"
  ["Омск"]="Новосибирск"
  ["Новосибирск"]="Омск"
  ["Красноярск"]="Иркутск"
  ["Иркутск"]="Красноярск"
  ["Уфа"]="Самара"
  ["Волгоград"]="Ростов-на-Дону"
)

CITY_ORDER=(
  "Москва"
  "Санкт-Петербург"
  "Нижний Новгород"
  "Челябинск"
  "Тюмень"
  "Омск"
  "Новосибирск"
  "Красноярск"
  "Иркутск"
  "Уфа"
  "Волгоград"
  "Якутск"
  "Владивосток"
  "Сахалин"
  "Норильск"
)

RESULTS=()

# Инициализация файла лога
touch "$LOG_FILE"
chmod 600 "$LOG_FILE"

run_step() {
  local step_title="$1"
  local step_cmd="$2"
  
  printf "${COLOR_BLUE}[*] Начало: %s...${COLOR_RESET}\n" "$step_title"
  
  if eval "$step_cmd" >> "$LOG_FILE" 2>&1; then
    printf "${COLOR_GREEN}[OK] Успешно завершено: %s${COLOR_RESET}\n\n" "$step_title"
  else
    printf "${COLOR_RED}[ERR] Ошибка при выполнении: %s (Подробности в %s)${COLOR_RESET}\n\n" "$step_title" "$LOG_FILE"
  fi
}

require_root() {
  [[ "${EUID}" -eq 0 ]] || { echo "Запусти скрипт через sudo/root."; exit 1; }
}

prompt_yes_no() {
  local prompt="$1"
  local answer
  while true; do
    read -r -p "$prompt [y/n]: " answer
    case "${answer,,}" in
      y|yes) return 0 ;;
      n|no) return 1 ;;
      *) echo "Введите y или n" ;;
    esac
  done
}

prompt_ssh_port() {
  local port
  while true; do
    read -r -p "Введите новый SSH порт: " port
    [[ "$port" =~ ^[0-9]+$ ]] || { echo "Порт должен быть числом"; continue; }
    (( port >= 1 && port <= 65535 )) || { echo "Порт должен быть в диапазоне 1-65535"; continue; }
    SSH_PORT="$port"
    return 0
  done
}

prompt_node_name() {
  local name
  while true; do
    read -r -p "Введите имя ноды (для отображения): " name
    [[ -n "${name// }" ]] || { echo "Имя ноды не должно быть пустым"; continue; }
    NODE_NAME="$name"
    return 0
  done
}

collect_inputs() {
  printf "\n${COLOR_BLUE}[*] Сбор входных данных перед настройкой${COLOR_RESET}\n"
  
  if prompt_yes_no "Установить nginx + stream + certbot?"; then
    INSTALL_NGINX="yes"
  else
    INSTALL_NGINX="no"
  fi

  if prompt_yes_no "Блокировать IPv6 в UFW?"; then
    BLOCK_IPV6="yes"
  else
    BLOCK_IPV6="no"
  fi

  prompt_ssh_port
  prompt_node_name
}

# --- ФУНКЦИИ СКОРОСТИ И ПРОВЕРКИ СВЯЗНОСТИ ---

find_available_port() {
  local city="$1"
  local host="$2"
  local port test_result

  if [[ -n "${SERVER_FIXED_PORTS[$city]:-}" ]]; then
    port="${SERVER_FIXED_PORTS[$city]}"
    test_result=$(timeout "$IPERF_TIMEOUT" iperf3 -c "$host" -p "$port" -t 1 2>&1 || true)
    if [[ "$test_result" == *"receiver"* && "$test_result" != *"error"* ]]; then
      echo "$port"
      return 0
    fi
    return 1
  fi

  for port in "${DEFAULT_IPERF_PORT_RANGE[@]}"; do
    test_result=$(timeout "$IPERF_TIMEOUT" iperf3 -c "$host" -p "$port" -t 1 2>&1 || true)
    if [[ "$test_result" == *"receiver"* && "$test_result" != *"error"* ]]; then
      echo "$port"
      return 0
    fi
  done

  return 1
}

test_iperf_server() {
  local host="$1"
  local port="$2"
  local streams="$3"
  local result

  result=$(timeout "$IPERF_TIMEOUT" iperf3 -c "$host" -p "$port" -P "$streams" \
    -t "$IPERF_TEST_DURATION" -J 2>/dev/null || true)

  if [[ -n "$result" && "$result" == *'"receiver"'* ]]; then
    echo "$result"
    return 0
  fi

  return 1
}

parse_speed() {
  local json="$1"
  local direction="$2"

  if [[ "$direction" == "sender" ]]; then
    echo "$json" | jq -r '.end.sum_sent.bits_per_second // 0' \
      | awk '{printf "%.1f", $1/1000000}'
  else
    echo "$json" | jq -r '.end.sum_received.bits_per_second // 0' \
      | awk '{printf "%.1f", $1/1000000}'
  fi
}

get_ping() {
  local host="$1"
  ping -c 5 -W 2 "$host" 2>/dev/null \
    | grep -oP 'rtt min/avg/max/mdev = [0-9.]+/\K[0-9.]+' || echo "N/A"
}

process_result() {
  local json="$1"
  local city="$2"
  local host="$3"
  local is_fallback="${4:-false}"

  local down up ping display_city marker
  down=$(parse_speed "$json" "receiver")
  up=$(parse_speed "$json" "sender")
  ping=$(get_ping "$host")

  display_city="$city"
  [[ "$is_fallback" == "true" ]] && display_city="${city} (F)"

  marker=""
  if [[ "$down" == "0.0" && "$up" == "0.0" ]]; then
    marker=" ⚠️"
  fi

  RESULTS+=("🔗 ${display_city}:${marker}")
  RESULTS+=("⬇️ ${down} ⬆️ ${up} ↔️ ${ping}")
  return 0
}

process_empty_result() {
  local city="$1"
  RESULTS+=("🔗 ${city}: ⚠️")
  RESULTS+=("⬇️ 0.0 ⬆️ 0.0 ↔️ N/A")
}

test_server() {
  local city="$1"
  local host="$2"
  local fallback_host="${3:-}"
  local fallback_city="${FALLBACK_CITIES[$city]:-}"
  local port result

  if port=$(find_available_port "$city" "$host"); then
    if result=$(test_iperf_server "$host" "$port" "$PARALLEL_STREAMS"); then
      process_result "$result" "$city" "$host" "false"
      return 0
    fi
  fi

  if [[ -n "$fallback_host" ]]; then
    if port=$(find_available_port "$city" "$fallback_host"); then
      if result=$(test_iperf_server "$fallback_host" "$port" "$PARALLEL_STREAMS"); then
        process_result "$result" "$fallback_city" "$fallback_host" "true"
        return 0
      fi
    fi
  fi

  process_empty_result "$city"
  return 1
}

run_speedtests() {
  printf "\n${COLOR_YELLOW}[*] Запуск проверки доступности и скорости локаций в РФ...${COLOR_RESET}\n"
  RESULTS=()

  for city in "${CITY_ORDER[@]}"; do
    local server="${SERVERS[$city]}"
    local fallback="${FALLBACK_SERVERS[$city]:-}"
    printf "Тестирование локации: %-20s ... " "$city"
    test_server "$city" "$server" "$fallback" || true
    printf "${COLOR_GREEN}Готово${COLOR_RESET}\n"
    sleep "$INTER_TEST_DELAY"
  done

  printf "\n${COLOR_BLUE}=== РЕЗУЛЬТАТЫ ПРОВЕРКИ СВЯЗНОСТИ С РФ ===${COLOR_RESET}\n"
  printf '%s\n' "${RESULTS[@]}"
  printf "${COLOR_BLUE}==========================================${COLOR_RESET}\n\n"

  printf "${COLOR_YELLOW}⚠️ Проанализируй данные выше. Если VPS не заблокирована ТСПУ и скорость в норме:${COLOR_RESET}\n"
  read -r -p "Нажми [Enter] для продолжения полной настройки ноды: ${NODE_NAME}..."
  clear
}

# --- ОСНОВНЫЕ СТАДИИ НАСТРОЙКИ VPS ---

setup_ssh_keys() {
  mkdir -p /root/.ssh
  cat << 'EOF' >> /root/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGsFDV3aA1Z9OmsoPIYQdqVYrsrAZmenGY+vmnkr8S+A dm-masterov@MacBook-Air-Dmitrij.local
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICn5i9oABfYbU+fIbuT5PpWiEJusxB5mAygmb1WY0OYI root@fenix.rmpanel
EOF
  sort -u /root/.ssh/authorized_keys -o /root/.ssh/authorized_keys
  chmod 700 /root/.ssh
  chmod 600 /root/.ssh/authorized_keys
}

apt_update_upgrade() {
  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
}

install_base_utils() {
  DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \
    vim nano curl wget htop unzip gnupg ufw lsb-release ca-certificates \
    apt-transport-https software-properties-common python3 jq iperf3
  
  if systemctl list-unit-files | grep -q '^iperf3\.service'; then
    systemctl disable --now iperf3 || true
  fi
}

enable_bbr() {
  sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf
  sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf
  echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
  echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
  sysctl -p
}

install_docker_official() {
  apt-get remove -y docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc || true
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
  chmod a+r /etc/apt/keyrings/docker.asc

  cat >/etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl enable --now docker
}

install_nginx_optional() {
  if [[ "$INSTALL_NGINX" == "yes" ]]; then
    DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" nginx libnginx-mod-stream certbot python3-certbot-nginx
    certbot register --non-interactive --agree-tos --email "$EMAIL" || true
    systemctl enable --now nginx
    
    (crontab -l 2>/dev/null | grep -v '^#' | grep -v 'acme.sh' | grep -v 'certbot'; echo "00 0 * * 5 /root/.acme.sh/acme.sh --cron --home /root/.acme.sh && systemctl reload nginx") | crontab -
  else
    echo "Установка Nginx пропущена пользователем."
  fi
}

install_netbird() {
  curl -fsSL https://pkgs.netbird.io/install.sh | sh
  netbird up --setup-key DDC0A341-CA31-4318-87FC-0326913996C0
}

backup_file() {
  local file="$1"
  [[ -f "$file" ]] || return 0
  cp -a "$file" "${file}.bak.$(date +%F-%H%M%S)"
}

configure_ufw_ipv6() {
  backup_file "$UFW_DEFAULT"
  if [[ "$BLOCK_IPV6" == "yes" ]]; then
    sed -i 's/^IPV6=.*/IPV6=no/' "$UFW_DEFAULT"
  else
    if grep -q '^IPV6=' "$UFW_DEFAULT"; then
      sed -i 's/^IPV6=.*/IPV6=yes/' "$UFW_DEFAULT"
    else
      echo 'IPV6=yes' >> "$UFW_DEFAULT"
    fi
  fi
}

configure_ssh() {
  backup_file "$SSHD_CONFIG"
  mkdir -p /run/sshd && chmod 755 /run/sshd

  for param in "Port ${SSH_PORT}" "PasswordAuthentication no" "PubkeyAuthentication yes" "KbdInteractiveAuthentication no"; do
    local key="${param%% *}"
    local val="${param#* }"
    if grep -qE "^[#[:space:]]*${key}[[:space:]]+" "$SSHD_CONFIG"; then
      sed -i "s/^[#[:space:]]*${key}[[:space:]].*/${key} ${val}/" "$SSHD_CONFIG"
    else
      echo "${param}" >> "$SSHD_CONFIG"
    fi
  done

  sshd -t
  systemctl daemon-reload || true
  systemctl restart ssh || true
  systemctl restart ssh.socket || true
}

configure_ufw_rules() {
  ufw --force reset
  ufw default deny incoming
  ufw default allow outgoing
  ufw allow "${SSH_PORT}/tcp"
  ufw limit "${SSH_PORT}/tcp"

  if [[ "$INSTALL_NGINX" == "yes" ]]; then
    ufw allow 80/tcp
    ufw allow 443/tcp
  fi
}

configure_ufw_icmp() {
  if [[ "$BLOCK_IPV6" != "yes" ]]; then return 0; fi
  backup_file "$UFW_BEFORE"

  python3 - <<'PY'
from pathlib import Path
path = Path("/etc/ufw/before.rules")
text = path.read_text()
icmp_block = """# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
-A ufw-before-input -p icmp --icmp-type source-quench -j DROP

# ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-forward -p icmp --icmp-type echo-request -j DROP"""

lines = text.splitlines()
out, i, replaced = [], 0, False
while i < len(lines):
  line = lines[i]
  if line.strip() == "# ok icmp codes for INPUT" and not replaced:
    out.extend(icmp_block.splitlines())
    replaced = True
    i += 1
    while i < len(lines):
      l = lines[i].strip()
      if l.startswith("-A ufw-before-input -p icmp") or l.startswith("-A ufw-before-forward -p icmp") or l == "# ok icmp code for FORWARD" or l == "":
        i += 1
        continue
      break
    continue
  out.append(line)
  i += 1
if not replaced:
  out.append("")
  out.extend(icmp_block.splitlines())
path.write_text("\n".join(out) + "\n")
PY
}

enable_ufw() {
  ufw disable || true
  ufw --force enable
}

install_trafficguard() {
  local MANAGER_PATH="/opt/trafficguard-manager.sh"
  local LINK_PATH="/usr/local/bin/rknpidor"
  
  cat > "$MANAGER_PATH" << 'EOF'
#!/bin/bash
set -u
RED='\033;31m'; GREEN='\033;32m'; YELLOW='\033[1;33m'; BLUE='\033;34m'; CYAN='\033;36m'; NC='\033[0m'
TG_URL="https://raw.githubusercontent.com/dotX12/traffic-guard/master/install.sh"
LIST_GOV="https://raw.githubusercontent.com/shadow-netlab/traffic-guard-lists/refs/heads/main/public/government_networks.list"
LIST_SCAN="https://raw.githubusercontent.com/shadow-netlab/traffic-guard-lists/refs/heads/main/public/antiscanner.list"
LIST_SKIPA="https://raw.githubusercontent.com/shadow-netlab/traffic-guard-lists/refs/heads/main/public/skipa.list"

if [[ $EUID -ne 0 ]]; then exit 1; fi

install_process() {
    DEBIAN_FRONTEND=noninteractive apt-get update -qq
    DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" curl wget rsyslog ipset ufw grep sed coreutils whois
    systemctl enable --now rsyslog
    curl -fsSL "$TG_URL" | bash
    traffic-guard full -u "$LIST_GOV" -u "$LIST_SCAN" -u "$LIST_SKIPA" --enable-logging
    systemctl restart rsyslog
}
case "${1:-}" in
    install) install_process ;;
    *) exit 0 ;;
esac
EOF

  chmod +x "$MANAGER_PATH"
  ln -sf "$MANAGER_PATH" "$LINK_PATH"
  
  "$MANAGER_PATH" install

  local L_GOV="https://raw.githubusercontent.com/shadow-netlab/traffic-guard-lists/refs/heads/main/public/government_networks.list"
  local L_SCAN="https://raw.githubusercontent.com/shadow-netlab/traffic-guard-lists/refs/heads/main/public/antiscanner.list"

  if [ -f /usr/local/bin/traffic-guard ] && /usr/local/bin/traffic-guard --help >/dev/null 2>&1; then
    /usr/local/bin/traffic-guard full -u "$L_GOV" -u "$L_SCAN" --enable-logging
  else
    echo "⚠️ Предупреждение: traffic-guard не установлен или поврежден на этой ноде. Пропускаем."
    return 1
  fi
}

upgrade_kernel_and_reboot() {
  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" linux-generic-hwe-24.04
  apt-get remove -y linux-image-generic || true
  apt-get autoremove -y --purge
  
  printf "${COLOR_YELLOW}[*] Сервер уходит на финальную перезагрузку через 5 секунд...${COLOR_RESET}\n"
  sleep 5
  reboot
}

main() {
  require_root
  collect_inputs
  
  # ПРЕДВЕРИТЕЛЬНЫЙ ШАГ: Ставим только то, что нужно для теста скорости прямо сейчас
  printf "\n${COLOR_BLUE}[*] Шаг 0: Быстрое обновление и установка утилит диагностики...${COLOR_RESET}\n"
  run_step "Первичное обновление репозиториев и установка jq/iperf3" "apt_update_upgrade && install_base_utils"

  # Запуск спидтеста и блокирующая пауза
  run_speedtests

  # Если нажали Enter — продолжаем штатную полную установку
  run_step "Автоматическое добавление SSH ключей" "setup_ssh_keys"
  run_step "Включение алгоритма оптимизации сети TCP BBR" "enable_bbr"
  run_step "Установка Docker и его компонентов" "install_docker_official"
  run_step "Установка и настройка Nginx (опционально)" "install_nginx_optional"
  run_step "Установка и авторизация Netbird VPN" "install_netbird"
  run_step "Конфигурация IPv6 в правилах UFW" "configure_ufw_ipv6"
  run_step "Перенос SSH на новый порт и отключение паролей" "configure_ssh"
  run_step "Применение базовых правил фаервола UFW" "configure_ufw_rules"
  run_step "Корректировка ICMP блоков в фаерволе" "configure_ufw_icmp"
  run_step "Активация фаервола UFW" "enable_ufw"
  run_step "Установка и валидация баз TrafficGuard PRO" "install_trafficguard"
  run_step "Обновление ядра Linux до HWE и инициализация перезагрузки" "upgrade_kernel_and_reboot"
}

main "$@"
