#!/bin/bash
set -Eeuo pipefail

API_URL="http://78.47.162.23:8088/register"
TOKEN="b3265247b40ffcb66db151bbe8b150d56e65d9d5a04cf6a2b8487c7002e427ff"

WG_DIR="/etc/wireguard"
STATE_FILE="${WG_DIR}/timehost-wg-client.env"

SERVER_PUBLIC_KEY="DDgBsOGcXEv2f26az0Ysx0WHmtaPa9pBdUf2x0JffiU="
SERVER_ENDPOINT="78.47.162.23:51820"

error_exit() {
    echo
    echo "ОШИБКА: $1"
    echo "Скрипт остановлен. Повторный запуск безопасен."
    exit 1
}

run_cmd() {
    "$@" || error_exit "Команда не выполнена: $*"
}

if [ "$EUID" -ne 0 ]; then
    error_exit "Запусти скрипт от root"
fi

detect_os() {
    [ -f /etc/os-release ] || error_exit "Не найден /etc/os-release"

    . /etc/os-release

    OS_ID="${ID:-unknown}"
    OS_NAME="${PRETTY_NAME:-unknown}"
    OS_VERSION_MAJOR="${VERSION_ID%%.*}"

    case "$OS_ID" in
        almalinux)
            OS_FAMILY="alma"
            ;;
        ubuntu|debian)
            OS_FAMILY="apt"
            ;;
        centos)
            if [ "$OS_VERSION_MAJOR" = "7" ]; then
                OS_FAMILY="centos7"
            else
                error_exit "Поддерживается только CentOS 7, текущая ОС: $OS_NAME"
            fi
            ;;
        *)
            error_exit "Неподдерживаемая ОС: $OS_NAME"
            ;;
    esac
}

check_network() {
    API_HOST="$(echo "$API_URL" | sed -E 's#^https?://([^/:]+).*#\1#')"
    API_PORT="$(echo "$API_URL" | sed -E 's#^https?://[^/:]+:([0-9]+).*#\1#')"

    if [ "$API_PORT" = "$API_URL" ]; then
        case "$API_URL" in
            https://*) API_PORT="443" ;;
            http://*) API_PORT="80" ;;
            *) API_PORT="80" ;;
        esac
    fi

    getent hosts "$API_HOST" >/dev/null 2>&1 || error_exit "DNS не резолвит API host: $API_HOST"
    timeout 5 bash -c "</dev/tcp/${API_HOST}/${API_PORT}" 2>/dev/null || error_exit "API сервер недоступен: ${API_HOST}:${API_PORT}"
}

install_apt() {
    command -v apt-get >/dev/null 2>&1 || error_exit "apt-get не найден"

    export DEBIAN_FRONTEND=noninteractive
    export NEEDRESTART_MODE=a

    run_cmd dpkg --configure -a

    run_cmd apt-get update -y

    run_cmd apt-get install -y \
        -o Dpkg::Options::="--force-confdef" \
        -o Dpkg::Options::="--force-confold" \
        wireguard curl

    run_cmd apt-get -f install -y \
        -o Dpkg::Options::="--force-confdef" \
        -o Dpkg::Options::="--force-confold"

    command -v wg >/dev/null 2>&1 || error_exit "wg не установлен"
    command -v wg-quick >/dev/null 2>&1 || error_exit "wg-quick не установлен"
    command -v curl >/dev/null 2>&1 || error_exit "curl не установлен"
}

install_alma() {
    command -v dnf >/dev/null 2>&1 || error_exit "dnf не найден"

    case "$OS_VERSION_MAJOR" in
        8|9|10)
            ELREPO_URL="https://www.elrepo.org/elrepo-release-${OS_VERSION_MAJOR}.el${OS_VERSION_MAJOR}.elrepo.noarch.rpm"
            ;;
        *)
            error_exit "Неподдерживаемая версия AlmaLinux: $OS_NAME"
            ;;
    esac

run_cmd dnf install -y epel-release
run_cmd dnf install -y dnf-plugins-core
dnf install -y "$ELREPO_URL" || true

if [ "$OS_VERSION_MAJOR" = "8" ]; then
    dnf config-manager --set-enabled powertools >/dev/null 2>&1 || \
    dnf config-manager --set-enabled PowerTools >/dev/null 2>&1 || true
