#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'

readonly SCRIPT_VERSION="1.3.3"
readonly BASE_DIR="/opt/docker"
readonly STATE_FILE="${BASE_DIR}/.vps-setup.env"
readonly LOG_FILE="/var/log/vps-setup.log"
readonly PROXY_NETWORK="proxy"
readonly TZ_VALUE="${TZ:-Europe/Budapest}"

readonly NPM_DIR="${BASE_DIR}/nginx-proxy-manager"
readonly HOMEPAGE_DIR="${BASE_DIR}/homepage"
readonly DOCKHAND_DIR="${BASE_DIR}/dockhand"
readonly THELOUNGE_DIR="${BASE_DIR}/thelounge"
readonly BESZEL_DIR="${BASE_DIR}/beszel"

readonly NPM_HTTP_PORT=80
readonly NPM_HTTPS_PORT=443
readonly NPM_ADMIN_PORT=81
readonly HOMEPAGE_PORT=3000
readonly DOCKHAND_PORT=3001
readonly THELOUNGE_PORT=9000
readonly THELOUNGE_IDENT_PORT=113
readonly BESZEL_PORT=8090

SERVER_ADDRESS=""

if [[ "${LC_ALL:-${LANG:-}}" != *UTF-8* && "${LC_ALL:-${LANG:-}}" != *utf8* ]]; then
  export LC_ALL=C.UTF-8
fi

if [[ -t 1 ]]; then
  readonly C_RESET=$'\033[0m'
  readonly C_BOLD=$'\033[1m'
  readonly C_CYAN=$'\033[36m'
  readonly C_GREEN=$'\033[32m'
  readonly C_YELLOW=$'\033[33m'
  readonly C_RED=$'\033[31m'
else
  readonly C_RESET=""
  readonly C_BOLD=""
  readonly C_CYAN=""
  readonly C_GREEN=""
  readonly C_YELLOW=""
  readonly C_RED=""
fi

terminal_size() {
  local rows=0 cols=0 size
  size="$(stty size 2>/dev/null || true)"
  if [[ -n "$size" ]]; then
    IFS=' ' read -r rows cols <<<"$size"
  fi
  if [[ ! "$cols" =~ ^[0-9]+$ ]] || (( cols < 20 )); then
    cols="${COLUMNS:-80}"
  fi
  if [[ ! "$rows" =~ ^[0-9]+$ ]] || (( rows < 10 )); then
    rows="${LINES:-24}"
  fi
  if [[ ! "$cols" =~ ^[0-9]+$ ]] || (( cols < 20 )); then
    cols=20
  fi
  if [[ ! "$rows" =~ ^[0-9]+$ ]] || (( rows < 10 )); then
    rows=10
  fi
  printf '%s %s\n' "$rows" "$cols"
}

terminal_cols() {
  local rows cols
  IFS=' ' read -r rows cols <<<"$(terminal_size)"
  printf '%s' "$cols"
}

is_narrow() {
  (( $(terminal_cols) < 60 ))
}

print_kv() {
  local label="$1"
  local value="$2"
  if is_narrow; then
    printf '  %s: %s\n' "$label" "$value"
  else
    printf '  %-26s %s\n' "$label" "$value"
  fi
}

step() {
  printf '\n%s%s➜ %s%s\n' "$C_BOLD" "$C_CYAN" "$*" "$C_RESET"
}

ok() {
  printf '  %s✔%s %s\n' "$C_GREEN" "$C_RESET" "$*"
}

warn() {
  printf '  %s▲%s %s\n' "$C_YELLOW" "$C_RESET" "$*"
}

err() {
  printf '  %s✖%s %s\n' "$C_RED" "$C_RESET" "$*" >&2
}

die() {
  err "$*"
  printf '  Log: %s\n' "$LOG_FILE" >&2
  exit 1
}

print_banner() {
  printf '\n%s' "$C_CYAN"
  cat <<'BANNER'
  ==================================
     VPS TELEPÍTŐ  ·  Debian 13
  ==================================
     Docker · NPM · Dockhand
     The Lounge · Homepage · Beszel
BANNER
  printf '%s' "$C_RESET"
  printf '  Verzió: %s\n' "$SCRIPT_VERSION"
}

init_log() {
  mkdir -p "$(dirname "$LOG_FILE")"
  touch "$LOG_FILE"
  chmod 600 "$LOG_FILE"
}

log() {
  printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG_FILE"
}

on_error() {
  local rc="${1:-1}"
  trap - ERR
  err "Váratlan hiba történt (kilépési kód: ${rc})."
  if [[ -f "$LOG_FILE" ]]; then
    printf '  A részletek itt vannak: %s\n' "$LOG_FILE" >&2
  fi
  exit "$rc"
}

wt() {
  local -a args=("$@")
  local i box=-1 rows cols max_h max_w h w l
  for i in "${!args[@]}"; do
    case "${args[$i]}" in
      --menu|--checklist|--inputbox|--yesno|--msgbox)
        box=$i
        break
        ;;
    esac
  done
  IFS=' ' read -r rows cols <<<"$(terminal_size)"
  max_w=$((cols - 2))
  max_h=$((rows - 1))
  (( max_w < 20 )) && max_w=20
  (( max_h < 8 )) && max_h=8
  if (( box >= 0 )); then
    h="${args[box+2]}"
    w="${args[box+3]}"
    if [[ "$w" =~ ^[0-9]+$ ]] && (( w > max_w )); then
      args[box+3]="$max_w"
    fi
    if [[ "$h" =~ ^[0-9]+$ ]] && (( h > max_h )); then
      args[box+2]="$max_h"
      h="$max_h"
    fi
    case "${args[$box]}" in
      --menu|--checklist)
        l="${args[box+4]}"
        if [[ "$l" =~ ^[0-9]+$ ]]; then
          if (( l > h - 6 )); then
            args[box+4]=$((h - 6))
          fi
          if (( args[box+4] < 2 )); then
            args[box+4]=2
          fi
        fi
        ;;
    esac
  fi
  local -a wargs=(--backtitle "VPS telepítő")
  if (( box >= 0 )); then
    case "${args[$box]}" in
      --menu|--checklist) ;;
      *) wargs+=(--scrolltext) ;;
    esac
  else
    wargs+=(--scrolltext)
  fi
  whiptail "${wargs[@]}" "${args[@]}" 3>&1 1>&2 2>&3
}

