#!/usr/bin/env bash
# WebPanel sürüm güncelleyicisi: SHA-256 doğrulama, sağlık kontrolü ve tek adım geri dönüş.
set -Eeuo pipefail

umask 077

ENV_INSTALL_DIR="${WEBPANEL_INSTALL_DIR:-}"
ENV_SERVICE_NAME="${WEBPANEL_SERVICE_NAME:-}"
ENV_BIN="${WEBPANEL_BIN:-}"
ENV_UPDATER_PATH="${WEBPANEL_UPDATER_PATH:-}"
ENV_UNINSTALLER_PATH="${WEBPANEL_UNINSTALLER_PATH:-}"
ENV_RELEASE_BASE_URL="${WEBPANEL_RELEASE_BASE_URL:-}"
ENV_CHANNEL_URL="${WEBPANEL_CHANNEL_URL:-}"
ENV_DOWNLOAD_TOKEN="${WEBPANEL_DOWNLOAD_TOKEN:-}"
ENV_DOWNLOAD_TOKEN_FILE="${WEBPANEL_DOWNLOAD_TOKEN_FILE:-}"
ENV_ALLOW_INSECURE="${WEBPANEL_ALLOW_INSECURE:-}"

CONFIG_DIR="${WEBPANEL_CONFIG_DIR:-/etc/webpanel}"
RELEASE_CONFIG="$CONFIG_DIR/release.conf"
RUNTIME_CONFIG="$CONFIG_DIR/webpanel.env"
INSTALL_DIR="${ENV_INSTALL_DIR:-/opt/webpanel}"
SERVICE_NAME="${ENV_SERVICE_NAME:-webpanel}"
BIN="${ENV_BIN:-$INSTALL_DIR/webpanel}"
CLI_LINK_PATH="${WEBPANEL_CLI_LINK_PATH:-/usr/local/bin/webpanel}"
UPDATER_PATH="${ENV_UPDATER_PATH:-/usr/local/sbin/webpanel-update}"
UNINSTALLER_PATH="${ENV_UNINSTALLER_PATH:-/usr/local/sbin/webpanel-uninstall}"
RELEASE_BASE_URL="${ENV_RELEASE_BASE_URL:-https://gits.hibna.com.tr/api/packages/hibna/generic/webpanel}"
CHANNEL_URL="${ENV_CHANNEL_URL:-https://gits.hibna.com.tr/api/v1/packages/hibna/generic/webpanel/-/latest}"
DOWNLOAD_TOKEN="$ENV_DOWNLOAD_TOKEN"
DOWNLOAD_TOKEN_FILE="$ENV_DOWNLOAD_TOKEN_FILE"
ALLOW_INSECURE="${ENV_ALLOW_INSECURE:-0}"
PORT="8888"
DATA_DIR=""
TARGET="x86_64-unknown-linux-musl"
TMP_DIR=""
CURL_AUTH_CONFIG=""

log() { printf '==> %s\n' "$*"; }
warn() { printf 'UYARI: %s\n' "$*" >&2; }
die() { printf 'HATA: %s\n' "$*" >&2; exit 1; }

cleanup() {
    if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
        rm -rf -- "$TMP_DIR"
    fi
}
trap cleanup EXIT

load_config() {
    local key value
    if [ -r "$RELEASE_CONFIG" ]; then
        while IFS='=' read -r key value; do
            case "$key" in
                WEBPANEL_INSTALL_DIR) [ -n "$ENV_INSTALL_DIR" ] || INSTALL_DIR="$value" ;;
                WEBPANEL_SERVICE_NAME) [ -n "$ENV_SERVICE_NAME" ] || SERVICE_NAME="$value" ;;
                WEBPANEL_BIN) [ -n "$ENV_BIN" ] || BIN="$value" ;;
                WEBPANEL_UPDATER_PATH) [ -n "$ENV_UPDATER_PATH" ] || UPDATER_PATH="$value" ;;
                WEBPANEL_UNINSTALLER_PATH) [ -n "$ENV_UNINSTALLER_PATH" ] || UNINSTALLER_PATH="$value" ;;
                WEBPANEL_RELEASE_BASE_URL) [ -n "$ENV_RELEASE_BASE_URL" ] || RELEASE_BASE_URL="$value" ;;
                WEBPANEL_CHANNEL_URL) [ -n "$ENV_CHANNEL_URL" ] || CHANNEL_URL="$value" ;;
                WEBPANEL_DOWNLOAD_TOKEN_FILE)
                    if [ -z "$ENV_DOWNLOAD_TOKEN" ] && [ -z "$ENV_DOWNLOAD_TOKEN_FILE" ]; then
                        DOWNLOAD_TOKEN_FILE="$value"
                    fi
                    ;;
                WEBPANEL_ALLOW_INSECURE) [ -n "$ENV_ALLOW_INSECURE" ] || ALLOW_INSECURE="$value" ;;
            esac
        done < "$RELEASE_CONFIG"
    fi
    if [ -r "$RUNTIME_CONFIG" ]; then
        value="$(awk -F= '$1 == "WEBPANEL_PORT" { print $2; exit }' "$RUNTIME_CONFIG")"
        PORT="${value:-8888}"
        DATA_DIR="$(awk -F= '$1 == "WEBPANEL_DATA_DIR" { print $2; exit }' "$RUNTIME_CONFIG")"
    fi
}