else
    dnf config-manager --set-enabled crb >/dev/null 2>&1 || true
fi

run_cmd dnf makecache -y
run_cmd dnf install -y kmod-wireguard wireguard-tools curl

    command -v wg >/dev/null 2>&1 || error_exit "wg не установлен"
    command -v wg-quick >/dev/null 2>&1 || error_exit "wg-quick не установлен"
    command -v curl >/dev/null 2>&1 || error_exit "curl не установлен"

    if ! modprobe wireguard 2>/tmp/wg_error.txt; then
        echo
        echo "WireGuard установлен, но модуль не загрузился."
        echo "Скорее всего обновилось ядро."
        echo
        echo "Сделайте reboot:"
        echo "reboot"
        echo
        echo "После reboot повторно запустите:"
        echo "bash telegram-fix.sh"
        echo
        cat /tmp/wg_error.txt
        exit 1
    fi
}


install_centos7() {
    command -v yum >/dev/null 2>&1 || error_exit "yum не найден"

    run_cmd yum install -y epel-release
    run_cmd yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) dkms gcc make perl elfutils-libelf-devel curl

    curl -fsSL -o /etc/yum.repos.d/jdoss-wireguard-epel-7.repo \
        https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo || \
        error_exit "Не удалось скачать jdoss-wireguard repo"

    run_cmd yum install -y wireguard-dkms wireguard-tools

    WG_DKMS_VERSION="$(dkms status | grep wireguard | awk -F',' '{print $2}' | tr -d ' ' | head -n1)"

    if [ -n "$WG_DKMS_VERSION" ]; then
        dkms install "wireguard/${WG_DKMS_VERSION}" >/dev/null 2>&1 || true
    fi

    command -v wg >/dev/null 2>&1 || error_exit "wg не установлен"
    command -v wg-quick >/dev/null 2>&1 || error_exit "wg-quick не установлен"
    command -v curl >/dev/null 2>&1 || error_exit "curl не установлен"

    if ! modprobe wireguard 2>/tmp/wg_error.txt; then
        echo
        echo "WireGuard установлен, но модуль не загрузился."
        echo "Возможно не совпадает текущее ядро и kernel-devel/kernel-headers."
        echo
        echo "Сделайте reboot:"
        echo "reboot"
        echo
        echo "После reboot повторно запустите:"
        echo "bash telegram-fix.sh"
        echo
        cat /tmp/wg_error.txt
        exit 1
    fi
}

get_free_wg_name() {
    for i in $(seq 0 99); do
        if [ ! -f "${WG_DIR}/wg${i}.conf" ]; then
            echo "wg${i}"
            return
        fi
    done

    error_exit "Нет свободного имени WireGuard интерфейса"
}

load_or_create_state() {
    mkdir -p "$WG_DIR"
    chmod 700 "$WG_DIR"

    if [ -f "$STATE_FILE" ]; then
        . "$STATE_FILE"

        [ -n "${WG_IF:-}" ] || error_exit "Поврежден state-файл: нет WG_IF"
        [ -n "${PRIVATE_KEY_FILE:-}" ] || error_exit "Поврежден state-файл: нет PRIVATE_KEY_FILE"
        [ -n "${PUBLIC_KEY_FILE:-}" ] || error_exit "Поврежден state-файл: нет PUBLIC_KEY_FILE"

        WG_CONF="${WG_DIR}/${WG_IF}.conf"
        return
    fi

    WG_IF="$(get_free_wg_name)"
    WG_CONF="${WG_DIR}/${WG_IF}.conf"
    PRIVATE_KEY_FILE="${WG_DIR}/${WG_IF}_privatekey"
    PUBLIC_KEY_FILE="${WG_DIR}/${WG_IF}_publickey"

    cat > "$STATE_FILE" <<EOF
WG_IF="$WG_IF"
PRIVATE_KEY_FILE="$PRIVATE_KEY_FILE"
PUBLIC_KEY_FILE="$PUBLIC_KEY_FILE"
EOF

    chmod 600 "$STATE_FILE"
}