trim() {
  local value="$1"
  value="${value#"${value%%[![:space:]]*}"}"
  value="${value%"${value##*[![:space:]]}"}"
  printf '%s' "$value"
}

spinner() {
  local pid="$1"
  local label="$2"
  local -a frames=('|' '/' '-' "\\")
  local i=0
  while kill -0 "$pid" 2>/dev/null; do
    printf '\r  %s%s%s %s' "$C_CYAN" "${frames[$((i % 4))]}" "$C_RESET" "$label" >&2
    i=$((i + 1))
    sleep 0.1
  done
  printf '\r\033[K' >&2
}

run_logged() {
  local desc="$1"
  shift
  log "START: ${desc} :: $*"
  "$@" >>"$LOG_FILE" 2>&1 &
  local pid=$!
  if [[ -t 1 ]]; then
    spinner "$pid" "$desc"
  fi
  local rc=0
  wait "$pid" || rc=$?
  if (( rc == 0 )); then
    log "OK: ${desc}"
    ok "$desc"
  else
    log "FAIL(${rc}): ${desc}"
    err "${desc} – hiba (kilépési kód: ${rc})"
    printf '  Utolsó log sorok:\n' >&2
    tail -n 20 "$LOG_FILE" | sed 's/^/    /' >&2 || true
    return "$rc"
  fi
}

require_root() {
  if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
    die "Root jogosultság szükséges. Futtasd így: sudo bash $0"
  fi
}

require_tty() {
  if [[ ! -t 0 || ! -t 1 ]]; then
    die "Interaktív terminál szükséges. Ne pipából futtasd, hanem: sudo bash $0"
  fi
}

check_os() {
  if [[ ! -r /etc/os-release ]]; then
    die "Nem található a /etc/os-release."
  fi
  local os_id os_version os_pretty
  os_id="$(awk -F= '$1 == "ID" { gsub(/"/, "", $2); print $2 }' /etc/os-release)"
  os_version="$(awk -F= '$1 == "VERSION_ID" { gsub(/"/, "", $2); print $2 }' /etc/os-release)"
  os_pretty="$(awk -F= '$1 == "PRETTY_NAME" { sub(/^[^=]*=/, ""); gsub(/^"|"$/, ""); print }' /etc/os-release)"
  if [[ "$os_id" != "debian" ]]; then
    die "Ez a script Debian 13-hoz készült (talált rendszer: ${os_pretty:-ismeretlen})."
  fi
  if [[ "$os_version" != "13" ]]; then
    warn "A rendszer Debian ${os_version:-?}, nem 13. A script Debian 13-ra lett tervezve."
    local answer
    read -r -p "  Folytatod? [i/N] " answer || exit 0
    if [[ ! "$answer" =~ ^[iI]$ ]]; then
      exit 0
    fi
  fi
}

