#!/bin/bash
# =============================================================================
#  SPZGate — bootstrap installer
#  Usage:    curl -fsSL https://spamorez.ru/spzgate/install.sh | bash
#  Optional: ... | bash -s -- --dir /opt/spzgate --lang ru
# =============================================================================
set -euo pipefail

RELEASE_BASE="https://spamorez.ru/spzgate/releases"
DEFAULT_INSTALL_DIR="/opt/spzgate"

# ── Colors ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
info()  { echo -e "${CYAN}[INFO]${NC}  $*"; }
ok()    { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
die()   { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }

# ── Arguments ─────────────────────────────────────────────────────────────────
INSTALL_DIR="$DEFAULT_INSTALL_DIR"
TARGET_VERSION=""
LANG_CODE=""   # empty = ask

while [[ $# -gt 0 ]]; do
    case $1 in
        --dir)     INSTALL_DIR="$2";     shift 2 ;;
        --version) TARGET_VERSION="$2";  shift 2 ;;
        --lang)    LANG_CODE="$2";       shift 2 ;;
        --help|-h)
            echo "curl -fsSL https://spamorez.ru/install.sh | bash -s -- [--dir PATH] [--version X.Y.Z] [--lang en|ru]"
            exit 0 ;;
        *) die "Unknown parameter: $1" ;;
    esac
done

# ── Language selection ────────────────────────────────────────────────────────
if [[ -z "$LANG_CODE" ]]; then
    if [[ -e /dev/tty ]]; then
        printf "${BOLD}Installation language / Язык установки [EN/ru]: ${NC}" >/dev/tty
        read -r _lang_input </dev/tty || _lang_input=""
    else
        _lang_input=""
    fi
    _lang_input=$(echo "$_lang_input" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')
    if [[ "$_lang_input" == "ru" ]]; then
        LANG_CODE="ru"
    else
        LANG_CODE="en"
    fi
fi

# ── Messages ──────────────────────────────────────────────────────────────────
if [[ "$LANG_CODE" == "ru" ]]; then
    MSG_TITLE="SPZGate — Установка"
    MSG_RUN_AS_ROOT="Запустите от root:\n  curl -fsSL https://spamorez.ru/install.sh | sudo bash"
    MSG_NO_MACOS="macOS не поддерживается. SPZGate работает только на Linux."
    MSG_BAD_OS="Неподдерживаемая ОС"
    MSG_BAD_ARCH="Неподдерживаемая архитектура"
    MSG_OS="ОС"
    MSG_INSTALL_DIR="Директория установки"
    MSG_NO_DOWNLOADER="Требуется curl или wget — установите один из них и повторите"
    MSG_FETCHING="Получаем последнюю версию..."
    MSG_VER_FAIL="Не удалось получить версию с сервера.\nПроверьте доступность https://spamorez.ru/"
    MSG_VERSION="Версия"
    MSG_BAD_VERSION="Неверный формат версии"
    MSG_MANIFEST="Загружаем манифест..."
    MSG_MANIFEST_FAIL="Не удалось загрузить манифест"
    MSG_BAD_ARCH_MANIFEST="не найдена в манифесте"
    MSG_BAD_CHECKSUM="Некорректный checksum в манифесте"
    MSG_DOWNLOADING="Загружаем"
    MSG_DL_FAIL="Ошибка загрузки"
    MSG_VERIFYING="Проверяем контрольную сумму..."
    MSG_CHECKSUM_MISMATCH="Контрольная сумма не совпадает!\n  Ожидалось: %s\n  Получено:  %s"
    MSG_CHECKSUM_OK="Контрольная сумма верна"
    MSG_EXTRACTING="Распаковываем в"
    MSG_EXTRACTED="Распаковано"
    MSG_NO_INSTALLER="install.sh не найден в тарболе — повреждённый дистрибутив?"
    MSG_RUNNING="Запускаем установщик..."
else
    MSG_TITLE="SPZGate — Installation"
    MSG_RUN_AS_ROOT="Run as root:\n  curl -fsSL https://spamorez.ru/install.sh | sudo bash"
    MSG_NO_MACOS="macOS is not supported. SPZGate requires Linux."
    MSG_BAD_OS="Unsupported OS"
    MSG_BAD_ARCH="Unsupported architecture"
    MSG_OS="OS"
    MSG_INSTALL_DIR="Install directory"
    MSG_NO_DOWNLOADER="curl or wget is required — install one of them and retry"
    MSG_FETCHING="Fetching latest version..."
    MSG_VER_FAIL="Failed to get version from server.\nCheck availability of https://spamorez.ru/"
    MSG_VERSION="Version"
    MSG_BAD_VERSION="Invalid version format"
    MSG_MANIFEST="Downloading manifest..."
    MSG_MANIFEST_FAIL="Failed to download manifest"
    MSG_BAD_ARCH_MANIFEST="not found in manifest"
    MSG_BAD_CHECKSUM="Invalid checksum in manifest"
    MSG_DOWNLOADING="Downloading"
    MSG_DL_FAIL="Download error"
    MSG_VERIFYING="Verifying checksum..."
    MSG_CHECKSUM_MISMATCH="Checksum mismatch!\n  Expected: %s\n  Got:      %s"
    MSG_CHECKSUM_OK="Checksum verified"
    MSG_EXTRACTING="Extracting to"
    MSG_EXTRACTED="Done"
    MSG_NO_INSTALLER="install.sh not found in tarball — corrupted package?"
    MSG_RUNNING="Running installer..."
fi

# ── Header ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}╔══════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║         $MSG_TITLE               ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════╝${NC}"
echo ""

# ── Checks ────────────────────────────────────────────────────────────────────
[[ $EUID -eq 0 ]] || die "$MSG_RUN_AS_ROOT"

case "$(uname -s)" in
    Linux) ;;
    Darwin) die "$MSG_NO_MACOS" ;;
    *) die "$MSG_BAD_OS: $(uname -s)" ;;