generate_or_reuse_keys() {
    if [ -f "$PRIVATE_KEY_FILE" ] && [ -f "$PUBLIC_KEY_FILE" ]; then
        PRIVATE_KEY="$(cat "$PRIVATE_KEY_FILE")"
        PUBLIC_KEY="$(cat "$PUBLIC_KEY_FILE")"
        return
    fi

    umask 077
    wg genkey | tee "$PRIVATE_KEY_FILE" | wg pubkey > "$PUBLIC_KEY_FILE"

    chmod 600 "$PRIVATE_KEY_FILE"
    chmod 644 "$PUBLIC_KEY_FILE"

    PRIVATE_KEY="$(cat "$PRIVATE_KEY_FILE")"
    PUBLIC_KEY="$(cat "$PUBLIC_KEY_FILE")"

    echo "$PUBLIC_KEY" | grep -Eq '^[A-Za-z0-9+/]{43}=$' || error_exit "Некорректный public key"
}

already_installed_check() {
    if [ -f "$WG_CONF" ]; then
        if grep -q "PublicKey = ${SERVER_PUBLIC_KEY}" "$WG_CONF" && grep -q "Endpoint = ${SERVER_ENDPOINT}" "$WG_CONF"; then
            echo "Конфиг уже существует: $WG_CONF"
            echo "Повторное добавление peer на сервер не выполняется."

            systemctl enable "wg-quick@${WG_IF}" >/dev/null 2>&1 || true
            run_cmd systemctl restart "wg-quick@${WG_IF}"

            echo
            echo "ГОТОВО"
            echo "Интерфейс: ${WG_IF}"
            wg show "$WG_IF"
            exit 0
        else
            error_exit "Файл $WG_CONF уже существует, но это не наш конфиг"
        fi
    fi
}

register_on_server() {
    CONFIG="$(curl -fsS -X POST "$API_URL" \
        -H "Authorization: Bearer $TOKEN" \
        --data-urlencode "pubkey=$PUBLIC_KEY" \
        --data-urlencode "hostname=$(hostname)")" || error_exit "API запрос не выполнен"

    echo "$CONFIG" | grep -q "NO FREE IP" && error_exit "Нет свободных IP на WG сервере"
    echo "$CONFIG" | grep -q "BAD TOKEN" && error_exit "Неверный токен"
    echo "$CONFIG" | grep -q "NO PUBKEY" && error_exit "Не удалось передать public key"

    echo "$CONFIG" | grep -q "CLIENT_PRIVATE_KEY" || {
        echo "$CONFIG"
        error_exit "WG сервер вернул некорректный ответ"
    }
}

write_config() {
    TMP_CONF="${WG_CONF}.tmp"

    echo "$CONFIG" | sed "s|CLIENT_PRIVATE_KEY|$PRIVATE_KEY|g" > "$TMP_CONF"

    grep -q "PrivateKey = " "$TMP_CONF" || error_exit "В конфиге нет PrivateKey"
    grep -q "Address = " "$TMP_CONF" || error_exit "В конфиге нет Address"
    grep -q "PublicKey = ${SERVER_PUBLIC_KEY}" "$TMP_CONF" || error_exit "В конфиге неверный серверный PublicKey"
    grep -q "Endpoint = ${SERVER_ENDPOINT}" "$TMP_CONF" || error_exit "В конфиге неверный Endpoint"

    mv "$TMP_CONF" "$WG_CONF"
    chmod 600 "$WG_CONF"
}

start_wireguard() {
    run_cmd systemctl enable "wg-quick@${WG_IF}"
    run_cmd systemctl restart "wg-quick@${WG_IF}"

    sleep 1
    wg show "$WG_IF" >/dev/null 2>&1 || error_exit "Интерфейс ${WG_IF} не запустился"
}

detect_os
check_network

case "$OS_FAMILY" in
    alma)
        install_alma
        ;;
    apt)
        install_apt
        ;;
    centos7)
        install_centos7
        ;;
esac

load_or_create_state
generate_or_reuse_keys
already_installed_check
register_on_server
write_config
start_wireguard


ping -c 1 10.10.10.1

wg show "$WG_IF"

echo
echo "ГОТОВО"
echo "ОС: ${OS_NAME}"
echo "Интерфейс: ${WG_IF}"
echo "Конфиг: ${WG_CONF}"
echo "PublicKey: ${PUBLIC_KEY}"
echo