require_command() {
    command -v "$1" >/dev/null 2>&1 || die "Gerekli komut bulunamadı: $1"
}

validate_absolute_path() {
    local canonical
    case "$2" in /*) ;; *) die "$1 mutlak bir yol olmalı: $2" ;; esac
    [[ "$2" != *$'\n'* && "$2" != *$'\r'* && "$2" != *' '* ]] ||
        die "$1 boşluk veya satır sonu içeremez"
    canonical="$(realpath -m -- "$2")"
    [ "$canonical" = "$2" ] || die "$1 kanonik olmalı: $2"
}

validate_version() {
    [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9]+)*$ ]] ||
        die "Geçersiz sürüm: $1"
}

validate_url() {
    local value="$2"
    [[ "$value" != *[[:space:]]* ]] || die "$1 boşluk içeremez"
    if [ "$ALLOW_INSECURE" = "1" ]; then
        [[ "$value" =~ ^(https?|file):// ]] || die "$1 geçerli bir URL değil: $value"
    else
        [[ "$value" == https://* ]] || die "$1 HTTPS kullanmalı: $value"
    fi
}

validate_download_token() {
    [ -z "$DOWNLOAD_TOKEN" ] && return
    if [ "${#DOWNLOAD_TOKEN}" -lt 16 ] || [ "${#DOWNLOAD_TOKEN}" -gt 512 ]; then
        die "İndirme token'ı geçersiz uzunlukta"
    fi
    [[ "$DOWNLOAD_TOKEN" =~ ^[A-Za-z0-9._~-]+$ ]] ||
        die "İndirme token'ı güvenli olmayan karakter içeriyor"
}

load_download_token() {
    local owner mode
    if [ -z "$DOWNLOAD_TOKEN" ] && [ -n "$DOWNLOAD_TOKEN_FILE" ]; then
        validate_absolute_path "İndirme token dosyası" "$DOWNLOAD_TOKEN_FILE"
        if [ ! -f "$DOWNLOAD_TOKEN_FILE" ] || [ -L "$DOWNLOAD_TOKEN_FILE" ]; then
            die "İndirme token yolu normal dosya olmalı"
        fi
        owner="$(stat -c %u "$DOWNLOAD_TOKEN_FILE")"
        mode="$(stat -c %a "$DOWNLOAD_TOKEN_FILE")"
        [ "$owner" = "0" ] || die "İndirme token dosyasının sahibi root olmalı"
        case "$mode" in 400 | 600) ;; *) die "İndirme token dosyası izni 0400 veya 0600 olmalı" ;; esac
        DOWNLOAD_TOKEN="$(<"$DOWNLOAD_TOKEN_FILE")"
    fi
    validate_download_token
}

prepare_download_auth() {
    [ -n "$DOWNLOAD_TOKEN" ] || return
    CURL_AUTH_CONFIG="$TMP_DIR/curl-auth.conf"
    printf 'header = "Authorization: token %s"\n' "$DOWNLOAD_TOKEN" > "$CURL_AUTH_CONFIG"
    chmod 0600 "$CURL_AUTH_CONFIG"
}

download() {
    local url="$1" output="$2"
    local auth_args=()
    local redirect_args=(--location)
    [ -z "$CURL_AUTH_CONFIG" ] || auth_args=(--config "$CURL_AUTH_CONFIG")
    [ -z "$CURL_AUTH_CONFIG" ] || redirect_args=(--location --max-redirs 0)
    if [ "$ALLOW_INSECURE" = "1" ]; then
        curl "${auth_args[@]}" "${redirect_args[@]}" --fail --silent --show-error \
            --output "$output" "$url"
    else
        curl "${auth_args[@]}" "${redirect_args[@]}" --proto '=https' --proto-redir '=https' \
            --tlsv1.2 --fail --silent --show-error --output "$output" "$url"
    fi
}

channel_version() {
    local source="$1" normalized version
    normalized="$(tr -d '[:space:]' < "$source")" ||
        die "Sürüm kanalı yanıtı okunamadı"
    case "$normalized" in
        \{*) version="$(printf '%s' "$normalized" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')" ;;
        *) version="$normalized" ;;
    esac
    [ -n "$version" ] || die "Sürüm kanalı yanıtında version bulunamadı"
    validate_version "$version"
    printf '%s\n' "$version"
}

current_version() {
    [ -x "$BIN" ] || die "WebPanel binary bulunamadı: $BIN"
    local output version
    output="$($BIN --version)" || die "Kurulu binary sürümü okunamadı"
    [[ "$output" =~ ^webpanel[[:space:]]+(.+)$ ]] || die "Kurulu binary sürüm bildirmiyor"
    version="${BASH_REMATCH[1]}"
    validate_version "$version"
    printf '%s\n' "$version"
}

stable_version() {
    validate_url "Sürüm kanalı" "$CHANNEL_URL"
    local output="$TMP_DIR/stable"
    download "$CHANNEL_URL" "$output" || die "Sürüm kanalı indirilemedi"
    local version
    version="$(channel_version "$output")" || die "Sürüm kanalı çözümlenemedi"
    printf '%s\n' "$version"
}

version_is_older() {
    local candidate="$1" current="$2" first
    [ "$candidate" != "$current" ] || return 1
    first="$(printf '%s\n%s\n' "$candidate" "$current" | sort -V | head -n 1)"
    [ "$first" = "$candidate" ]
}

verify_checksum() {
    local artifact="$1" checksum_file="$2" expected actual
    expected="$(awk 'NF { print $1; exit }' "$checksum_file")"
    [[ "$expected" =~ ^[0-9a-fA-F]{64}$ ]] || die "Checksum dosyası geçersiz"
    actual="$(sha256sum "$artifact" | awk '{print $1}')"
    [ "${actual,,}" = "${expected,,}" ] || die "Paket SHA-256 doğrulaması başarısız"
}

extract_package() {
    local artifact="$1" destination="$2"
    local count=0 seen_binary=0 seen_update=0 seen_uninstall=0 seen_version=0 entry
    while IFS= read -r entry; do
        count=$((count + 1))
        case "$entry" in
            webpanel) seen_binary=$((seen_binary + 1)) ;;
            webpanel-update) seen_update=$((seen_update + 1)) ;;
            webpanel-uninstall) seen_uninstall=$((seen_uninstall + 1)) ;;
            VERSION) seen_version=$((seen_version + 1)) ;;
            *) die "Paket beklenmeyen bir yol içeriyor: $entry" ;;
        esac
    done < <(tar -tzf "$artifact")
    if [ "$count" -ne 4 ] || [ "$seen_binary" -ne 1 ] || [ "$seen_update" -ne 1 ] ||
        [ "$seen_uninstall" -ne 1 ] || [ "$seen_version" -ne 1 ]; then
        die "Paket içeriği eksik veya tekrarlı"
    fi
    mkdir -p "$destination"
    tar -xzf "$artifact" -C "$destination" --no-same-owner --no-same-permissions
}

fetch_package() {
    local version="$1" destination="$2"
    local name="webpanel-v$version-$TARGET.tar.gz"
    local artifact="$TMP_DIR/$name" checksum="$TMP_DIR/$name.sha256"
    validate_url "Paket deposu" "$RELEASE_BASE_URL"
    log "WebPanel $version paketi indiriliyor"
    download "$RELEASE_BASE_URL/$version/$name" "$artifact"
    download "$RELEASE_BASE_URL/$version/$name.sha256" "$checksum"
    verify_checksum "$artifact" "$checksum"
    extract_package "$artifact" "$destination"
    [ "$(tr -d '[:space:]' < "$destination/VERSION")" = "$version" ] ||
        die "Paket içindeki sürüm beklenen değerle eşleşmiyor"
    chmod 0755 "$destination/webpanel" "$destination/webpanel-update" \
        "$destination/webpanel-uninstall"
    [ "$("$destination/webpanel" --version)" = "webpanel $version" ] ||
        die "Binary sürüm doğrulaması başarısız"
    bash -n "$destination/webpanel-update"
    bash -n "$destination/webpanel-uninstall"
}

health_check() {
    local _
    for _ in {1..30}; do
        if systemctl is-active --quiet "$SERVICE_NAME" &&
            curl --fail --silent --show-error --max-time 2 \
                "http://127.0.0.1:$PORT/api/health" | grep -q '"status":"ok"'; then
            return 0
        fi
        sleep 1
    done
    return 1
}

save_previous() {
    local version="$1" source_dir="$2" previous="$INSTALL_DIR/releases/previous"
    local staging="$INSTALL_DIR/releases/.previous-new"
    rm -rf -- "$staging"
    install -d -m 0700 "$staging"
    install -m 0755 "$source_dir/webpanel" "$staging/webpanel"
    install -m 0755 "$source_dir/webpanel-update" "$staging/webpanel-update"
    install -m 0755 "$source_dir/webpanel-uninstall" "$staging/webpanel-uninstall"
    printf '%s\n' "$version" > "$staging/VERSION"
    chmod 0600 "$staging/VERSION"
    rm -rf -- "$previous"
    mv -- "$staging" "$previous"
}

capture_current() {
    local destination="$1" version="$2"
    install -d -m 0700 "$destination"
    install -m 0755 "$BIN" "$destination/webpanel"
    install -m 0755 "$UPDATER_PATH" "$destination/webpanel-update"
    install -m 0755 "$UNINSTALLER_PATH" "$destination/webpanel-uninstall"
    printf '%s\n' "$version" > "$destination/VERSION"
}

# Migration'dan önce veritabanının tutarlı bir anlık görüntüsünü alır.
#
# ignore_missing sayesinde binary rollback'i çoğu durumda veriyi de koruyarak
# çalışır; bu anlık görüntü, migration'ın Dirty bıraktığı ya da şemayı geriye
# uyumsuz değiştirdiği ender durumlar için son çare geri dönüş noktasıdır.
# Alınamazsa güncelleme durmaz — yalnız uyarılır.
snapshot_database() {
    local snapshot="$INSTALL_DIR/releases/pre-update.db"
    if [ -z "$DATA_DIR" ]; then
        warn "Veri dizini bilinmiyor; migration öncesi veritabanı anlık görüntüsü atlandı"
        return 0
    fi
    if [ ! -f "$DATA_DIR/webpanel.db" ]; then
        warn "Veritabanı bulunamadı ($DATA_DIR/webpanel.db); anlık görüntü atlandı"
        return 0
    fi
    install -d -m 0700 "$INSTALL_DIR/releases"
    if WEBPANEL_DATA_DIR="$DATA_DIR" "$BIN" backup-db "$snapshot" >/dev/null 2>&1; then
        chmod 0600 "$snapshot" 2>/dev/null || true
        log "Migration öncesi veritabanı anlık görüntüsü: $snapshot"
    else
        warn "Veritabanı anlık görüntüsü alınamadı; güncelleme yine de sürüyor"
    fi
}

install_package_files() {
    local source="$1" version="$2"
    rm -f -- "$BIN.new" "$UPDATER_PATH.new" "$UNINSTALLER_PATH.new"
    install -m 0755 "$source/webpanel" "$BIN.new"
    install -m 0755 "$source/webpanel-update" "$UPDATER_PATH.new"
    install -m 0755 "$source/webpanel-uninstall" "$UNINSTALLER_PATH.new"
    mv -f -- "$BIN.new" "$BIN"
    mv -f -- "$UPDATER_PATH.new" "$UPDATER_PATH"
    mv -f -- "$UNINSTALLER_PATH.new" "$UNINSTALLER_PATH"
    ensure_cli_link
    printf '%s\n' "$version" > "$INSTALL_DIR/VERSION"
    chmod 0600 "$INSTALL_DIR/VERSION"
}

# `webpanel` komutunu PATH'e bağlar.
#
# 0.4.0 öncesi kurulumlarda bu bağ hiç oluşturulmuyordu: binary yalnız
# `$INSTALL_DIR/webpanel` altındaydı ve `webpanel doctor` gibi komutlar —
# panelin kendi hata mesajlarında önerilenler dahil — "command not found"
# veriyordu. Güncelleme eksik bağı kendiliğinden onarır. Bağ zaten doğru
# hedefi gösteriyorsa `ln -sfn` işlemsizdir; operatör başka bir şeye
# çevirdiyse dokunulmaz.
ensure_cli_link() {
    if [ -e "$CLI_LINK_PATH" ] && [ ! -L "$CLI_LINK_PATH" ]; then
        warn "$CLI_LINK_PATH bir sembolik bağ değil; CLI bağı güncellenmedi"
        return 0
    fi
    if [ -L "$CLI_LINK_PATH" ] && [ "$(readlink "$CLI_LINK_PATH")" != "$BIN" ]; then
        warn "$CLI_LINK_PATH başka bir hedefi gösteriyor; dokunulmadı"
        return 0
    fi
    install -d -m 0755 "$(dirname "$CLI_LINK_PATH")" 2>/dev/null || true
    ln -sfn "$BIN" "$CLI_LINK_PATH" 2>/dev/null ||
        warn "$CLI_LINK_PATH bağı oluşturulamadı"
}

restart_or_restore() {
    local previous="$INSTALL_DIR/releases/previous"
    if systemctl restart "$SERVICE_NAME" && health_check; then
        return 0
    fi
    warn "Yeni sürüm sağlık kontrolünü geçemedi; önceki sürüm geri yükleniyor"
    install_package_files "$previous" "$(tr -d '[:space:]' < "$previous/VERSION")"
    systemctl restart "$SERVICE_NAME" || true
    health_check || die "Önceki sürüm de sağlık kontrolünü geçemedi; journalctl -u $SERVICE_NAME inceleyin"
    return 1
}

update_command() {
    local requested="" allow_downgrade=0
    while [ "$#" -gt 0 ]; do
        case "$1" in
            --version)
                [ "$#" -ge 2 ] || die "--version bir değer ister"
                requested="$2"
                shift 2
                ;;
            --allow-downgrade) allow_downgrade=1; shift ;;
            *) die "Bilinmeyen güncelleme seçeneği: $1" ;;
        esac
    done
    local current target
    current="$(current_version)" || return
    if [ -n "$requested" ]; then
        target="$requested"
        validate_version "$target"
    else
        target="$(stable_version)" || return
    fi
    if [ "$current" = "$target" ]; then
        log "WebPanel zaten güncel: $current"
        return 0
    fi
    if version_is_older "$target" "$current" && [ "$allow_downgrade" != "1" ]; then
        die "$target, kurulu $current sürümünden eski; bilinçli düşürme için --allow-downgrade kullanın"
    fi
    fetch_package "$target" "$TMP_DIR/package"
    capture_current "$TMP_DIR/current" "$current"
    save_previous "$current" "$TMP_DIR/current"
    # Anlık görüntü, binary değişmeden ve yeni sürüm migration uygulamadan önce
    # alınır: şemanın güncelleme öncesi hâlini yakalar.
    snapshot_database
    log "$current → $target güncellemesi uygulanıyor"
    install_package_files "$TMP_DIR/package" "$target"
    if ! restart_or_restore; then
        die "Güncelleme geri alındı"
    fi
    log "WebPanel $target sürümüne güncellendi"
}

rollback_command() {
    local previous="$INSTALL_DIR/releases/previous"
    if [ ! -x "$previous/webpanel" ] || [ ! -r "$previous/VERSION" ]; then
        die "Geri dönülebilecek sürüm yok"
    fi
    local current target
    current="$(current_version)" || return
    target="$(tr -d '[:space:]' < "$previous/VERSION")" ||
        die "Geri dönüş sürümü okunamadı"
    validate_version "$target"
    capture_current "$TMP_DIR/current" "$current"
    log "$current → $target geri dönüşü uygulanıyor"
    install_package_files "$previous" "$target"
    if systemctl restart "$SERVICE_NAME" && health_check; then
        save_previous "$current" "$TMP_DIR/current"
        log "WebPanel $target sürümüne döndürüldü"
        return 0
    fi
    warn "Geri dönülen sürüm sağlık kontrolünü geçemedi; $current geri yükleniyor"
    install_package_files "$TMP_DIR/current" "$current"
    systemctl restart "$SERVICE_NAME" || true
    health_check || die "Servis geri yükleme sonrasında da sağlıksız"
    die "Geri dönüş uygulanamadı"
}

status_command() {
    local current previous="yok" stable="erişilemedi" stable_value
    current="$(current_version)" || return
    if [ -r "$INSTALL_DIR/releases/previous/VERSION" ]; then
        previous="$(tr -d '[:space:]' < "$INSTALL_DIR/releases/previous/VERSION")"
    fi
    if stable_value="$(stable_version 2>/dev/null)"; then
        stable="$stable_value"
    fi
    local snapshot="$INSTALL_DIR/releases/pre-update.db" snapshot_state="yok"
    if [ -f "$snapshot" ]; then
        snapshot_state="$snapshot"
    fi
    printf 'Kurulu sürüm  : %s\n' "$current"
    printf 'Kararlı sürüm : %s\n' "$stable"
    printf 'Geri dönüş    : %s\n' "$previous"
    printf 'DB anlık görüntüsü : %s\n' "$snapshot_state"
    local cli_state="yok (webpanel komutu PATH'te değil)"
    if [ -L "$CLI_LINK_PATH" ] && [ "$(readlink "$CLI_LINK_PATH")" = "$BIN" ]; then
        cli_state="$CLI_LINK_PATH"
    fi
    printf 'CLI bağı      : %s\n' "$cli_state"
    printf 'Servis        : %s\n' "$(systemctl is-active "$SERVICE_NAME" 2>/dev/null || true)"
}

check_command() {
    local current stable
    current="$(current_version)" || return
    stable="$(stable_version)" || return
    if [ "$current" = "$stable" ]; then
        log "WebPanel güncel: $current"
    else
        log "Yeni sürüm var: $current → $stable"
    fi
}

usage() {
    cat <<'EOF'
Kullanım:
  webpanel-update status
  webpanel-update check
  webpanel-update update [--version X.Y.Z] [--allow-downgrade]
  webpanel-update rollback

Güncelleme paketi SHA-256 ile doğrulanır. Yeni servis sağlık kontrolünü geçemezse
önceki binary ve bakım araçları otomatik olarak geri yüklenir.
EOF
}

if [ "$(id -u)" -ne 0 ]; then
    die "Bu komut root olarak çalıştırılmalı (sudo)."
fi
for command in awk bash curl flock grep head install mkdir mv realpath rm sed seq sha256sum sort stat systemctl tar tr; do
    require_command "$command"
done
[ "$(uname -s)" = "Linux" ] || die "Yalnızca Linux destekleniyor"
case "$(uname -m)" in x86_64 | amd64) ;; *) die "Desteklenmeyen mimari: $(uname -m)" ;; esac

load_config
validate_absolute_path "Kurulum dizini" "$INSTALL_DIR"
validate_absolute_path "Binary yolu" "$BIN"
validate_absolute_path "Güncelleyici yolu" "$UPDATER_PATH"
validate_absolute_path "Kaldırıcı yolu" "$UNINSTALLER_PATH"
case "$INSTALL_DIR" in / | /opt | /usr | /usr/local | /var | /var/lib | /etc | /root | /home)
    die "Kurulum dizini fazla geniş: $INSTALL_DIR" ;;
esac
[ "$BIN" = "$INSTALL_DIR/webpanel" ] || die "Binary kurulum dizini altında webpanel olmalı"
[ "$UPDATER_PATH" = "/usr/local/sbin/$SERVICE_NAME-update" ] || die "Güncelleyici yolu servis adıyla eşleşmiyor"
[ "$UNINSTALLER_PATH" = "/usr/local/sbin/$SERVICE_NAME-uninstall" ] || die "Kaldırıcı yolu servis adıyla eşleşmiyor"
[[ "$SERVICE_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_.@-]*$ ]] || die "Geçersiz servis adı"
if ! [[ "$PORT" =~ ^[0-9]+$ ]] || [ "$PORT" -lt 1 ] || [ "$PORT" -gt 65535 ]; then
    die "Geçersiz panel portu"
fi
case "$ALLOW_INSECURE" in 0 | 1) ;; *) die "WEBPANEL_ALLOW_INSECURE 0 veya 1 olmalı" ;; esac

TMP_DIR="$(mktemp -d -t webpanel-update.XXXXXXXX)"
load_download_token
prepare_download_auth
COMMAND="${1:-update}"
if [ "$#" -gt 0 ]; then shift; fi

case "$COMMAND" in
    status) status_command "$@" ;;
    check) check_command "$@" ;;
    update)
        exec 9>"/run/lock/$SERVICE_NAME-update.lock"
        flock -n 9 || die "Başka bir WebPanel güncelleme işlemi çalışıyor"
        update_command "$@"
        ;;
    rollback)
        exec 9>"/run/lock/$SERVICE_NAME-update.lock"
        flock -n 9 || die "Başka bir WebPanel güncelleme işlemi çalışıyor"
        rollback_command "$@"
        ;;
    -h | --help | help) usage ;;
    *) usage >&2; die "Bilinmeyen komut: $COMMAND" ;;
esac