esac

case "$(uname -m)" in
    x86_64|amd64) ARCH="amd64" ;;
    aarch64|arm64) ARCH="arm64" ;;
    *) die "$MSG_BAD_ARCH: $(uname -m)" ;;
esac

info "$MSG_OS: $(uname -s) / $(uname -m)"
info "$MSG_INSTALL_DIR: $INSTALL_DIR"

# ── Validate version format if provided ───────────────────────────────────────
if [[ -n "$TARGET_VERSION" ]] && \
   [[ ! "$TARGET_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[^[:space:]]+)?$ ]]; then
    die "$MSG_BAD_VERSION: $TARGET_VERSION (expected X.Y.Z)"
fi

# ── Downloader ────────────────────────────────────────────────────────────────
DOWNLOADER=""
if command -v curl >/dev/null 2>&1; then
    DOWNLOADER="curl"
elif command -v wget >/dev/null 2>&1; then
    DOWNLOADER="wget"
else
    die "$MSG_NO_DOWNLOADER"
fi

download() {
    local url="$1" out="${2:-}"
    # Cache-busting: releases переиздаются под тем же именем файла во время
    # разработки (make_release.sh --publish перезаписывает архив на месте).
    # Внешние edge-кэши перед spamorez.ru могут закэшировать ответ надолго и
    # не перепроверять его по Cache-Control от клиента — поэтому каждый запуск
    # bootstrap.sh добавляет уникальный параметр к URL, меняющий cache key.
    local bust="_cb=$(date +%s%N 2>/dev/null || date +%s)$$"
    if [[ "$url" == *'?'* ]]; then url="${url}&${bust}"; else url="${url}?${bust}"; fi
    if [[ "$DOWNLOADER" == "curl" ]]; then
        if [[ -n "$out" ]]; then curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' -o "$out" "$url"
        else curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' "$url"; fi
    else
        if [[ -n "$out" ]]; then wget -q --no-cache -O "$out" "$url"
        else wget -q --no-cache -O - "$url"; fi
    fi
}

# ── Fetch version ─────────────────────────────────────────────────────────────
if [[ -z "$TARGET_VERSION" ]]; then
    info "$MSG_FETCHING"
    VERSION=$(download "$RELEASE_BASE/latest" 2>/dev/null || true)
    if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
        die "$MSG_VER_FAIL"
    fi
else
    VERSION="$TARGET_VERSION"
fi
info "$MSG_VERSION: $VERSION"

# ── Download manifest and checksum ────────────────────────────────────────────
MANIFEST_URL="$RELEASE_BASE/$VERSION/manifest.json"
info "$MSG_MANIFEST"
MANIFEST=$(download "$MANIFEST_URL" 2>/dev/null) || \
    die "$MSG_MANIFEST_FAIL: $MANIFEST_URL"

# Extract checksum from JSON (no jq dependency)
get_checksum() {
    local json="$1" platform="$2"
    json=$(echo "$json" | tr -d '\n\r\t' | sed 's/ \+/ /g')
    if [[ $json =~ \"$platform\"[^}]*\"checksum\"[[:space:]]*:[[:space:]]*\"([a-f0-9]{64})\" ]]; then
        echo "${BASH_REMATCH[1]}"; return 0
    fi
    if [[ $json =~ \"checksum\"[[:space:]]*:[[:space:]]*\"([a-f0-9]{64})\" ]]; then
        echo "${BASH_REMATCH[1]}"; return 0
    fi
    return 1
}

CHECKSUM=$(get_checksum "$MANIFEST" "$ARCH") || \
    die "Architecture '$ARCH' $MSG_BAD_ARCH_MANIFEST $VERSION"

if [[ ! "$CHECKSUM" =~ ^[a-f0-9]{64}$ ]]; then
    die "$MSG_BAD_CHECKSUM"
fi
info "SHA256: ${CHECKSUM:0:16}…"

# ── Download tarball ──────────────────────────────────────────────────────────
TARBALL_NAME="spzgate-${VERSION}-${ARCH}.tar.gz"
TARBALL_URL="$RELEASE_BASE/$VERSION/$TARBALL_NAME"
TMP_DIR=$(mktemp -d)
TARBALL_PATH="$TMP_DIR/$TARBALL_NAME"

trap 'rm -rf "$TMP_DIR"' EXIT

info "$MSG_DOWNLOADING $TARBALL_NAME..."
download "$TARBALL_URL" "$TARBALL_PATH" || \
    die "$MSG_DL_FAIL: $TARBALL_URL"

# ── Verify SHA256 ─────────────────────────────────────────────────────────────
info "$MSG_VERIFYING"
if command -v sha256sum >/dev/null 2>&1; then
    ACTUAL=$(sha256sum "$TARBALL_PATH" | cut -d' ' -f1)
else
    ACTUAL=$(openssl dgst -sha256 "$TARBALL_PATH" | awk '{print $NF}')
fi

if [[ "$ACTUAL" != "$CHECKSUM" ]]; then
    # shellcheck disable=SC2059
    die "$(printf "$MSG_CHECKSUM_MISMATCH" "$CHECKSUM" "$ACTUAL")"
fi
ok "$MSG_CHECKSUM_OK"

# ── Extract ───────────────────────────────────────────────────────────────────
info "$MSG_EXTRACTING $INSTALL_DIR ..."
mkdir -p "$INSTALL_DIR"
tar -xzf "$TARBALL_PATH" -C "$INSTALL_DIR" --strip-components=1
ok "$MSG_EXTRACTED"

# ── Run inner installer ───────────────────────────────────────────────────────
INNER_INSTALLER="$INSTALL_DIR/install.sh"
[[ -f "$INNER_INSTALLER" ]] || die "$MSG_NO_INSTALLER"
chmod +x "$INNER_INSTALLER"

echo ""
info "$MSG_RUNNING"
echo ""
exec bash "$INNER_INSTALLER" --dir "$INSTALL_DIR" --lang "$LANG_CODE"
