#!/bin/bash
# ═══════════════════════════════════════════════════════════
#  VPN Server Quick Deploy — VLESS + Reality
#  Устанавливает 3x-ui, создаёт пользователя, выводит конфиг
#
#  Использование:
#    bash deploy-vpn.sh                              # на сервере
#    ssh root@IP 'bash -s' < deploy-vpn.sh           # удалённо
#    ssh user@IP 'sudo bash -s' < deploy-vpn.sh      # через sudo
#
#  Опции:
#    --name NAME    Имя клиента (по умолчанию: client1)
#    --port PORT    Порт для VPN (по умолчанию: случайный)
# ═══════════════════════════════════════════════════════════
set -euo pipefail

# ── Цвета ──
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

# ── Параметры командной строки ──
CLIENT_NAME="client1"
CUSTOM_PORT=""

while [[ $# -gt 0 ]]; do
    case $1 in
        --name) CLIENT_NAME="$2"; shift 2 ;;
        --port) CUSTOM_PORT="$2"; shift 2 ;;
        *) echo "Неизвестный параметр: $1"; exit 1 ;;
    esac
done

# ── Проверки ──
if [[ $EUID -ne 0 ]]; then
    echo -e "${RED}Запустите от root: sudo bash deploy-vpn.sh${NC}"
    exit 1
fi

# ── Генерация случайных значений ──
rand_port() { shuf -i 10000-59999 -n 1; }
rand_hex() { openssl rand -hex "$1"; }

PANEL_PORT=$(rand_port)
INBOUND_PORT=${CUSTOM_PORT:-$(rand_port)}
while [[ "$INBOUND_PORT" == "$PANEL_PORT" ]]; do
    INBOUND_PORT=$(rand_port)
done

WEB_BASE_PATH="/$(rand_hex 10)/"
ADMIN_USER="admin"
ADMIN_PASS=$(rand_hex 8)

# ── Определение IP ──
SERVER_IP=$(curl -s4 --max-time 5 ifconfig.me 2>/dev/null \
    || curl -s4 --max-time 5 ip.sb 2>/dev/null \
    || curl -s4 --max-time 5 ipinfo.io/ip 2>/dev/null \
    || echo "UNKNOWN")

if [[ "$SERVER_IP" == "UNKNOWN" ]]; then
    echo -e "${RED}Не удалось определить внешний IP${NC}"
    exit 1
fi

SNI_DOMAIN="www.amd.com"
TARGET_DEST="www.amd.com:443"

echo -e "${CYAN}╔═══════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║   VPN Quick Deploy — VLESS + Reality      ║${NC}"
echo -e "${CYAN}╠═══════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║  Сервер:  ${GREEN}${SERVER_IP}${NC}"
echo -e "${CYAN}║  Клиент:  ${GREEN}${CLIENT_NAME}${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════╝${NC}"

# ═══════════════════════════════════════════
# Шаг 1: Система + BBR
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[1/6]${NC} Настройка системы..."

export DEBIAN_FRONTEND=noninteractive
apt-get update -qq > /dev/null 2>&1
apt-get install -y -qq curl wget sqlite3 > /dev/null 2>&1

# BBR
if ! sysctl net.ipv4.tcp_congestion_control 2>/dev/null | grep -q bbr; then
    cat >> /etc/sysctl.conf << 'SYSCTL'
# VPN Optimization
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mtu_probing = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
SYSCTL
    sysctl -p > /dev/null 2>&1
    echo -e "  BBR ${GREEN}включён${NC}"
else
    echo -e "  BBR ${GREEN}уже активен${NC}"
fi

# ═══════════════════════════════════════════
# Шаг 2: Открытие портов (все способы)
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[2/6]${NC} Открытие портов ${BOLD}${PANEL_PORT}${NC} и ${BOLD}${INBOUND_PORT}${NC}..."