install_prereqs() {
  step "Előfeltételek"
  export DEBIAN_FRONTEND=noninteractive
  run_logged "Csomaglista frissítése" apt-get update
  local pkgs=()
  command -v curl >/dev/null 2>&1 || pkgs+=("curl")
  command -v whiptail >/dev/null 2>&1 || pkgs+=("whiptail")
  command -v ss >/dev/null 2>&1 || pkgs+=("iproute2")
  command -v cmp >/dev/null 2>&1 || pkgs+=("diffutils")
  dpkg -s ca-certificates >/dev/null 2>&1 || pkgs+=("ca-certificates")
  if (( ${#pkgs[@]} > 0 )); then
    run_logged "Hiányzó csomagok telepítése (${pkgs[*]})" apt-get install -y --no-install-recommends "${pkgs[@]}"
  else
    ok "Minden szükséges csomag telepítve van."
  fi
}

install_docker() {
  step "Docker ellenőrzése"
  if command -v docker >/dev/null 2>&1; then
    ok "Docker már telepítve: $(docker --version 2>/dev/null | head -n1)"
  else
    run_logged "Docker telepítése (hivatalos get.docker.com)" bash -c 'set -o pipefail; curl -fsSL https://get.docker.com | sh'
  fi
  if command -v systemctl >/dev/null 2>&1; then
    if ! systemctl is-active --quiet docker 2>/dev/null; then
      run_logged "Docker szolgáltatás indítása" systemctl enable --now docker || \
        run_logged "Docker szolgáltatás indítása (service)" service docker start
    fi
  else
    run_logged "Docker szolgáltatás indítása" service docker start
  fi
  if ! docker compose version >/dev/null 2>&1; then
    run_logged "Docker Compose plugin telepítése" apt-get install -y docker-compose-plugin
  fi
  if ! docker info >/dev/null 2>&1; then
    die "A Docker daemon nem érhető el."
  fi
  local compose_version
  compose_version="$(docker compose version --short 2>/dev/null || true)"
  ok "Docker Compose: ${compose_version:-telepítve}"
}

ensure_network() {
  step "Docker hálózat"
  if docker network inspect "$PROXY_NETWORK" >/dev/null 2>&1; then
    ok "A(z) ${PROXY_NETWORK} hálózat már létezik."
  else
    run_logged "Közös hálózat létrehozása (${PROXY_NETWORK})" docker network create "$PROXY_NETWORK"
  fi
}

detect_ip() {
  local ip
  ip="$(hostname -I 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { print $i; exit } }')"
  printf '%s' "${ip:-127.0.0.1}"
}

read_state() {
  local key="$1"
  if [[ ! -f "$STATE_FILE" ]]; then
    return 0
  fi
  awk -F= -v k="$key" '$1 == k { sub(/^[^=]*=/, ""); print; exit }' "$STATE_FILE"
}

write_state() {
  local addr="$1"
  mkdir -p "$BASE_DIR"
  ( umask 022; printf 'SERVER_ADDRESS=%s\n' "$addr" >"$STATE_FILE" )
}

port_in_use() {
  local port="$1"
  [[ -n "$(ss -ltnH "sport = :${port}" 2>/dev/null)" ]]
}

port_used_by_our_container() {
  local port="$1"
  local name ports
  while IFS=$'\t' read -r name ports; do
    case "$name" in
      nginx-proxy-manager|homepage|dockhand|thelounge|beszel) ;;
      *) continue ;;
    esac
    if [[ "$ports" == *":${port}->"* ]]; then
      return 0
    fi
  done < <(docker ps --format '{{.Names}}\t{{.Ports}}' 2>/dev/null)
  return 1
}

check_ports() {
  local used=()
  local p
  for p in "$@"; do
    if port_in_use "$p" && ! port_used_by_our_container "$p"; then
      used+=("$p")
    fi
  done
  if (( ${#used[@]} == 0 )); then
    ok "A szükséges portok szabadok."
    return 0
  fi
  warn "Foglalt portok: ${used[*]}"
  if ! wt --title "Portütközés" --yesno "A következő portok már foglaltak:\n\n${used[*]}\n\nA telepítés valószínűleg sikertelen lesz. Folytatod?" 14 70; then
    return 1
  fi
}

backup_file() {
  local file="$1"
  local backup
  if [[ ! -f "$file" ]]; then
    return 0
  fi
  backup="${file}.bak.$(date '+%Y%m%d-%H%M%S')"
  while [[ -e "$backup" ]]; do
    backup="${file}.bak.$(date '+%Y%m%d-%H%M%S')-${RANDOM}"
  done
  cp -a "$file" "$backup"
  log "BACKUP: ${backup}"
  printf '  %sMentve:%s %s\n' "$C_CYAN" "$C_RESET" "$backup"
}

write_compose() {
  local dir="$1"
  local tmp
  mkdir -p "$dir"
  tmp="$(mktemp)"
  cat >"$tmp"
  if [[ -f "${dir}/compose.yaml" ]] && cmp -s "$tmp" "${dir}/compose.yaml"; then
    rm -f "$tmp"
    ok "Compose változatlan: ${dir}/compose.yaml"
    return 0
  fi
  if [[ -f "${dir}/compose.yaml" ]]; then
    backup_file "${dir}/compose.yaml"
  fi
  install -m 0644 "$tmp" "${dir}/compose.yaml"
  rm -f "$tmp"
  ok "Compose fájl kiírva: ${dir}/compose.yaml"
}

compose_cmd() {
  local dir="$1"
  shift
  ( cd "$dir" || return 1; docker compose "$@" )
}

compose_validate() {
  local dir="$1"
  shift
  log "VALIDATE: ${dir}"
  if ! ( cd "$dir" || return 1; docker compose "$@" config -q ) >>"$LOG_FILE" 2>&1; then
    err "Hibás compose konfiguráció: ${dir}/compose.yaml"
    tail -n 20 "$LOG_FILE" | sed 's/^/    /' >&2 || true
    return 1
  fi
  ok "Compose konfiguráció érvényes."
}

compose_up() {
  local dir="$1"
  shift
  local name
  name="$(basename "$dir")"
  run_logged "Konténerek indítása (${name})" compose_cmd "$dir" up -d "$@"
}

wait_for_http() {
  local name="$1"
  local port="$2"
  local timeout="${3:-120}"
  local container="${4:-}"
  local deadline=$((SECONDS + timeout))
  local code
  while (( SECONDS < deadline )); do
    code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 "http://127.0.0.1:${port}/" 2>/dev/null || true)"
    if [[ "$code" =~ ^[1-4][0-9][0-9]$ ]]; then
      ok "${name} elérhető (127.0.0.1:${port}, HTTP ${code})."
      return 0
    fi
    sleep 2
  done
  warn "${name} nem válaszolt ${timeout} másodpercen belül."
  if [[ -n "$container" ]] && docker inspect "$container" >/dev/null 2>&1; then
    printf '  Legutóbbi konténer logok:\n' >&2
    docker logs --tail 20 "$container" 2>&1 | sed 's/^/    /' >&2 || true
  fi
  return 1
}

env_get() {
  local file="$1"
  local key="$2"
  if [[ ! -f "$file" ]]; then
    return 0
  fi
  awk -F= -v k="$key" '$1 == k { sub(/^[^=]*=/, ""); print; exit }' "$file"
}

ensure_beszel_env() {
  local file="${BESZEL_DIR}/.env"
  if [[ ! -f "$file" ]]; then
    ( umask 077; printf 'BESZEL_KEY=\nBESZEL_TOKEN=\n' >"$file" )
    ok "Beszel .env létrehozva."
  fi
  chown 1001:1001 "$file" 2>/dev/null || warn "Nem sikerült a Beszel .env tulajdonjogának beállítása."
  chmod 600 "$file" 2>/dev/null || true
}

install_npm() {
  step "Nginx Proxy Manager"
  local dir="$NPM_DIR"
  mkdir -p "${dir}/data" "${dir}/letsencrypt"
  write_compose "$dir" <<EOF
services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "${NPM_HTTP_PORT}:80"
      - "${NPM_HTTPS_PORT}:443"
      - "${NPM_ADMIN_PORT}:81"
    environment:
      TZ: "${TZ_VALUE}"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy

networks:
  proxy:
    external: true
EOF
  compose_validate "$dir" || return 1
  compose_up "$dir" || return 1
  wait_for_http "Nginx Proxy Manager" "$NPM_ADMIN_PORT" 180 "nginx-proxy-manager" || true
}

homepage_other_services_present() {
  [[ -f "${NPM_DIR}/compose.yaml" || -f "${DOCKHAND_DIR}/compose.yaml" || -f "${THELOUNGE_DIR}/compose.yaml" || -f "${BESZEL_DIR}/compose.yaml" ]]
}

seed_homepage_dashboard() {
  local file="${HOMEPAGE_DIR}/config/services.yaml"
  local tmp
  if ! homepage_other_services_present; then
    mkdir -p "${HOMEPAGE_DIR}/config"
    printf '[]\n' >"$file"
    chmod 0644 "$file"
    ok "Homepage üres dashboard létrehozva: ${file}"
    return 0
  fi
  tmp="$(mktemp)"
  {
    if [[ -f "${NPM_DIR}/compose.yaml" || -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
      printf '%s\n' '- ⚙️ Kezelés:'
      if [[ -f "${NPM_DIR}/compose.yaml" ]]; then
        printf '    - Nginx Proxy Manager:\n'
        printf '        icon: nginx-proxy-manager.png\n'
        printf '        href: "http://%s:%s"\n' "$SERVER_ADDRESS" "$NPM_ADMIN_PORT"
        printf '        description: "Reverse proxy és SSL"\n'
        printf '        siteMonitor: "http://npm:81"\n'
        printf '        statusStyle: dot\n'
      fi
      if [[ -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
        printf '    - Dockhand:\n'
        printf '        icon: dockhand.png\n'
        printf '        href: "http://%s:%s"\n' "$SERVER_ADDRESS" "$DOCKHAND_PORT"
        printf '        description: "Docker kezelés"\n'
        printf '        siteMonitor: "http://dockhand:3000"\n'
        printf '        statusStyle: dot\n'
      fi
    fi
    if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
      printf '%s\n' '- 📊 Monitorozás:'
      printf '    - Beszel:\n'
      printf '        icon: beszel.png\n'
      printf '        href: "http://%s:%s"\n' "$SERVER_ADDRESS" "$BESZEL_PORT"
      printf '        description: "Rendszer-monitoring"\n'
      printf '        siteMonitor: "http://beszel:8090"\n'
      printf '        statusStyle: dot\n'
    fi
    if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
      printf '%s\n' '- 💬 Kommunikáció:'
      printf '    - The Lounge:\n'
      printf '        icon: thelounge.png\n'
      printf '        href: "http://%s:%s"\n' "$SERVER_ADDRESS" "$THELOUNGE_PORT"
      printf '        description: "IRC kliens"\n'
      printf '        siteMonitor: "http://thelounge:9000"\n'
      printf '        statusStyle: dot\n'
    fi
  } >"$tmp"
  if [[ ! -s "$tmp" ]]; then
    rm -f "$tmp"
    return 0
  fi
  mkdir -p "${HOMEPAGE_DIR}/config"
  install -m 0644 "$tmp" "$file"
  rm -f "$tmp"
  ok "Homepage alap dashboard létrehozva: ${file}"
}

seed_homepage_settings() {
  local file="${HOMEPAGE_DIR}/config/settings.yaml"
  local tmp
  tmp="$(mktemp)"
  cat >"$tmp" <<'EOF'
title: "VPS Vezérlőpult"
theme: dark
color: slate
language: hu
statusStyle: dot
headerStyle: boxed
cardStyle: hairline
cardBlur: md
useEqualHeights: true
fullWidth: true
target: _blank
font: plexData
background:
  image: https://images.unsplash.com/photo-1419242902214-272b3f66ee7a?auto=format&fit=crop&w=1920&q=80
  opacity: 30
quicklaunch:
  searchDescriptions: true
  showSearchSuggestions: true
  provider: google
EOF
  mkdir -p "${HOMEPAGE_DIR}/config"
  install -m 0644 "$tmp" "$file"
  rm -f "$tmp"
  ok "Homepage megjelenés létrehozva: ${file}"
}

seed_homepage_bookmarks() {
  local file="${HOMEPAGE_DIR}/config/bookmarks.yaml"
  mkdir -p "${HOMEPAGE_DIR}/config"
  printf '[]\n' >"$file"
  chmod 0644 "$file"
  ok "Homepage bookmarks létrehozva: ${file}"
}

seed_homepage_widgets() {
  local file="${HOMEPAGE_DIR}/config/widgets.yaml"
  mkdir -p "${HOMEPAGE_DIR}/config"
  cat >"$file" <<'EOF'
- resources:
    cpu: true
    memory: true
    disk: /
    uptime: true
- search:
    provider: google
    target: _blank
- openmeteo:
    label: Szolnok
    latitude: 47.17467
    longitude: 20.19649
    timezone: Europe/Budapest
    units: metric
    cache: 5
- greeting:
    text_size: xl
    text: "Üdv a VPS Vezérlőpulton!"
- datetime:
    text_size: sm
    locale: hu
    format:
      dateStyle: short
      timeStyle: short
EOF
  chmod 0644 "$file"
  ok "Homepage widgetek létrehozva (uptime + időjárás): ${file}"
}

render_homepage_compose() {
  local dir="$HOMEPAGE_DIR"
  mkdir -p "${dir}/config"
  write_compose "$dir" <<EOF
services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    restart: unless-stopped
    ports:
      - "${HOMEPAGE_PORT}:3000"
    environment:
      TZ: "${TZ_VALUE}"
      HOMEPAGE_ALLOWED_HOSTS: "*"
    volumes:
      - ./config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

networks:
  proxy:
    external: true
EOF
}

apply_homepage_compose() {
  local dir="$HOMEPAGE_DIR"
  render_homepage_compose || return 1
  compose_validate "$dir" || return 1
  compose_up "$dir" || return 1
  wait_for_http "Homepage" "$HOMEPAGE_PORT" 120 "homepage" || true
}

install_homepage() {
  step "Homepage"
  mkdir -p "${HOMEPAGE_DIR}/config"
  seed_homepage_dashboard
  seed_homepage_settings
  seed_homepage_bookmarks
  seed_homepage_widgets
  apply_homepage_compose
}

install_dockhand() {
  step "Dockhand"
  local dir="$DOCKHAND_DIR"
  local data="${dir}/data"
  mkdir -p "$data"
  chown -R 1001:1001 "$data" 2>/dev/null || warn "A Dockhand data tulajdonjogát nem sikerült beállítani."
  write_compose "$dir" <<EOF
services:
  dockhand:
    image: fnsys/dockhand:latest
    container_name: dockhand
    restart: unless-stopped
    ports:
      - "${DOCKHAND_PORT}:3000"
    environment:
      DATA_DIR: "${data}"
      TZ: "${TZ_VALUE}"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - "${NPM_DIR}:${NPM_DIR}"
      - "${HOMEPAGE_DIR}:${HOMEPAGE_DIR}"
      - "${THELOUNGE_DIR}:${THELOUNGE_DIR}"
      - "${BESZEL_DIR}:${BESZEL_DIR}"
      - "${data}:${data}"
    networks:
      - proxy

networks:
  proxy:
    external: true
EOF
  compose_validate "$dir" || return 1
  compose_up "$dir" || return 1
  wait_for_http "Dockhand" "$DOCKHAND_PORT" 120 "dockhand" || true
}

make_stacks_adoptable() {
  local d
  for d in "$NPM_DIR" "$HOMEPAGE_DIR" "$THELOUNGE_DIR" "$BESZEL_DIR"; do
    if [[ -f "${d}/compose.yaml" ]]; then
      chown 1001:1001 "$d" "${d}/compose.yaml" 2>/dev/null || warn "Nem sikerült a Dockhand adoptálási jogosultság beállítása: ${d}"
    fi
  done
  if [[ -f "${BESZEL_DIR}/.env" ]]; then
    chown 1001:1001 "${BESZEL_DIR}/.env" 2>/dev/null || warn "Nem sikerült a Beszel .env tulajdonjogának beállítása."
    chmod 600 "${BESZEL_DIR}/.env"
  fi
}

install_thelounge() {
  step "The Lounge"
  local dir="$THELOUNGE_DIR"
  mkdir -p "${dir}/data"
  chown -R 1000:1000 "${dir}/data" 2>/dev/null || warn "A The Lounge data tulajdonjogát nem sikerült beállítani."
  local cfg="${dir}/data/config.js"
  if [[ ! -f "$cfg" ]]; then
    cat >"$cfg" <<'EOF'
"use strict";

module.exports = {
  identd: {
    enable: true,
    port: 9001,
  },
};
EOF
    chown 1000:1000 "$cfg"
    ok "The Lounge identd beállítás létrehozva: ${cfg}"
  fi
  write_compose "$dir" <<EOF
services:
  thelounge:
    image: ghcr.io/thelounge/thelounge:latest
    container_name: thelounge
    restart: unless-stopped
    ports:
      - "${THELOUNGE_PORT}:9000"
      - "${THELOUNGE_IDENT_PORT}:9001"
    environment:
      TZ: "${TZ_VALUE}"
    volumes:
      - ./data:/var/opt/thelounge
    networks:
      - proxy

networks:
  proxy:
    external: true
EOF
  compose_validate "$dir" || return 1
  compose_up "$dir" || return 1
  wait_for_http "The Lounge" "$THELOUNGE_PORT" 120 "thelounge" || true
}

print_beszel_instructions() {
  cat <<EOF

  ${C_BOLD}Beszel Hub és a helyi agent összekötése${C_RESET}

  1. Nyisd meg a Hubot: ${C_CYAN}http://${SERVER_ADDRESS}:${BESZEL_PORT}${C_RESET}
  2. Hozd létre az admin fiókot, ha még nincs.
  3. Kattints az ${C_BOLD}Add System${C_RESET} gombra.
  4. Host / IP: ${C_CYAN}/beszel_socket/beszel.sock${C_RESET}
     A port mezőt hagyd az alapértelmezett értéken.
  5. Az Add System ablakban megjelenő compose-részletből másold ki
     a ${C_BOLD}KEY${C_RESET} és ${C_BOLD}TOKEN${C_RESET} értékeket.
  6. Ne zárd be az ablakot, amíg a script el nem indítja az agentet.
  7. Térj vissza ide, és illeszd be a két értéket.

EOF
}

setup_beszel_agent() {
  local dir="$BESZEL_DIR"
  local env_file="${dir}/.env"
  if [[ ! -f "${dir}/compose.yaml" ]]; then
    wt --title "Beszel" --msgbox "A Beszel Hub még nincs telepítve.\n\nElőször futtasd a Telepítés menüpontot." 11 68
    return 0
  fi
  ensure_beszel_env

  local key token
  key="$(env_get "$env_file" BESZEL_KEY)"
  token="$(env_get "$env_file" BESZEL_TOKEN)"
  if [[ -n "$key" && -n "$token" ]]; then
    if ! wt --title "Beszel agent" --yesno "A Beszel agent már be van állítva.\n\nSzeretnéd felülírni a KEY/TOKEN értékeket?" 12 70; then
      ok "Meglévő Beszel beállítás megtartva."
      run_logged "Beszel agent indítása" compose_cmd "$dir" --profile agent up -d beszel-agent || true
      return 0
    fi
  fi

  print_beszel_instructions
  read -r -p "  Ha kész vagy, nyomj Entert..." _ || return 0

  local new_key new_token
  read -r -p "  KEY (üres = kihagyás): " new_key || return 0
  new_key="$(trim "${new_key//$'\r'/}")"
  if [[ -z "$new_key" ]]; then
      warn "A Beszel agent beállítása kihagyva."
      printf '  Később a főmenü Beszel agent pontjával állíthatod be.\n'
    return 0
  fi
  while true; do
    read -r -s -p "  TOKEN (nem látszik): " new_token || { printf '\n'; return 0; }
    printf '\n'
    new_token="$(trim "${new_token//$'\r'/}")"
    if [[ -n "$new_token" ]]; then
      break
    fi
    warn "A TOKEN nem lehet üres. Próbáld újra."
  done

  ( umask 077; printf 'BESZEL_KEY=%s\nBESZEL_TOKEN=%s\nCOMPOSE_PROFILES=agent\n' "$new_key" "$new_token" >"$env_file" )
  chmod 600 "$env_file"
  chown 1001:1001 "$env_file" 2>/dev/null || warn "Nem sikerült a Beszel .env tulajdonjogának beállítása."
  ok "Beszel KEY/TOKEN elmentve."

  compose_validate "$dir" --profile agent || die "A Beszel compose konfiguráció érvénytelen."
  run_logged "Beszel agent indítása" compose_cmd "$dir" --profile agent up -d beszel-agent || die "A Beszel agent nem indult el."
  sleep 2
  if [[ "$(docker inspect -f '{{.State.Running}}' beszel-agent 2>/dev/null || true)" == "true" ]]; then
    ok "A Beszel agent fut."
    printf '  Most kattints az %sAdd System%s gombra a Beszel Hubban.\n' "$C_BOLD" "$C_RESET"
  else
    warn "A Beszel agent nem fut. Ellenőrizd: docker logs beszel-agent"
  fi
}

install_beszel() {
  step "Beszel Hub"
  local dir="$BESZEL_DIR"
  mkdir -p "${dir}/beszel_data" "${dir}/beszel_socket" "${dir}/beszel_agent_data"
  ensure_beszel_env
  write_compose "$dir" <<EOF
services:
  beszel:
    image: henrygd/beszel:latest
    container_name: beszel
    restart: unless-stopped
    environment:
      APP_URL: "http://${SERVER_ADDRESS}:${BESZEL_PORT}"
      TZ: "${TZ_VALUE}"
    ports:
      - "${BESZEL_PORT}:8090"
    volumes:
      - ./beszel_data:/beszel_data
      - ./beszel_socket:/beszel_socket
    networks:
      - proxy

  beszel-agent:
    image: henrygd/beszel-agent:latest
    container_name: beszel-agent
    restart: unless-stopped
    profiles:
      - agent
    network_mode: host
    depends_on:
      - beszel
    volumes:
      - ./beszel_agent_data:/var/lib/beszel-agent
      - ./beszel_socket:/beszel_socket
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      LISTEN: /beszel_socket/beszel.sock
      HUB_URL: http://127.0.0.1:8090
      KEY: \${BESZEL_KEY}
      TOKEN: \${BESZEL_TOKEN}

networks:
  proxy:
    external: true
EOF
  compose_validate "$dir" || return 1
  compose_up "$dir" beszel || return 1
  wait_for_http "Beszel Hub" "$BESZEL_PORT" 120 "beszel" || true
  setup_beszel_agent
}

print_summary() {
  local addr="$SERVER_ADDRESS"
  local npm_installed=0
  step "Telepítés összefoglaló"

  if [[ -f "${NPM_DIR}/compose.yaml" ]]; then
    npm_installed=1
    print_kv "Nginx Proxy Manager" "http://${addr}:${NPM_ADMIN_PORT}"
  fi
  if [[ -f "${HOMEPAGE_DIR}/compose.yaml" ]]; then
    print_kv "Homepage" "http://${addr}:${HOMEPAGE_PORT}"
  fi
  if [[ -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
    print_kv "Dockhand" "http://${addr}:${DOCKHAND_PORT}"
  fi
  if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
    print_kv "The Lounge" "http://${addr}:${THELOUNGE_PORT}"
  fi
  if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
    print_kv "Beszel Hub" "http://${addr}:${BESZEL_PORT}"
  fi

  if (( npm_installed )); then
    printf '\n  %sNPM belső célok%s (Proxy Host → Forward Hostname / Port):\n' "$C_BOLD" "$C_RESET"
    if [[ -f "${HOMEPAGE_DIR}/compose.yaml" ]]; then
      printf '    Homepage → homepage:3000\n'
    fi
    if [[ -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
      printf '    Dockhand → dockhand:3000\n'
    fi
    if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
      printf '    The Lounge → thelounge:9000\n'
    fi
    if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
      printf '    Beszel → beszel:8090\n'
    fi
    printf '  Az NPM első megnyitásakor a setup wizardban hozd létre az admin fiókot.\n'
    printf '  A proxy hostokat és az SSL-t kézzel állítod be.\n'
    printf '  Beszel Hub domain/HTTPS esetén az APP_URL-t frissíteni kell.\n'
  fi

  if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
    printf '\n  The Lounge felhasználó létrehozása:\n'
    printf '    docker exec --user node -it thelounge thelounge add felhasznalonev\n'
    printf '  The Lounge identd: %s (engedélyezve)\n' "$THELOUNGE_IDENT_PORT"
    printf '  Identhez a %s/TCP portnak nyitva kell lennie (az IRC szerverek ezt kérdezik).\n' "$THELOUNGE_IDENT_PORT"
  fi

  if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
    local beszel_key beszel_token
    beszel_key="$(env_get "${BESZEL_DIR}/.env" BESZEL_KEY)"
    beszel_token="$(env_get "${BESZEL_DIR}/.env" BESZEL_TOKEN)"
    printf '\n  Beszel agent socket: /beszel_socket/beszel.sock\n'
    if [[ -n "$beszel_key" && -n "$beszel_token" ]]; then
      printf '  Beszel agent: beállítva\n'
    else
      printf '  Beszel agent: nincs beállítva (főmenü → Beszel agent)\n'
    fi
  fi

  if [[ -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
    printf '\n  %sDockhand adoptálás%s (Stacks → Adopt → Browse):\n' "$C_BOLD" "$C_RESET"
    if [[ -f "${NPM_DIR}/compose.yaml" ]]; then
      printf '    NPM: %s\n' "${NPM_DIR}/compose.yaml"
    fi
    if [[ -f "${HOMEPAGE_DIR}/compose.yaml" ]]; then
      printf '    Homepage: %s\n' "${HOMEPAGE_DIR}/compose.yaml"
    fi
    if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
      printf '    The Lounge: %s\n' "${THELOUNGE_DIR}/compose.yaml"
    fi
    if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
      printf '    Beszel: %s + %s\n' "${BESZEL_DIR}/compose.yaml" "${BESZEL_DIR}/.env"
    fi
    printf '    A Dockhand saját stackjét ne adoptáld.\n'
  fi

  printf '\n  %sFontos:%s\n' "$C_YELLOW" "$C_RESET"
  printf '    - A portok publikusan figyelnek; használj tűzfalat, és te állítod be az NPM SSL-t.\n'
  printf '    - A Homepage Host-ellenőrzése ki van kapcsolva (HOMEPAGE_ALLOWED_HOSTS=*).\n'
  printf '    - Dockhand: az első belépés után állítsd be az autentikációt.\n'
  printf '    - A Dockhand, Homepage és Beszel agent hozzáfér a Docker sockethez (root-szintű jog).\n'
  printf '    - A Dockhand a stack könyvtárakat is eléri (adoptálás); tartsd auth mögött.\n'
  printf '    - Adatok: %s\n' "$BASE_DIR"
  printf '    - Log: %s\n\n' "$LOG_FILE"
}

show_status() {
  step "Szolgáltatások állapota"
  if ! is_narrow; then
    printf '  %-26s %-22s %s\n' "Szolgáltatás" "Konténer" "Állapot"
    printf '  %s\n' "--------------------------------------------------------------------"
  fi
  local -a names=("nginx-proxy-manager" "homepage" "dockhand" "thelounge" "beszel" "beszel-agent")
  local -a labels=("Nginx Proxy Manager" "Homepage" "Dockhand" "The Lounge" "Beszel Hub" "Beszel Agent")
  local i name label state color
  for i in "${!names[@]}"; do
    name="${names[$i]}"
    label="${labels[$i]}"
    if docker inspect "$name" >/dev/null 2>&1; then
      state="$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null || true)"
      case "$state" in
        running) color="$C_GREEN" ;;
        restarting) color="$C_YELLOW" ;;
        *) color="$C_RED" ;;
      esac
      if is_narrow; then
        printf '  %s: %s%s%s\n' "$label" "$color" "${state:-ismeretlen}" "$C_RESET"
      else
        printf '  %-26s %-22s %s%s%s\n' "$label" "$name" "$color" "${state:-ismeretlen}" "$C_RESET"
      fi
    else
      if is_narrow; then
        printf '  %s: nincs telepítve\n' "$label"
      else
        printf '  %-26s %-22s %s\n' "$label" "—" "nincs telepítve"
      fi
    fi
  done
  printf '\n  Adatok: %s\n  Log: %s\n' "$BASE_DIR" "$LOG_FILE"
}

action_install() {
  install_docker
  ensure_network

  local selected
  if ! selected="$(wt --separate-output --title "Komponensek" --checklist "Válaszd ki a komponenseket:" 20 78 10 \
    "npm" "NPM (80/443/81)" ON \
    "homepage" "Homepage (3000)" ON \
    "dockhand" "Dockhand (3001)" ON \
    "thelounge" "Lounge (9000)" ON \
    "beszel" "Beszel Hub + agent" ON)"; then
    return 0
  fi

  local -A selected_map=()
  local tag
  while IFS= read -r tag; do
    if [[ -n "$tag" ]]; then
      selected_map["$tag"]=1
    fi
  done <<<"$selected"

  if (( ${#selected_map[@]} == 0 )); then
    wt --title "Komponensek" --msgbox "Válassz legalább egy komponenst." 9 60
    return 0
  fi

  local default_addr addr
  default_addr="$(read_state SERVER_ADDRESS)"
  if [[ -z "$default_addr" ]]; then
    default_addr="$(detect_ip)"
  fi
  while true; do
    if ! addr="$(wt --title "Szerver címe" --inputbox "Szerver IPv4 címe vagy domain neve:" 10 70 "$default_addr")"; then
      return 0
    fi
    addr="$(trim "$addr")"
    if [[ "$addr" =~ ^[A-Za-z0-9._-]+$ ]]; then
      break
    fi
    wt --title "Hibás cím" --msgbox "Érvénytelen cím. IPv4 vagy domain kell." 9 60
  done
  SERVER_ADDRESS="$addr"

  local ports=()
  if [[ -n "${selected_map[npm]:-}" ]]; then
    ports+=("$NPM_HTTP_PORT" "$NPM_HTTPS_PORT" "$NPM_ADMIN_PORT")
  fi
  if [[ -n "${selected_map[homepage]:-}" ]]; then
    ports+=("$HOMEPAGE_PORT")
  fi
  if [[ -n "${selected_map[dockhand]:-}" ]]; then
    ports+=("$DOCKHAND_PORT")
  fi
  if [[ -n "${selected_map[thelounge]:-}" ]]; then
    ports+=("$THELOUNGE_PORT" "$THELOUNGE_IDENT_PORT")
  fi
  if [[ -n "${selected_map[beszel]:-}" ]]; then
    ports+=("$BESZEL_PORT")
  fi
  if (( ${#ports[@]} > 0 )); then
    check_ports "${ports[@]}" || return 0
  fi

  local summary="Telepítendő komponensek:\n\n"
  if [[ -n "${selected_map[npm]:-}" ]]; then
    summary+="  • Nginx Proxy Manager (80/443/81)\n"
  fi
  if [[ -n "${selected_map[homepage]:-}" ]]; then
    summary+="  • Homepage (3000)\n"
  fi
  if [[ -n "${selected_map[dockhand]:-}" ]]; then
    summary+="  • Dockhand (3001)\n"
  fi
  if [[ -n "${selected_map[thelounge]:-}" ]]; then
    summary+="  • The Lounge (9000)\n"
  fi
  if [[ -n "${selected_map[beszel]:-}" ]]; then
    summary+="  • Beszel Hub + helyi agent (8090)\n"
  fi
  summary+="\nSzerver címe: ${SERVER_ADDRESS}\n"
  summary+="Adatok: ${BASE_DIR}\n\n"
  summary+="A portok publikusan lesznek elérhetők. Folytatod?"
  if ! wt --title "Megerősítés" --yesno "$summary" 20 76; then
    return 0
  fi

  write_state "$SERVER_ADDRESS"

  if [[ -n "${selected_map[npm]:-}" ]]; then
    install_npm
  fi
  if [[ -n "${selected_map[dockhand]:-}" ]]; then
    install_dockhand
  fi
  if [[ -n "${selected_map[thelounge]:-}" ]]; then
    install_thelounge
  fi
  if [[ -n "${selected_map[beszel]:-}" ]]; then
    install_beszel
  fi
  if [[ -n "${selected_map[homepage]:-}" ]]; then
    install_homepage
  fi

  make_stacks_adoptable
  print_summary
}

action_beszel() {
  install_docker
  ensure_network
  setup_beszel_agent
}

update_npm() {
  step "Nginx Proxy Manager frissítése"
  backup_file "${NPM_DIR}/compose.yaml"
  run_logged "NPM image frissítése" compose_cmd "$NPM_DIR" pull || return 1
  run_logged "NPM újraindítása" compose_cmd "$NPM_DIR" up -d || return 1
  wait_for_http "Nginx Proxy Manager" "$NPM_ADMIN_PORT" 180 "nginx-proxy-manager" || true
}

update_homepage() {
  step "Homepage frissítése"
  backup_file "${HOMEPAGE_DIR}/compose.yaml"
  run_logged "Homepage image frissítése" compose_cmd "$HOMEPAGE_DIR" pull || return 1
  run_logged "Homepage újraindítása" compose_cmd "$HOMEPAGE_DIR" up -d || return 1
  wait_for_http "Homepage" "$HOMEPAGE_PORT" 120 "homepage" || true
}

update_dockhand() {
  step "Dockhand frissítése"
  backup_file "${DOCKHAND_DIR}/compose.yaml"
  run_logged "Dockhand image frissítése" compose_cmd "$DOCKHAND_DIR" pull || return 1
  run_logged "Dockhand újraindítása" compose_cmd "$DOCKHAND_DIR" up -d || return 1
  wait_for_http "Dockhand" "$DOCKHAND_PORT" 120 "dockhand" || true
}

update_thelounge() {
  step "The Lounge frissítése"
  backup_file "${THELOUNGE_DIR}/compose.yaml"
  run_logged "The Lounge image frissítése" compose_cmd "$THELOUNGE_DIR" pull || return 1
  run_logged "The Lounge újraindítása" compose_cmd "$THELOUNGE_DIR" up -d || return 1
  wait_for_http "The Lounge" "$THELOUNGE_PORT" 120 "thelounge" || true
}

update_beszel() {
  step "Beszel frissítése"
  local dir="$BESZEL_DIR"
  local key token agent=0
  key="$(env_get "${dir}/.env" BESZEL_KEY)"
  token="$(env_get "${dir}/.env" BESZEL_TOKEN)"
  if [[ -n "$key" && -n "$token" ]]; then
    agent=1
  fi
  backup_file "${dir}/compose.yaml"
  run_logged "Beszel Hub image frissítése" compose_cmd "$dir" pull beszel || return 1
  if (( agent )); then
    run_logged "Beszel agent image frissítése" compose_cmd "$dir" --profile agent pull beszel-agent || return 1
  fi
  run_logged "Beszel Hub újraindítása" compose_cmd "$dir" up -d beszel || return 1
  if (( agent )); then
    run_logged "Beszel agent újraindítása" compose_cmd "$dir" --profile agent up -d beszel-agent || return 1
  fi
  wait_for_http "Beszel Hub" "$BESZEL_PORT" 120 "beszel" || true
  if (( agent )); then
    sleep 2
    if [[ "$(docker inspect -f '{{.State.Running}}' beszel-agent 2>/dev/null || true)" == "true" ]]; then
      ok "Beszel agent fut."
    else
      warn "A Beszel agent nem fut. Ellenőrizd: docker logs beszel-agent"
    fi
  fi
}

action_update() {
  local -a tags=()
  local -a labels=()
  local -a checklist_args=()
  local selected tag i
  local -A selected_map=()
  local beszel_label="Beszel Hub"

  if [[ -f "${NPM_DIR}/compose.yaml" ]]; then
    tags+=("npm")
    labels+=("Nginx Proxy Manager")
  fi
  if [[ -f "${HOMEPAGE_DIR}/compose.yaml" ]]; then
    tags+=("homepage")
    labels+=("Homepage")
  fi
  if [[ -f "${DOCKHAND_DIR}/compose.yaml" ]]; then
    tags+=("dockhand")
    labels+=("Dockhand")
  fi
  if [[ -f "${THELOUNGE_DIR}/compose.yaml" ]]; then
    tags+=("thelounge")
    labels+=("The Lounge")
  fi
  if [[ -f "${BESZEL_DIR}/compose.yaml" ]]; then
    if [[ -n "$(env_get "${BESZEL_DIR}/.env" BESZEL_KEY)" && -n "$(env_get "${BESZEL_DIR}/.env" BESZEL_TOKEN)" ]]; then
      beszel_label="Beszel Hub + agent"
    fi
    tags+=("beszel")
    labels+=("$beszel_label")
  fi

  if (( ${#tags[@]} == 0 )); then
    wt --title "Frissítés" --msgbox "Nincs frissíthető telepített komponens." 9 60
    return 0
  fi

  for i in "${!tags[@]}"; do
    checklist_args+=("${tags[$i]}" "${labels[$i]}" ON)
  done

  if ! selected="$(wt --separate-output --title "Frissítés" --checklist "Válaszd ki a frissítendő komponenseket." 20 78 10 "${checklist_args[@]}")"; then
    return 0
  fi

  while IFS= read -r tag; do
    if [[ -n "$tag" ]]; then
      selected_map["$tag"]=1
    fi
  done <<<"$selected"

  if (( ${#selected_map[@]} == 0 )); then
    wt --title "Frissítés" --msgbox "Válassz legalább egy komponenst." 9 60
    return 0
  fi

  local summary="Frissítendő komponensek:\n\n"
  if [[ -n "${selected_map[npm]:-}" ]]; then
    summary+="  • Nginx Proxy Manager\n"
  fi
  if [[ -n "${selected_map[homepage]:-}" ]]; then
    summary+="  • Homepage\n"
  fi
  if [[ -n "${selected_map[dockhand]:-}" ]]; then
    summary+="  • Dockhand\n"
  fi
  if [[ -n "${selected_map[thelounge]:-}" ]]; then
    summary+="  • The Lounge\n"
  fi
  if [[ -n "${selected_map[beszel]:-}" ]]; then
    summary+="  • ${beszel_label}\n"
  fi
  summary+="\nLatest image-ek, rövid kiesés.\n"
  summary+="Compose backup készül, adat backup nem.\n\n"
  summary+="Folytatod?"
  if ! wt --title "Frissítés megerősítése" --yesno "$summary" 20 76; then
    return 0
  fi

  if [[ -n "${selected_map[npm]:-}" ]]; then
    update_npm
  fi
  if [[ -n "${selected_map[homepage]:-}" ]]; then
    update_homepage
  fi
  if [[ -n "${selected_map[dockhand]:-}" ]]; then
    update_dockhand
  fi
  if [[ -n "${selected_map[thelounge]:-}" ]]; then
    update_thelounge
  fi
  if [[ -n "${selected_map[beszel]:-}" ]]; then
    update_beszel
  fi

  ok "Frissítés kész."
  show_status
}

main_menu() {
  local choice
  while true; do
    if ! choice="$(wt --title "Főmenü" --menu "Válassz egy műveletet:" 16 64 6 \
      "install" "Telepítés" \
      "update" "Frissítés" \
      "beszel" "Beszel agent" \
      "status" "Állapot" \
      "quit" "Kilépés")"; then
      printf '\nViszlát!\nMenü: sudo vps-menu\n'
      exit 0
    fi
    case "$choice" in
      install) action_install ;;
      update) action_update ;;
      beszel) action_beszel ;;
      status) show_status ;;
      quit) printf '\nViszlát!\nMenü: sudo vps-menu\n'; exit 0 ;;
    esac
  done
}

menu_mode() {
  print_banner
  require_root
  require_tty
  trap 'on_error $?' ERR
  init_log
  check_os
  if ! command -v whiptail >/dev/null 2>&1; then
    die "A whiptail hiányzik. Futtasd a telepítőt: sudo bash $0"
  fi
  if ! command -v docker >/dev/null 2>&1 || ! docker info >/dev/null 2>&1; then
    die "A Docker nem érhető el. Indítsd el, vagy futtasd a telepítőt."
  fi
  ensure_network
  install_launcher
  SERVER_ADDRESS="$(read_state SERVER_ADDRESS)"
  if [[ -z "$SERVER_ADDRESS" ]]; then
    SERVER_ADDRESS="$(detect_ip)"
  fi
  main_menu
}

install_launcher() {
  local self
  self="$(readlink -f "$0" 2>/dev/null || true)"
  if [[ -z "$self" || ! -f "$self" ]]; then
    return 0
  fi
  mkdir -p /usr/local/sbin
  if ln -sf "$self" /usr/local/sbin/vps-menu; then
    ok "Menü parancs: sudo vps-menu"
  fi
}

usage() {
  cat <<EOF
VPS telepítő – Debian 13

Használat:
  sudo bash $0            # telepítés
  sudo bash $0 --menu     # csak a menü
  sudo vps-menu           # menü (telepítés után)

A script interaktív. Root jogosultság és Debian 13 szükséges.
Telepíthető: Docker, Dockhand, Nginx Proxy Manager, The Lounge,
Homepage, Beszel Hub és helyi Beszel agent.

Opciók:
  --menu           Menü megnyitása
  -h, --help       Súgó
  -V, --version    Verzió
EOF
}

main() {
  if [[ $# -eq 0 && "$(basename "$0")" == "vps-menu" ]]; then
    set -- --menu
  fi

  case "${1:-}" in
    -h|--help)
      usage
      exit 0
      ;;
    -V|--version)
      printf 'vps-setup %s\n' "$SCRIPT_VERSION"
      exit 0
      ;;
    --menu|menu)
      menu_mode
      exit 0
      ;;
    "") ;;
    *)
      usage
      exit 2
      ;;
  esac

  print_banner
  require_root
  require_tty
  trap 'on_error $?' ERR
  init_log
  log "=== vps-setup ${SCRIPT_VERSION} indul ==="
  check_os
  install_prereqs
  install_docker
  ensure_network
  install_launcher

  SERVER_ADDRESS="$(read_state SERVER_ADDRESS)"
  if [[ -z "$SERVER_ADDRESS" ]]; then
    SERVER_ADDRESS="$(detect_ip)"
  fi

  main_menu
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  main "$@"
fi