open_ports() {
    local ports=("$@")
    local opened=false

    # --- UFW ---
    if command -v ufw &>/dev/null; then
        # Включить если не активен
        if ! ufw status 2>/dev/null | grep -q "active"; then
            ufw --force enable > /dev/null 2>&1 || true
            ufw default allow outgoing > /dev/null 2>&1
            ufw default deny incoming > /dev/null 2>&1
            ufw allow ssh > /dev/null 2>&1
        fi
        for p in "${ports[@]}"; do
            ufw allow "$p"/tcp > /dev/null 2>&1
        done
        ufw reload > /dev/null 2>&1 || true
        echo -e "  ufw: порты ${GREEN}открыты${NC}"
        opened=true
    fi

    # --- firewalld ---
    if command -v firewall-cmd &>/dev/null && systemctl is-active --quiet firewalld 2>/dev/null; then
        for p in "${ports[@]}"; do
            firewall-cmd --permanent --add-port="$p"/tcp > /dev/null 2>&1
        done
        firewall-cmd --reload > /dev/null 2>&1
        echo -e "  firewalld: порты ${GREEN}открыты${NC}"
        opened=true
    fi

    # --- iptables (fallback) ---
    if command -v iptables &>/dev/null; then
        for p in "${ports[@]}"; do
            # Проверяем, нет ли уже правила
            if ! iptables -C INPUT -p tcp --dport "$p" -j ACCEPT 2>/dev/null; then
                iptables -I INPUT -p tcp --dport "$p" -j ACCEPT 2>/dev/null || true
            fi
        done
        # Сохраняем правила если есть инструмент
        if command -v netfilter-persistent &>/dev/null; then
            netfilter-persistent save > /dev/null 2>&1 || true
        elif command -v iptables-save &>/dev/null; then
            iptables-save > /etc/iptables.rules 2>/dev/null || true
        fi
        if [[ "$opened" == false ]]; then
            echo -e "  iptables: порты ${GREEN}открыты${NC}"
        fi
    fi
}

open_ports "$PANEL_PORT" "$INBOUND_PORT"

# ═══════════════════════════════════════════
# Шаг 3: Установка 3x-ui
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[3/6]${NC} Установка 3x-ui..."

if [[ -f /usr/local/x-ui/x-ui ]]; then
    echo -e "  3x-ui ${GREEN}уже установлен${NC}, пропускаю"
else
    INSTALL_SCRIPT=$(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh)
    printf 'y\n\n\n\n\n\n\n\n\n\n' | timeout 180 bash -c "$INSTALL_SCRIPT" > /tmp/x-ui-install.log 2>&1 || true

    if [[ -f /usr/local/x-ui/x-ui ]]; then
        echo -e "  3x-ui ${GREEN}установлен${NC}"
    else
        echo -e "  ${RED}Ошибка установки!${NC} Лог: /tmp/x-ui-install.log"
        exit 1
    fi
fi

# Убедиться что сервис запущен (нужен для CLI-команд)
systemctl start x-ui 2>/dev/null || true
sleep 3

# ═══════════════════════════════════════════
# Шаг 4: Конфигурация панели через CLI
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[4/6]${NC} Конфигурация панели..."

# CLI x-ui setting — надёжнее чем прямая запись в SQLite
/usr/local/x-ui/x-ui setting -port "$PANEL_PORT" > /dev/null 2>&1
/usr/local/x-ui/x-ui setting -webBasePath "$WEB_BASE_PATH" > /dev/null 2>&1
/usr/local/x-ui/x-ui setting -username "$ADMIN_USER" -password "$ADMIN_PASS" > /dev/null 2>&1

echo -e "  Панель: порт ${GREEN}${PANEL_PORT}${NC}, путь ${GREEN}${WEB_BASE_PATH}${NC}"

# ═══════════════════════════════════════════
# Шаг 5: Генерация ключей + создание inbound
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[5/6]${NC} Создание VLESS Reality..."

XRAY_BIN="/usr/local/x-ui/bin/xray-linux-amd64"
if [[ ! -f "$XRAY_BIN" ]]; then
    XRAY_BIN=$(find /usr/local/x-ui/bin/ -name "xray-linux-*" -type f | head -1)
fi

# Reality keypair: строка 1 = PrivateKey, строка 2 = PublicKey (Password в новых версиях)
REALITY_OUTPUT=$("$XRAY_BIN" x25519 2>/dev/null)
PRIVATE_KEY=$(echo "$REALITY_OUTPUT" | sed -n '1s/.*: *//p')
PUBLIC_KEY=$(echo "$REALITY_OUTPUT" | sed -n '2s/.*: *//p')

if [[ -z "$PRIVATE_KEY" || -z "$PUBLIC_KEY" || ${#PRIVATE_KEY} -lt 30 || ${#PUBLIC_KEY} -lt 30 ]]; then
    echo -e "  ${RED}Ошибка генерации ключей Reality${NC}"
    echo "$REALITY_OUTPUT"
    exit 1
fi

CLIENT_UUID=$("$XRAY_BIN" uuid 2>/dev/null || cat /proc/sys/kernel/random/uuid)

SID1=$(rand_hex 2); SID2=$(rand_hex 1); SID3=$(rand_hex 3); SID4=$(rand_hex 4)
SID5=$(rand_hex 5); SID6=$(rand_hex 7); SID7=$(rand_hex 6); SID8=$(rand_hex 8)

CLIENT_EMAIL=$(rand_hex 4)
CLIENT_SUB=$(rand_hex 8)
NOW_MS=$(date +%s)000

# Записываем inbound в БД (для inbound CLI не подходит — только SQLite)
DB_PATH="/etc/x-ui/x-ui.db"

sqlite3 "$DB_PATH" "DELETE FROM inbounds;"

SETTINGS="{\"clients\":[{\"id\":\"${CLIENT_UUID}\",\"email\":\"${CLIENT_EMAIL}\",\"enable\":true,\"flow\":\"\",\"comment\":\"${CLIENT_NAME}\",\"expiryTime\":0,\"limitIp\":0,\"totalGB\":0,\"reset\":0,\"subId\":\"${CLIENT_SUB}\",\"tgId\":\"\",\"created_at\":${NOW_MS},\"updated_at\":${NOW_MS}}],\"decryption\":\"none\",\"encryption\":\"none\"}"

STREAM="{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"target\":\"${TARGET_DEST}\",\"serverNames\":[\"${SNI_DOMAIN}\",\"amd.com\"],\"privateKey\":\"${PRIVATE_KEY}\",\"minClientVer\":\"\",\"maxClientVer\":\"\",\"maxTimediff\":0,\"shortIds\":[\"${SID1}\",\"${SID2}\",\"${SID3}\",\"${SID4}\",\"${SID5}\",\"${SID6}\",\"${SID7}\",\"${SID8}\"],\"settings\":{\"publicKey\":\"${PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"http\",\"request\":{\"version\":\"1.1\",\"method\":\"GET\",\"path\":[\"/\"],\"headers\":{}},\"response\":{\"version\":\"1.1\",\"status\":\"200\",\"reason\":\"OK\",\"headers\":{}}}},\"sockopt\":{\"tcpFastOpen\":true,\"tcpMptcp\":true,\"domainStrategy\":\"UseIP\",\"tcpMaxSeg\":1440,\"tcpKeepAliveInterval\":25,\"tcpKeepAliveIdle\":300,\"tcpUserTimeout\":10000,\"tcpcongestion\":\"bbr\",\"tcpWindowClamp\":600}}"

SNIFFING="{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}"

sqlite3 "$DB_PATH" "INSERT INTO inbounds (user_id, up, down, total, remark, enable, expiry_time, listen, port, protocol, settings, stream_settings, tag, sniffing) VALUES (1, 0, 0, 0, 'VLESS-Reality', 1, 0, '', ${INBOUND_PORT}, 'vless', '${SETTINGS}', '${STREAM}', 'inbound-${INBOUND_PORT}', '${SNIFFING}');"

echo -e "  VLESS Reality на порту ${GREEN}${INBOUND_PORT}${NC} ${GREEN}✓${NC}"

# Перезапуск чтобы применить ВСЕ изменения (и CLI, и SQLite)
systemctl restart x-ui
sleep 3

if systemctl is-active --quiet x-ui; then
    echo -e "  Сервис ${GREEN}запущен${NC}"
else
    echo -e "  ${RED}Ошибка запуска!${NC} Проверьте: journalctl -u x-ui -n 50"
    exit 1
fi

# ═══════════════════════════════════════════
# Шаг 6: Проверка и вывод результатов
# ═══════════════════════════════════════════
echo -e "\n${GREEN}[6/6]${NC} Проверка доступности портов..."

# Проверяем что порты слушают локально
PANEL_LISTENING=$(ss -tlnp | grep -c ":${PANEL_PORT}" || true)
VPN_LISTENING=$(ss -tlnp | grep -c ":${INBOUND_PORT}" || true)

if [[ "$PANEL_LISTENING" -eq 0 ]]; then
    echo -e "  ${YELLOW}⚠ Панель не слушает порт ${PANEL_PORT}${NC}"
    # Попробуем узнать реальный порт
    ACTUAL_PANEL=$(ss -tlnp | grep x-ui | grep -v xray | head -1 | awk '{print $4}' | rev | cut -d: -f1 | rev)
    if [[ -n "$ACTUAL_PANEL" ]]; then
        PANEL_PORT="$ACTUAL_PANEL"
        echo -e "  Панель слушает на порту ${GREEN}${PANEL_PORT}${NC} — использую его"
        open_ports "$PANEL_PORT"
    fi
else
    echo -e "  Панель (${PANEL_PORT}) ${GREEN}слушает${NC}"
fi

if [[ "$VPN_LISTENING" -eq 0 ]]; then
    echo -e "  ${RED}✗ VPN не слушает порт ${INBOUND_PORT}!${NC}"
else
    echo -e "  VPN (${INBOUND_PORT}) ${GREEN}слушает${NC}"
fi

# Проверяем доступность снаружи (через внешний сервис)
echo -e "  Проверяю доступность извне..."
VPN_EXTERNAL=$(curl -s --max-time 5 "https://portcheck.transmissionbt.com/${INBOUND_PORT}" 2>/dev/null || true)
# Альтернативный способ — пробуем подключиться через curl к самому себе
VPN_REACHABLE="unknown"
if timeout 3 bash -c "echo > /dev/tcp/${SERVER_IP}/${INBOUND_PORT}" 2>/dev/null; then
    VPN_REACHABLE="open"
fi

VLESS_LINK="vless://${CLIENT_UUID}@${SERVER_IP}:${INBOUND_PORT}?type=tcp&security=reality&pbk=${PUBLIC_KEY}&fp=chrome&sni=${SNI_DOMAIN}&sid=${SID1}&spx=%2F&headerType=http&path=%2F#VPN-${SERVER_IP}"
PANEL_URL="http://${SERVER_IP}:${PANEL_PORT}${WEB_BASE_PATH}"

echo ""
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}ПАНЕЛЬ УПРАВЛЕНИЯ${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  URL:     ${GREEN}${PANEL_URL}${NC}"
echo -e "  Логин:   ${GREEN}${ADMIN_USER}${NC}"
echo -e "  Пароль:  ${GREEN}${ADMIN_PASS}${NC}"

echo ""
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}ССЫЛКА ДЛЯ ПОДКЛЮЧЕНИЯ${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  Скопируйте в VPN-приложение:\n"
echo -e "  ${GREEN}${VLESS_LINK}${NC}"

echo ""
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}КАК ПОДКЛЮЧИТЬСЯ${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  ${BOLD}iPhone/iPad:${NC}  Streisand или V2Box (App Store)"
echo -e "  ${BOLD}Android:${NC}      V2RayNG или Hiddify (Google Play)"
echo -e "  ${BOLD}Windows:${NC}      Hiddify или V2RayN"
echo -e "  ${BOLD}macOS:${NC}        Hiddify или V2RayN"
echo ""
echo -e "  1. Установите приложение"
echo -e "  2. Нажмите '+' → 'Импорт из буфера' или 'Add from clipboard'"
echo -e "  3. Вставьте ссылку выше"
echo -e "  4. Подключайтесь!"

# Предупреждение если порты недоступны
if [[ "$VPN_REACHABLE" != "open" ]]; then
    echo ""
    echo -e "${YELLOW}═══════════════════════════════════════════${NC}"
    echo -e "${YELLOW}  ⚠  ПОРТЫ МОГУТ БЫТЬ ЗАКРЫТЫ ПРОВАЙДЕРОМ${NC}"
    echo -e "${YELLOW}═══════════════════════════════════════════${NC}"
    echo -e "  Порт ${INBOUND_PORT} слушает, но может быть заблокирован"
    echo -e "  на уровне хостинга (внешний файрвол)."
    echo ""
    echo -e "  ${BOLD}Что сделать:${NC}"
    echo -e "  1. Откройте панель управления вашего хостинга"
    echo -e "  2. Найдите раздел Firewall / Security Groups / Сеть"
    echo -e "  3. Разрешите входящий TCP на порты:"
    echo -e "     - ${BOLD}${INBOUND_PORT}${NC} (VPN)"
    echo -e "     - ${BOLD}${PANEL_PORT}${NC} (панель управления)"
    echo ""
    echo -e "  ${BOLD}Или:${NC} Hetzner, DigitalOcean, Vultr — обычно все"
    echo -e "  порты открыты по умолчанию."
fi

echo ""
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}ДОБАВИТЬ ПОЛЬЗОВАТЕЛЯ${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  Откройте панель → Inbounds → VLESS-Reality"
echo -e "  → кнопка '+' рядом с клиентами"

echo ""
echo -e "${YELLOW}⚠  Сохраните эту информацию! Повторно она не покажется.${NC}"
echo ""

# ── Сохранить в файл ──
CREDS_FILE="/root/vpn-credentials.txt"
cat > "$CREDS_FILE" << CREDEOF
VPN Server Credentials
Created: $(date '+%Y-%m-%d %H:%M')
Server:  ${SERVER_IP}

Panel URL:   ${PANEL_URL}
Login:       ${ADMIN_USER}
Password:    ${ADMIN_PASS}

VLESS Link:  ${VLESS_LINK}

Client:      ${CLIENT_NAME}
Protocol:    VLESS + Reality
VPN Port:    ${INBOUND_PORT}
Panel Port:  ${PANEL_PORT}
CREDEOF
chmod 600 "$CREDS_FILE"
echo -e "${GREEN}Данные сохранены в ${CREDS_FILE}${NC}\n"
