#!/usr/bin/env bash
#
# Hedgehog Gateway 一键安装脚本 (macOS / Linux)
# Usage: bash install.sh [--force] [--silent] [--desktop] [--node-binary <path>] [--registry <url>]
#
# 支持的安装方式（优先级从高到低）：
#   1. 本地构建安装（检测到 dist/src/index.js 时）
#   2. 自定义服务器下载（设置 DOWNLOAD_URL 或 DOWNLOAD_BASE_URL 时）
#   3. GitHub Release 下载安装
#   4. npm 全局安装 fallback
#

set -euo pipefail

# ===== Constants =====
APP_NAME="HedgehogGateway"
NODE_MIN_VERSION="22.19.0"
GITHUB_REPO="hedgehog-finance/hedgehog-gateway"
DIST_NAME="hedgehog-gateway"
NPM_PACKAGE_NAME="hedgehoggateway"
DEFAULT_REGISTRY="https://registry.npmmirror.com"
DOWNLOAD_BASE_URL="https://download.ciweiai.com/downloads"
INSTALL_SCRIPT_URL="https://download.ciweiai.com/downloads/install.sh"

# ===== Colors =====
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# ===== Platform Detection =====
OS="$(uname -s)"
ARCH="$(uname -m)"

case "$OS" in
  Darwin) PLATFORM="macos" ;;
  Linux)  PLATFORM="linux" ;;
  *)      echo -e "${RED}Unsupported OS: $OS${NC}"; exit 1 ;;
esac

case "$OS" in
  Darwin) PACKAGE_PLATFORM="darwin" ;;
  Linux)  PACKAGE_PLATFORM="linux" ;;
esac

case "$ARCH" in
  x86_64|amd64) ARCH_NAME="x64" ;;
  arm64|aarch64) ARCH_NAME="arm64" ;;
  *) echo -e "${RED}Unsupported architecture: $ARCH${NC}"; exit 1 ;;
esac

# ===== Install Directory =====
DEFAULT_INSTALL_BASE="${XDG_DATA_HOME:-$HOME/.local/share}"
INSTALL_DIR="${HEDGEHOG_INSTALL_DIR:-${DEFAULT_INSTALL_BASE}/hedgehog-gateway}"

# 安装目录是否由本次运行新建（失败退出时清理残留空目录用）
INSTALL_DIR_CREATED_THIS_RUN=false

# 失败退出（exit != 0）且安装目录为本次新建时，删除该目录，
# 避免下载/依赖失败后留下“不完整安装”空壳（下次运行会告警清理）
cleanup_incomplete_install() {
  local code=$?
  if [ "$code" -ne 0 ] && [ "$INSTALL_DIR_CREATED_THIS_RUN" = true ] && [ -d "$INSTALL_DIR" ]; then
    rm -rf "$INSTALL_DIR" 2>/dev/null || true
  fi
}
trap cleanup_incomplete_install EXIT

DATA_DIR="${HEDGEHOG_DATA_DIR:-$HOME/.hedgehoggateway}"
PORT="${HEDGEHOG_PORT:-59100}"
BIND="${HEDGEHOG_BIND:-127.0.0.1}"
FORCE=false
SILENT=false
NODE_BINARY=""
DESKTOP=false
REGISTRY=""
DOWNLOAD_URL=""
INSTALL_STARTED_AT=$(date +%s)

# ===== Tray Companion Variables =====
INSTALL_TRAY="${HEDGEHOG_INSTALL_TRAY:-auto}"
START_TRAY="${HEDGEHOG_START_TRAY:-1}"
TRAY_AUTOSTART="${HEDGEHOG_TRAY_AUTOSTART:-0}"
IS_WSL2=false
HAS_DESKTOP=false
TRAY_INSTALLED=false

# ===== Arguments =====
while [[ $# -gt 0 ]]; do
  case "$1" in
    --force) FORCE=true; shift ;;
    --silent) SILENT=true; shift ;;
    --desktop) DESKTOP=true; shift ;;
    --node-binary) NODE_BINARY="$2"; shift 2 ;;
    --registry) REGISTRY="$2"; shift 2 ;;
    --download-url) DOWNLOAD_URL="$2"; shift 2 ;;
    --help|-h)
      echo "Usage: bash install.sh [options]"
      echo ""
      echo "Options:"
      echo "  --force               Overwrite existing installation"
      echo "  --silent              Suppress interactive output, emit JSON status"
      echo "  --desktop             Desktop app mode: inject NODE_ENV=production into service"
      echo "  --node-binary <path>  Use specified Node.js binary (bundled mode)"
      echo "  --registry <url>      npm registry URL (default: auto-detect CN/global)"
      echo "  --download-url <url>  Custom download URL for installation package"
      echo ""
      echo "Environment variables:"
      echo "  HEDGEHOG_INSTALL_DIR   Install directory (default: ~/.local/share/hedgehog-gateway)"
      echo "  HEDGEHOG_CLI_BIN_DIR   Directory for hedgehog command links (default: ~/.local/bin)"
      echo "  HEDGEHOG_SHELL_CONFIG  Shell config file for PATH setup (default: ~/.zshrc on macOS zsh)"
      echo "  HEDGEHOG_DATA_DIR      Data directory (default: ~/.hedgehoggateway)"
      echo "  HEDGEHOG_PORT          HTTP port (default: 59100)"
      echo "  HEDGEHOG_BIND          Bind address (default: 127.0.0.1)"
      echo "  HEDGEHOG_AUTOSTART     Set to 1 to configure auto-start during install"
      echo "  HEDGEHOG_START         Set to 0 to skip starting Gateway after install on macOS"
      echo "  HEDGEHOG_INSTALL_TRAY  Set to 0 to skip tray companion, 1 to force install (default: auto)"
      echo "  HEDGEHOG_START_TRAY    Set to 0 to skip starting tray companion after install"
      echo "  HEDGEHOG_TRAY_AUTOSTART  Set to 1 to enable tray login item (default: 0)"
      echo "  HEDGEHOG_REGISTRY      npm registry URL"
      echo "  HEDGEHOG_UPDATE_MANIFEST_URL  Version manifest URL used by hedgehog update"
      echo "  HEDGEHOG_DOWNLOAD_URL  Custom download URL for installation package"
      echo "  HEDGEHOG_DOWNLOAD_SHA256  Expected SHA256 for installation package"
      exit 0
      ;;
	    -*)
	      echo -e "${YELLOW}[WARN]${NC} Unknown option: $1 (use --help for usage)"
	      shift
	      ;;
    *) shift ;;
  esac
done

DOWNLOAD_URL="${DOWNLOAD_URL:-${HEDGEHOG_DOWNLOAD_URL:-}}"
DOWNLOAD_SHA256="${HEDGEHOG_DOWNLOAD_SHA256:-}"
if [ -z "$DOWNLOAD_URL" ] && [ -n "$DOWNLOAD_BASE_URL" ]; then
  DOWNLOAD_URL="${DOWNLOAD_BASE_URL}/${DIST_NAME}-latest-${PACKAGE_PLATFORM}-${ARCH_NAME}.tar.gz"
fi
if [ -z "$INSTALL_SCRIPT_URL" ] && [ -n "$DOWNLOAD_BASE_URL" ]; then
  INSTALL_SCRIPT_URL="${DOWNLOAD_BASE_URL%/}/install.sh"
fi
UPDATE_MANIFEST_URL="${HEDGEHOG_UPDATE_MANIFEST_URL:-}"
if [ -z "$UPDATE_MANIFEST_URL" ] && [ -n "$DOWNLOAD_BASE_URL" ]; then
  UPDATE_MANIFEST_URL="${DOWNLOAD_BASE_URL%/}/hedgehog-gateway-update-manifest.json"
fi

# ===== Desktop mode: inject NODE_ENV=production into service =====
DESKTOP_NODE_ENV=""
DESKTOP_NODE_ENV_PLIST=""
if [ "$DESKTOP" = "true" ]; then
  DESKTOP_NODE_ENV="Environment=NODE_ENV=production"
  DESKTOP_NODE_ENV_PLIST='
    <key>NODE_ENV</key>
    <string>production</string>'
fi

# ===== Helper Functions =====
json_escape() {
  local s="${1-}"
  s=${s//\\/\\\\}
  s=${s//\"/\\\"}
  s=${s//$'\b'/\\b}
  s=${s//$'\f'/\\f}
  s=${s//$'\n'/\\n}
  s=${s//$'\r'/\\r}
  s=${s//$'\t'/\\t}
  printf '%s' "$s"
}

json_string() {
  printf '"%s"' "$(json_escape "${1-}")"
}

json_line() {
  local step="$1"
  local status="$2"
  local message="$3"
  printf '{"step":%s,"status":%s,"message":%s}\n' \
    "$(json_string "$step")" \
    "$(json_string "$status")" \
    "$(json_string "$message")"
}

info()    { if [ "$SILENT" = true ]; then json_line "info" "running" "$1"; else echo -e "${BLUE}[INFO]${NC} $1"; fi; }
success() { if [ "$SILENT" = true ]; then json_line "$1" "running" "$1"; else echo -e "${GREEN}[OK]${NC} $1"; fi; }
warn()    { if [ "$SILENT" = true ]; then json_line "warn" "running" "$1"; else echo -e "${YELLOW}[WARN]${NC} $1"; fi; }
error() {
  if [ "$SILENT" = true ]; then
    json_line "error" "error" "$1"
  else
    echo -e "${RED}[ERROR]${NC} $1" >&2
  fi
  exit 1
}

validate_port() {
  local value="$1"
  if [[ ! "$value" =~ ^[0-9]+$ ]] || [ "$value" -lt 1 ] || [ "$value" -gt 65535 ]; then
    error "Invalid HEDGEHOG_PORT: ${value}. Expected an integer from 1 to 65535."
  fi
}

TOTAL_STEPS=9
progress() {
  local step="$1"
  local message="$2"
  if [ "$SILENT" = true ]; then
    json_line "${step}/${TOTAL_STEPS}" "running" "$message"
  else
    echo -e "${BLUE}[${step}/${TOTAL_STEPS}]${NC} ${message}"
  fi
}

validate_port "$PORT"

download_file() {
  local url="$1"
  local output="$2"
  local error_log="$3"
  if [ "$SILENT" = true ]; then
    curl -fsSL -o "$output" "$url" 2>"$error_log"
  else
    curl -fL --progress-bar -o "$output" "$url" 2> >(tee "$error_log" >&2)
  fi
}

verify_download_sha256() {
  local file="$1"
  if [ -z "$DOWNLOAD_SHA256" ]; then
    return 0
  fi

  local actual_hash=""
  if command -v shasum &>/dev/null; then
    actual_hash="$(shasum -a 256 "$file" | awk '{print $1}')"
  elif command -v sha256sum &>/dev/null; then
    actual_hash="$(sha256sum "$file" | awk '{print $1}')"
  else
    error "SHA256 verification requested but no SHA256 tool is available"
  fi

  if [ "$actual_hash" != "$DOWNLOAD_SHA256" ]; then
    error "SHA256 mismatch for $(basename "$file"). Expected ${DOWNLOAD_SHA256}, got ${actual_hash}"
  fi

  success "SHA256 verified"
}

# Check if sudo is available
check_sudo() {
  if command -v sudo &>/dev/null && sudo -n true 2>/dev/null; then
    return 0
  fi
  return 1
}

# Auto-detect registry based on network
detect_registry() {
  if [ -n "$REGISTRY" ]; then
    echo "$REGISTRY"
    return
  fi
  if [ -n "${HEDGEHOG_REGISTRY:-}" ]; then
    echo "$HEDGEHOG_REGISTRY"
    return
  fi

  if curl -fsSL --connect-timeout 3 "https://registry.npmmirror.com/npm" &>/dev/null; then
    echo "$DEFAULT_REGISTRY"
  else
    echo "https://registry.npmjs.org"
  fi
}

# Check if node is installed and meets version requirement
check_node() {
  if ! command -v node &>/dev/null; then
    return 1
  fi

  local node_version
  node_version=$(node -v | sed 's/^v//')

  # Compare versions
  local min_major min_minor min_patch
  IFS='.' read -r min_major min_minor min_patch <<< "$NODE_MIN_VERSION"

  local cur_major cur_minor cur_patch
  IFS='.' read -r cur_major cur_minor cur_patch <<< "$node_version"

  if [ "$cur_major" -lt "$min_major" ]; then return 1; fi
  if [ "$cur_major" -eq "$min_major" ] && [ "$cur_minor" -lt "$min_minor" ]; then return 1; fi
  if [ "$cur_major" -eq "$min_major" ] && [ "$cur_minor" -eq "$min_minor" ] && [ "$cur_patch" -lt "$min_patch" ]; then return 1; fi

  success "Node.js v${node_version} detected (>= ${NODE_MIN_VERSION})"
  return 0
}

# Install Node.js via official installer
install_node() {
  info "Installing Node.js >= ${NODE_MIN_VERSION}..."

  if [ "$PLATFORM" = "macos" ]; then
    if command -v brew &>/dev/null; then
      brew install node@22
      brew link --overwrite node@22
    else
      error "Please install Node.js >= ${NODE_MIN_VERSION} manually: https://nodejs.org/"
    fi
  elif [ "$PLATFORM" = "linux" ]; then
    if check_sudo; then
      curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
      sudo apt-get install -y nodejs
    else
      error "sudo not available. Please install Node.js >= ${NODE_MIN_VERSION} manually: https://nodejs.org/"
    fi
  fi

  if ! check_node; then
    error "Node.js installation failed. Please install manually: https://nodejs.org/"
  fi
}

detect_shell_config() {
  local shell_config=""

  if [ -n "${HEDGEHOG_SHELL_CONFIG:-}" ]; then
    echo "$HEDGEHOG_SHELL_CONFIG"
    return
  fi

  if [ -n "${SHELL:-}" ] && [ "$(basename "$SHELL")" = "zsh" ]; then
    shell_config="$HOME/.zshrc"
  elif [ -n "${SHELL:-}" ] && [ "$(basename "$SHELL")" = "bash" ]; then
    shell_config="$HOME/.bashrc"
    [ -f "$HOME/.bash_profile" ] && shell_config="$HOME/.bash_profile"
  elif [ -n "${ZSH_VERSION:-}" ]; then
    shell_config="$HOME/.zshrc"
  elif [ -n "${BASH_VERSION:-}" ]; then
    shell_config="$HOME/.bashrc"
    [ -f "$HOME/.bash_profile" ] && shell_config="$HOME/.bash_profile"
  elif [ -f "$HOME/.profile" ]; then
    shell_config="$HOME/.profile"
  else
    shell_config="$HOME/.zshrc"
  fi

  echo "$shell_config"
}

# Add path to shell config (idempotent)
add_to_path() {
  local target_path="$1"
  local shell_config
  shell_config="$(detect_shell_config)"

  mkdir -p "$(dirname "$shell_config")"
  touch "$shell_config"

  local begin="# >>> hedgehog gateway >>>"
  local end="# <<< hedgehog gateway <<<"
  local export_line=""
  local tmp_file="${shell_config}.hedgehog.tmp"

  if [ "$target_path" = "$HOME/.local/bin" ]; then
    export_line='export PATH="$HOME/.local/bin:$PATH"'
  else
    export_line="export PATH='$(shell_single_quote "$target_path")':\"\$PATH\""
  fi

  awk -v begin="$begin" -v end="$end" '
    $0 == begin { skip = 1; next }
    $0 == end { skip = 0; next }
    skip != 1 { print }
  ' "$shell_config" > "$tmp_file"

  {
    cat "$tmp_file"
    echo ""
    echo "$begin"
    echo "$export_line"
    echo "$end"
  } > "$shell_config"
  rm -f "$tmp_file"

  if [ "$target_path" = "$HOME/.local/bin" ]; then
    info "Added \$HOME/.local/bin to PATH in ${shell_config}"
  else
    info "Added ${target_path} to PATH in ${shell_config}"
  fi
}

path_contains_dir() {
  case ":$PATH:" in
    *":$1:"*) return 0 ;;
    *) return 1 ;;
  esac
}

select_cli_bin_dir() {
  if [ -n "${HEDGEHOG_CLI_BIN_DIR:-}" ]; then
    mkdir -p "$HEDGEHOG_CLI_BIN_DIR"
    echo "$HEDGEHOG_CLI_BIN_DIR"
    return
  fi

  mkdir -p "$HOME/.local/bin"
  echo "$HOME/.local/bin"
}

shell_single_quote() {
  printf "%s" "$1" | sed "s/'/'\\\\''/g"
}

create_cli_launcher() {
  local launcher_path="$1"
  local escaped_install_dir
  escaped_install_dir="$(shell_single_quote "$INSTALL_DIR")"

  cat > "$launcher_path" << EOF
#!/usr/bin/env sh
INSTALL_DIR='${escaped_install_dir}'
BUNDLED_NODE="\$INSTALL_DIR/node/node-${PACKAGE_PLATFORM}-${ARCH_NAME}/node"
if [ -x "\$BUNDLED_NODE" ]; then
  exec "\$BUNDLED_NODE" "\$INSTALL_DIR/dist/bin/hedgehoggateway.js" "\$@"
fi
exec node "\$INSTALL_DIR/dist/bin/hedgehoggateway.js" "\$@"
EOF
  chmod +x "$launcher_path"
}

install_cli_links() {
  local cli_bin_dir
  cli_bin_dir="$(select_cli_bin_dir)"

  ln -sf "${INSTALL_DIR}/bin/hedgehog" "$cli_bin_dir/hedgehog"
  ln -sf "${INSTALL_DIR}/bin/hedgehoggateway" "$cli_bin_dir/hedgehoggateway"
  info "Command links: ${cli_bin_dir}/hedgehog, ${cli_bin_dir}/hedgehoggateway"
  add_to_path "$cli_bin_dir"
  CLI_BIN_DIR="$cli_bin_dir"
}

test_cli_commands_installed() {
  local cli_bin_dir
  cli_bin_dir="$(select_cli_bin_dir)"

  [ -f "${INSTALL_DIR}/bin/hedgehog" ] || return 1
  [ -f "${INSTALL_DIR}/bin/hedgehoggateway" ] || return 1
  command -v hedgehog >/dev/null 2>&1 && return 0
  path_contains_dir "$cli_bin_dir"
}

ensure_cli_commands() {
  if [ -f "${INSTALL_DIR}/dist/bin/hedgehoggateway.js" ]; then
    chmod +x "${INSTALL_DIR}/dist/bin/hedgehoggateway.js"

    head -1 "${INSTALL_DIR}/dist/bin/hedgehoggateway.js" | grep -q "^#!" || {
      sed -i.bak '1i\
#!/usr/bin/env node' "${INSTALL_DIR}/dist/bin/hedgehoggateway.js"
      rm -f "${INSTALL_DIR}/dist/bin/hedgehoggateway.js.bak"
    }

    mkdir -p "${INSTALL_DIR}/bin"
    create_cli_launcher "${INSTALL_DIR}/bin/hedgehog"
    create_cli_launcher "${INSTALL_DIR}/bin/hedgehoggateway"
    install_cli_links
    if command -v hedgehog >/dev/null 2>&1; then
      info "hedgehog command is available: $(command -v hedgehog)"
    else
      info "Open a new terminal to use: hedgehog"
      info "Current terminal command: ${INSTALL_DIR}/bin/hedgehog"
    fi
  else
    warn "CLI entry not found: ${INSTALL_DIR}/dist/bin/hedgehoggateway.js"
  fi
}

save_update_source() {
  if [ -n "$INSTALL_SCRIPT_URL" ]; then
    cat > "${INSTALL_DIR}/update-source.json" << EOF
{
  "installUrl": "${INSTALL_SCRIPT_URL}",
  "manifestUrl": "${UPDATE_MANIFEST_URL}"
}
EOF
  fi
}

save_install_metadata() {
  local preserve_existing="${1:-false}"
  local existing_source=""
  if [ -f "${INSTALL_DIR}/install-metadata.json" ]; then
    existing_source=$(grep -o '"installSource"[[:space:]]*:[[:space:]]*"[^"]*"' "${INSTALL_DIR}/install-metadata.json" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)"$/\1/' || true)
    if [ "$existing_source" != "desktop-app" ] && [ "$existing_source" != "service-package" ]; then
      existing_source=""
    fi
  fi

  local install_source="service-package"
  if [ "$preserve_existing" = "true" ] && [ -n "$existing_source" ]; then
    install_source="$existing_source"
  elif [ "$DESKTOP" = "true" ]; then
    install_source="desktop-app"
  elif [ "${HEDGEHOG_UPDATE_MODE:-0}" = "1" ] && [ -n "$existing_source" ]; then
    install_source="$existing_source"
  fi

  cat > "${INSTALL_DIR}/install-metadata.json" << EOF
{
  "installSource": "${install_source}",
  "installer": "install.sh",
  "installedAt": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF
}

start_gateway_in_background() {
  if [ "${HEDGEHOG_START:-1}" = "0" ]; then
    info "Gateway start skipped because HEDGEHOG_START=0."
    SERVICE_STARTED=false
    return 0
  fi

  local hedgehog_cmd="${INSTALL_DIR}/bin/hedgehog"
  if [ ! -x "$hedgehog_cmd" ]; then
    warn "Could not start Gateway because command link was not found: ${hedgehog_cmd}"
    SERVICE_STARTED=false
    return 0
  fi

  info "Starting Gateway in background..."
  export HEDGEHOG_DATA_DIR="$DATA_DIR"
  export HEDGEHOG_PORT="$PORT"
  export HEDGEHOG_BIND="$BIND"
  if [ "$DESKTOP" = "true" ]; then
    export NODE_ENV=production
  fi

  if [ "$SILENT" = true ]; then
    if "$hedgehog_cmd" start --daemon --port "$PORT" --bind "$BIND" --data-dir "$DATA_DIR" >/dev/null 2>&1; then
      success "Gateway started in background."
      SERVICE_STARTED=true
    else
      warn "Gateway start failed. Run 'hedgehog start --daemon' to retry."
      SERVICE_STARTED=false
    fi
  else
    if "$hedgehog_cmd" start --daemon --port "$PORT" --bind "$BIND" --data-dir "$DATA_DIR"; then
      success "Gateway started in background."
      SERVICE_STARTED=true
    else
      warn "Gateway start failed. Run 'hedgehog start --daemon' to retry."
      SERVICE_STARTED=false
    fi
  fi

  # 服务启动成功后，非桌面模式自动打开浏览器（桌面安装包由 Electron 原生窗口接管，不弹浏览器）
  if [ "$SERVICE_STARTED" = true ] && [ "$DESKTOP" != "true" ] && [ "$SILENT" != "true" ]; then
    open_service_pages
  fi
}

# 等待端口就绪后打开浏览器（Gateway UI 59100 + HogAgent WebUI 9108）
open_service_pages() {
  local gateway_url="http://localhost:${PORT}"
  local hogagent_web_url="http://localhost:9108"

  # 等待 Gateway 端口就绪（最多 15s）
  local waited=0
  while [ $waited -lt 15 ]; do
    if curl -s "$gateway_url/api/status" >/dev/null 2>&1; then
      break
    fi
    sleep 1
    waited=$((waited + 1))
  done

  info "Opening service pages in browser..."
  case "$OS" in
    Darwin)
      open "$gateway_url"
      # HogAgent WebUI 可能需额外几秒启动，短暂等待
      sleep 2
      open "$hogagent_web_url" 2>/dev/null || true
      ;;
    Linux)
      xdg-open "$gateway_url" 2>/dev/null || true
      sleep 2
      xdg-open "$hogagent_web_url" 2>/dev/null || true
      ;;
  esac
}

# Fix npm permissions (user-level prefix)
fix_npm_permissions() {
  local npm_prefix
  npm_prefix=$(npm config get prefix 2>/dev/null || echo "")

  if [ -z "$npm_prefix" ]; then
    return
  fi

  if [ "$npm_prefix" = "/usr/local" ] && [ ! -w "$npm_prefix/lib/node_modules" ] && ! check_sudo; then
    warn "npm global directory not writable, switching to user-level prefix"

    local user_prefix="$HOME/.npm-global"
    mkdir -p "$user_prefix/lib/node_modules"

    npm config set prefix "$user_prefix"

    add_to_path "$user_prefix/bin"

    info "npm prefix changed to ${user_prefix}"
  fi
}

# Install via npm (fallback method)
install_via_npm() {
  local registry_url
  registry_url=$(detect_registry)
  info "Installing via npm (registry: ${registry_url})..."

  fix_npm_permissions

  local npm_opts="--omit=dev"
  if [ -n "$registry_url" ]; then
    npm_opts="$npm_opts --registry=$registry_url"
  fi

  if npm install -g "${NPM_PACKAGE_NAME}" $npm_opts 2>&1; then
    success "npm installation completed"
    return 0
  else
    warn "npm installation failed"
    return 1
  fi
}

# ===== Desktop Environment & WSL2 Detection =====

detect_wsl2() {
  if [ "$PLATFORM" = "linux" ] && grep -qiE '(microsoft|wsl2)' /proc/version 2>/dev/null; then
    IS_WSL2=true
  fi
}

detect_desktop_env() {
  if [ "$PLATFORM" = "macos" ]; then
    HAS_DESKTOP=true
  elif [ "$IS_WSL2" = true ]; then
    # WSL2: 检查 Windows interop 是否可用
    if command -v powershell.exe &>/dev/null || [ -x /mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe ]; then
      HAS_DESKTOP=true
    fi
  elif [ "$PLATFORM" = "linux" ]; then
    if [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
      HAS_DESKTOP=true
    fi
  fi
}

should_install_tray() {
  if [ "$INSTALL_TRAY" = "0" ]; then
    return 1
  fi
  if [ "$INSTALL_TRAY" = "1" ]; then
    return 0
  fi
  # auto: 有桌面环境时安装
  [ "$HAS_DESKTOP" = true ]
}

get_wsl_distro() {
  # 优先从 WSL_DISTRO_NAME 环境变量获取（最可靠）
  if [ -n "${WSL_DISTRO_NAME:-}" ]; then
    echo "$WSL_DISTRO_NAME"
    return
  fi
  # 回退：从 /proc/1/environ 提取
  local distro
  distro="$(cat /proc/1/environ 2>/dev/null | tr '\0' '\n' | grep '^WSL_DISTRO_NAME=' | cut -d= -f2)"
  if [ -n "$distro" ]; then
    echo "$distro"
    return
  fi
  # 最终回退：使用 wsl.exe 查询当前发行版
  if command -v wsl.exe &>/dev/null; then
    distro="$(wsl.exe -l -q 2>/dev/null | head -1 | tr -d '\r\0' | sed 's/^[* ]*//')"
    if [ -n "$distro" ]; then
      echo "$distro"
      return
    fi
  fi
  echo "Ubuntu"
}

install_tray_companion() {
  if ! should_install_tray; then
    if [ "$INSTALL_TRAY" = "0" ]; then
      info "Tray companion skipped (HEDGEHOG_INSTALL_TRAY=0)."
    else
      info "Tray companion skipped (no desktop environment detected)."
    fi
    return 0
  fi

  info "Installing tray companion..."

  if [ "$IS_WSL2" = true ]; then
    install_tray_wsl2
  elif [ "$PLATFORM" = "macos" ]; then
    install_tray_macos
  elif [ "$PLATFORM" = "linux" ]; then
    install_tray_linux
  fi
}

install_tray_wsl2() {
  local distro
  distro="$(get_wsl_distro)"
  local tray_url="${DOWNLOAD_BASE_URL}/hedgehog-gateway-tray-latest-win-x64.exe"
  local ps_script="\$ProgressPreference='SilentlyContinue; Invoke-WebRequest -Uri '${tray_url}' -OutFile \"\$env:TEMP\\HedgehogGatewaySetup.exe\"; Start-Process -Wait \"\$env:TEMP\\HedgehogGatewaySetup.exe\" -ArgumentList '/S'"

  if command -v powershell.exe &>/dev/null; then
    if powershell.exe -NoProfile -Command "$ps_script" 2>/dev/null; then
      TRAY_INSTALLED=true
      # 写入 WSL2 companion 配置
      local win_tray_dir
      win_tray_dir="$(powershell.exe -NoProfile -Command 'Write-Output $env:LOCALAPPDATA' 2>/dev/null | tr -d '\r')/HedgehogGateway"
      if [ -n "$win_tray_dir" ]; then
        local wsl_tray_dir
        wsl_tray_dir="$(wslpath "$win_tray_dir" 2>/dev/null || echo "")"
        if [ -n "$wsl_tray_dir" ]; then
          mkdir -p "$wsl_tray_dir"
          cat > "${wsl_tray_dir}/companion-config.json" << EOF
{
  "gatewayMode": "wsl2",
  "wslDistro": "${distro}",
  "port": ${PORT}
}
EOF
        fi
      fi
      success "Tray companion installed (Windows host, WSL2 mode: ${distro})."
    else
      warn "Tray companion installation failed. Install manually from Windows PowerShell."
    fi
  else
    warn "WSL2 detected but powershell.exe not available. Install tray companion manually on Windows."
  fi
}

install_tray_macos() {
  local tray_url="${DOWNLOAD_BASE_URL}/hedgehog-gateway-tray-latest-darwin-${ARCH_NAME}.dmg"
  local tmp_dmg="/tmp/HedgehogGateway.dmg"

  info "Downloading tray companion..."
  if curl -fsSL -o "$tmp_dmg" "$tray_url" 2>/dev/null; then
    local mount_point
    mount_point="$(hdiutil attach "$tmp_dmg" -nobrowse 2>/dev/null | tail -1 | awk '{print $NF}')"
    if [ -n "$mount_point" ] && [ -d "$mount_point" ]; then
      local app_src
      app_src="$(find "$mount_point" -name '*.app' -maxdepth 1 | head -1)"
      if [ -n "$app_src" ]; then
        local target_dir="$HOME/Applications"
        mkdir -p "$target_dir"
        cp -R "$app_src" "$target_dir/" 2>/dev/null && TRAY_INSTALLED=true
      fi
      hdiutil detach "$mount_point" -quiet 2>/dev/null || true
    fi
    rm -f "$tmp_dmg"
    if [ "$TRAY_INSTALLED" = true ]; then
      success "Tray companion installed to ~/Applications."
    else
      warn "Tray companion installation failed."
    fi
  else
    warn "Tray companion download failed. Install manually later."
  fi
}

install_tray_linux() {
  local tray_url="${DOWNLOAD_BASE_URL}/hedgehog-gateway-tray-latest-linux-${ARCH_NAME}.AppImage"
  local tray_dir="$HOME/.local/share/hedgehog-gateway-app"
  local tray_bin="${tray_dir}/HedgehogGateway.AppImage"

  mkdir -p "$tray_dir"
  info "Downloading tray companion..."
  if curl -fsSL -o "$tray_bin" "$tray_url" 2>/dev/null; then
    chmod +x "$tray_bin"
    TRAY_INSTALLED=true
    success "Tray companion installed to ${tray_dir}."

    # 注册开机启动托盘（XDG autostart）
    if [ "$TRAY_AUTOSTART" = "1" ]; then
      local autostart_dir="$HOME/.config/autostart"
      mkdir -p "$autostart_dir"
      cat > "${autostart_dir}/hedgehog-gateway-tray.desktop" << EOF
[Desktop Entry]
Type=Application
Name=HedgehogGateway
Comment=HedgehogGateway Desktop Client
Exec=${tray_bin}
Icon=hedgehog-gateway-tray
Terminal=false
StartupNotify=false
Categories=Utility;
X-GNOME-Autostart-enabled=true
X-GNOME-Autostart-Delay=3
EOF
      info "Tray autostart registered (XDG)."
    fi
  else
    warn "Tray companion download failed. Install manually later."
  fi
}

start_tray_companion() {
  if [ "$TRAY_INSTALLED" != true ] || [ "$START_TRAY" = "0" ]; then
    return 0
  fi

  info "Starting tray companion..."
  if [ "$IS_WSL2" = true ]; then
    # WSL2: 启动 Windows 侧 tray
    local win_tray_exe
    win_tray_exe="$(powershell.exe -NoProfile -Command 'Write-Output "$env:LOCALAPPDATA\Programs\HedgehogGateway\HedgehogGateway.exe"' 2>/dev/null | tr -d '\r')"
    if [ -n "$win_tray_exe" ]; then
      powershell.exe -NoProfile -Command "Start-Process '$win_tray_exe'" 2>/dev/null || true
    fi
  elif [ "$PLATFORM" = "macos" ]; then
    open -a "$HOME/Applications/刺猬AI.app" 2>/dev/null || true
  elif [ "$PLATFORM" = "linux" ]; then
    local tray_bin="$HOME/.local/share/hedgehog-gateway-app/HedgehogGateway.AppImage"
    if [ -x "$tray_bin" ]; then
      nohup "$tray_bin" &>/dev/null &
    fi
  fi
}

# ===== Main Installation =====

echo ""
echo "========================================"
echo "  Hedgehog Gateway Installer"
echo "  Platform: ${PLATFORM} (${ARCH_NAME})"
echo "========================================"
echo ""

progress 1 "Checking existing installation"
UPGRADE_MODE=false
CURRENT_VERSION=""
if [ -d "$INSTALL_DIR" ]; then
  # 有效安装判定：入口文件存在且非空（-s 防止中断写入留下的 0 字节文件误判）
  if [ -s "${INSTALL_DIR}/dist/bin/hedgehoggateway.js" ] || [ -s "${INSTALL_DIR}/dist/src/index.js" ]; then
    CURRENT_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "${INSTALL_DIR}/package.json" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)"$/\1/' || echo "unknown")
    if [ "$FORCE" = true ]; then
      info "--force specified, will overwrite existing installation (v${CURRENT_VERSION})"
    elif [ "${HEDGEHOG_UPDATE_MODE:-0}" = "1" ]; then
      UPGRADE_MODE=true
      info "Existing installation detected: v${CURRENT_VERSION}"
      info "Proceeding with update"
    elif test_cli_commands_installed; then
      warn "HedgehogGateway is already installed and the hedgehog command is available"
      info "Run 'hedgehog update' to update, or rerun installer with --force to reinstall"
      exit 0
    else
      info "Existing installation detected: v${CURRENT_VERSION}"
      info "Repairing command links and PATH without reinstalling"
      mkdir -p "$DATA_DIR"
      ensure_cli_commands
      save_update_source
      save_install_metadata true
      success "HedgehogGateway is already installed"
      info "Use --force to reinstall, or run 'hedgehog update' to update"
      exit 0
    fi
  else
    warn "Found incomplete installation at ${INSTALL_DIR} (likely a previous failed attempt)"
    info "Cleaning up incomplete files (preserving bundled Node.js if present)..."
    find "$INSTALL_DIR" -mindepth 1 -maxdepth 1 ! -name 'node' -exec rm -rf {} +
  fi
fi

progress 2 "Resolving Node.js runtime"
if [ -n "$NODE_BINARY" ]; then
  info "Using bundled Node.js: ${NODE_BINARY}"
  NODE_CMD="$NODE_BINARY"
else
  NODE_CMD=""
fi

find_bundled_node() {
  local bundled_node="${INSTALL_DIR}/node/node-${PACKAGE_PLATFORM}-${ARCH_NAME}/node"
  if [ -x "$bundled_node" ]; then
    echo "$bundled_node"
  fi
}

ensure_node_cmd() {
  if [ -n "$NODE_CMD" ]; then
    return
  fi

  local bundled_node
  bundled_node="$(find_bundled_node)"
  if [ -n "$bundled_node" ]; then
    info "Using bundled Node.js: ${bundled_node}"
    NODE_CMD="$bundled_node"
  elif check_node; then
    NODE_CMD="node"
  else
    warn "Node.js >= ${NODE_MIN_VERSION} not found"
    install_node
    NODE_CMD="node"
  fi
}

progress 3 "Preparing install directory"
UPGRADE_STAGING_DIR=""
if [ "$UPGRADE_MODE" = true ] || [ "$FORCE" = true ]; then
  if [ -d "$INSTALL_DIR" ]; then
    # 升级模式：先解压到临时目录，成功后原子交换（旧文件保留到最后一刻，失败则不受影响）
    UPGRADE_STAGING_DIR=$(mktemp -d "${INSTALL_DIR}.upgrade.XXXXXX")
    info "Preparing upgrade staging directory..."
  fi
fi
info "Installing to ${INSTALL_DIR}..."
[ -d "$INSTALL_DIR" ] || INSTALL_DIR_CREATED_THIS_RUN=true
mkdir -p "$INSTALL_DIR"

progress 4 "Installing package files"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"

INSTALL_METHOD=""

if [ -f "${PACKAGE_DIR}/dist/src/index.js" ]; then
  info "Installing from local build..."
  cp -R "${PACKAGE_DIR}/dist" "$INSTALL_DIR/"
  cp "${PACKAGE_DIR}/package.json" "$INSTALL_DIR/"
  [ -d "${PACKAGE_DIR}/agents" ] && cp -R "${PACKAGE_DIR}/agents" "$INSTALL_DIR/"
  [ -d "${PACKAGE_DIR}/skills" ] && cp -R "${PACKAGE_DIR}/skills" "$INSTALL_DIR/"
  [ -d "${PACKAGE_DIR}/node_modules" ] && cp -R "${PACKAGE_DIR}/node_modules" "$INSTALL_DIR/"
  [ -d "${PACKAGE_DIR}/web/dist" ] && mkdir -p "$INSTALL_DIR/web" && cp -R "${PACKAGE_DIR}/web/dist" "$INSTALL_DIR/web/"
  INSTALL_METHOD="local"
  progress 5 "Package extraction skipped for local build"
else
  # 升级模式解压到临时目录，非升级模式直接解压到 INSTALL_DIR
  EXTRACT_TARGET="${UPGRADE_STAGING_DIR:-$INSTALL_DIR}"

  if [ -n "${HEDGEHOG_LOCAL_PACKAGE:-}" ] && [ -f "$HEDGEHOG_LOCAL_PACKAGE" ]; then
    # Gateway 已完成包下载与 sha256 校验（update-service downloadPackage），
    # 直接用本地包解压，避免脚本内二次下载；旧版 Gateway 不传该变量时走下方下载分支
    info "Using pre-downloaded package: $(basename "$HEDGEHOG_LOCAL_PACKAGE")"
    progress 5 "Installing Gateway service files"
    if tar -xzf "$HEDGEHOG_LOCAL_PACKAGE" -C "$EXTRACT_TARGET" --strip-components=1 2>/dev/null; then
      INSTALL_METHOD="local-package"
    else
      warn "Extract failed, tarball may be corrupted"
    fi
  fi

  if [ -z "$INSTALL_METHOD" ] && [ -n "$DOWNLOAD_URL" ]; then
    info "Downloading from custom server: ${DOWNLOAD_URL}"
    TARBALL=$(basename "$DOWNLOAD_URL")
    TEMP_DIR=$(mktemp -d)
    CURL_LOG="${TEMP_DIR}/curl-error.log"
    if download_file "$DOWNLOAD_URL" "${TEMP_DIR}/${TARBALL}" "$CURL_LOG"; then
      info "Downloaded ${TARBALL} ($(du -h "${TEMP_DIR}/${TARBALL}" | cut -f1))"
      verify_download_sha256 "${TEMP_DIR}/${TARBALL}"
      progress 5 "Installing Gateway service files"
      if ! tar -xzf "${TEMP_DIR}/${TARBALL}" -C "$EXTRACT_TARGET" --strip-components=1 2>/dev/null; then
        warn "Extract failed, tarball may be corrupted"
        rm -rf "$TEMP_DIR"
      else
        rm -rf "$TEMP_DIR"
        INSTALL_METHOD="custom"
      fi
    else
      warn "Download from custom server failed: $(cat "$CURL_LOG" 2>/dev/null || echo 'unknown error')"
      rm -rf "$TEMP_DIR"
    fi
  elif [ -z "$INSTALL_METHOD" ]; then
    info "Downloading latest release from GitHub..."
    VERSION=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" 2>/dev/null | grep '"tag_name"' | head -1 | sed 's/.*"tag_name":"\([^"]*\)".*/\1/' || echo "")

    if [ -z "$VERSION" ]; then
      warn "Could not fetch latest version from GitHub"
    else
      info "Version: ${VERSION}"
      TARBALL="${DIST_NAME}-${VERSION#v}.tar.gz"
      GH_DOWNLOAD_URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/${TARBALL}"

      TEMP_DIR=$(mktemp -d)
      CURL_LOG="${TEMP_DIR}/curl-error.log"
      if download_file "$GH_DOWNLOAD_URL" "${TEMP_DIR}/${TARBALL}" "$CURL_LOG"; then
        info "Downloaded ${TARBALL} ($(du -h "${TEMP_DIR}/${TARBALL}" | cut -f1))"
        verify_download_sha256 "${TEMP_DIR}/${TARBALL}"
        progress 5 "Installing Gateway service files"
        if ! tar -xzf "${TEMP_DIR}/${TARBALL}" -C "$EXTRACT_TARGET" --strip-components=1 2>/dev/null; then
          warn "Extract failed, tarball may be corrupted"
          rm -rf "$TEMP_DIR"
        else
          rm -rf "$TEMP_DIR"
          INSTALL_METHOD="github"
        fi
      else
        warn "Download from GitHub failed: $(cat "$CURL_LOG" 2>/dev/null || echo 'unknown error')"
        rm -rf "$TEMP_DIR"
      fi
    fi
  fi

  if [ -z "$INSTALL_METHOD" ]; then
    info "Trying npm installation as fallback..."
    ensure_node_cmd
    if install_via_npm; then
      INSTALL_METHOD="npm"
      NPM_INSTALL_PATH="$(npm root -g 2>/dev/null)/${NPM_PACKAGE_NAME}"
      if [ -d "$NPM_INSTALL_PATH" ]; then
        cp -R "$NPM_INSTALL_PATH/"* "$EXTRACT_TARGET/"
      fi
    else
      error "All installation methods failed. Please build from source: npm run build && bash scripts/install.sh"
    fi
  fi
fi

# ===== 升级模式原子交换 =====
# 解压成功后，删除旧文件（保留 node/）并将新文件移入
if [ -n "$UPGRADE_STAGING_DIR" ] && [ -d "$UPGRADE_STAGING_DIR" ]; then
  if [ -n "$INSTALL_METHOD" ] && [ -f "$UPGRADE_STAGING_DIR/dist/src/index.js" ]; then
    info "Swapping to new version (atomic replace)..."
    # 保留 node/ 目录（捆绑的 Node.js 二进制，版本间通常不变）
    find "$INSTALL_DIR" -mindepth 1 -maxdepth 1 ! -name 'node' -exec rm -rf {} +
    # 将解压的新文件移入安装目录
    find "$UPGRADE_STAGING_DIR" -mindepth 1 -maxdepth 1 -exec mv {} "$INSTALL_DIR/" \;
    rm -rf "$UPGRADE_STAGING_DIR"
  else
    warn "Extraction to staging failed, keeping old installation intact"
    rm -rf "$UPGRADE_STAGING_DIR"
  fi
fi

progress 6 "Selecting installed Node.js runtime"
ensure_node_cmd

progress 7 "Checking production dependencies"
if [ ! -d "${INSTALL_DIR}/node_modules" ]; then
  info "Installing production dependencies..."
  if [ -f "${INSTALL_DIR}/package-lock.json" ]; then
    (cd "$INSTALL_DIR" && npm ci --omit=dev) || warn "npm ci failed, trying npm install..."
    if [ ! -d "${INSTALL_DIR}/node_modules" ]; then
      (cd "$INSTALL_DIR" && npm install --omit=dev) || warn "npm install also failed"
    fi
  else
    (cd "$INSTALL_DIR" && npm install --omit=dev) || warn "npm install failed"
  fi
fi

progress 8 "Creating data directory and command links"
info "Data directory: ${DATA_DIR}"
mkdir -p "$DATA_DIR"

save_update_source
save_install_metadata

# Step 7: Create CLI symlink
ensure_cli_commands

progress 9 "Applying auto-start preference"

# 始终生成服务项文件（plist/systemd），RunAtLoad/KeepAlive 根据 HEDGEHOG_AUTOSTART 决定。
# autostart=0 时生成"中性"文件（RunAtLoad=false），仅作为托盘启停的载体，不开机自启。
# autostart=1 时启用开机自启（额外执行 launchctl load -w / systemctl enable）。
# 与 electron/services/launchd-plist.ts、systemd-unit.ts 模板保持字段对齐。
if [ "$PLATFORM" = "macos" ]; then
  PLIST_PATH="$HOME/Library/LaunchAgents/com.hedgehog.gateway.plist"
  mkdir -p "$(dirname "$PLIST_PATH")"
  mkdir -p "${DATA_DIR}/logs"

  if [ "${HEDGEHOG_AUTOSTART:-0}" = "1" ]; then
    RUN_AT_LOAD="<true/>"
    KEEP_ALIVE="<true/>"
  else
    RUN_AT_LOAD="<false/>"
    KEEP_ALIVE="<false/>"
  fi

  cat > "$PLIST_PATH" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.hedgehog.gateway</string>
  <key>ProgramArguments</key>
  <array>
    <string>${NODE_CMD}</string>
    <string>${INSTALL_DIR}/dist/src/index.js</string>
  </array>
  <key>RunAtLoad</key>
  ${RUN_AT_LOAD}
  <key>KeepAlive</key>
  ${KEEP_ALIVE}
  <key>StandardOutPath</key>
  <string>${DATA_DIR}/logs/gateway-launchd.log</string>
  <key>StandardErrorPath</key>
  <string>${DATA_DIR}/logs/gateway-launchd.err</string>
  <key>EnvironmentVariables</key>
  <dict>
    <key>HEDGEHOG_DATA_DIR</key>
    <string>${DATA_DIR}</string>
    <key>HEDGEHOG_PORT</key>
    <string>${HEDGEHOG_PORT:-59100}</string>
    <key>HEDGEHOG_BIND</key>
    <string>${HEDGEHOG_BIND:-127.0.0.1}</string>${DESKTOP_NODE_ENV_PLIST}
  </dict>
</dict>
</plist>
EOF

  if [ "${HEDGEHOG_AUTOSTART:-0}" = "1" ]; then
    launchctl unload "$PLIST_PATH" 2>/dev/null || true
    launchctl load -w "$PLIST_PATH" 2>/dev/null || true
    success "Auto-start enabled (LaunchAgent)."
  else
    success "LaunchAgent plist generated (auto-start disabled by default). Run 'hedgehog autostart on' to enable."
  fi

elif [ "$PLATFORM" = "linux" ]; then
  SERVICE_DIR="$HOME/.config/systemd/user"
  mkdir -p "$SERVICE_DIR"
  mkdir -p "${DATA_DIR}/logs"

  if [ "${HEDGEHOG_AUTOSTART:-0}" = "1" ]; then
    INSTALL_SECTION=$'\n[Install]\nWantedBy=default.target'
  else
    INSTALL_SECTION=""
  fi

  cat > "${SERVICE_DIR}/hedgehog-gateway.service" << EOF
[Unit]
Description=Hedgehog Gateway
After=network.target

[Service]
Type=simple
WorkingDirectory=${INSTALL_DIR}
ExecStart="${NODE_CMD}" "${INSTALL_DIR}/dist/src/index.js"
Restart=on-failure
RestartSec=5
Environment=HEDGEHOG_DATA_DIR=${DATA_DIR}
Environment=HEDGEHOG_PORT=${HEDGEHOG_PORT:-59100}
Environment=HEDGEHOG_BIND=${HEDGEHOG_BIND:-127.0.0.1}
${DESKTOP_NODE_ENV}
StandardOutput=append:${DATA_DIR}/logs/gateway.log
StandardError=append:${DATA_DIR}/logs/gateway.err${INSTALL_SECTION}
EOF
  systemctl --user daemon-reload 2>/dev/null || true

  if [ "${HEDGEHOG_AUTOSTART:-0}" = "1" ]; then
    systemctl --user enable hedgehog-gateway.service 2>/dev/null || true
    success "Auto-start enabled (systemd user service). Gateway was not started."
  else
    success "systemd unit generated (auto-start disabled by default). Run 'hedgehog autostart on' to enable."
  fi
fi

SERVICE_STARTED=false
if [ "$PLATFORM" = "macos" ] || [ "$PLATFORM" = "linux" ]; then
  if [ "${HEDGEHOG_UPDATE_MODE:-0}" != "1" ] && [ "$UPGRADE_MODE" != true ]; then
    # 首次安装：始终启动 Gateway（桌面模式和 CLI 模式一致）
    start_gateway_in_background
  elif [ "${HEDGEHOG_AUTO_RESTART:-0}" = "1" ]; then
    # 升级模式 + AUTO_RESTART=1：先停止旧进程，再启动新版本
    # （hedgehog start 遇到已运行进程会直接 exit 0 不重启）
    _hedgehog_cmd="${INSTALL_DIR}/bin/hedgehog"
    if [ -x "$_hedgehog_cmd" ]; then
      info "Stopping old Gateway before restart..."
      "$_hedgehog_cmd" stop >/dev/null 2>&1 || true
    fi
    unset _hedgehog_cmd
    info "Restarting Gateway after upgrade..."
    start_gateway_in_background
  fi
fi

# ===== Tray Companion Installation =====
detect_wsl2
detect_desktop_env
install_tray_companion
start_tray_companion

# ===== Done =====
ELAPSED_SECONDS=$(( $(date +%s) - INSTALL_STARTED_AT ))
if [ "${HEDGEHOG_UPDATE_MODE:-0}" = "1" ] || [ "$UPGRADE_MODE" = true ]; then
  DONE_MESSAGE="Hedgehog Gateway updated"
  DONE_TITLE="Hedgehog Gateway updated!"
  if [ "${HEDGEHOG_AUTO_RESTART:-0}" = "1" ]; then
    SERVICE_STATE="restarting automatically"
    NEXT_STEP="auto-restart in progress"
    WEB_UI_NOTE="after restart"
  elif [ "${HEDGEHOG_WAS_RUNNING:-0}" = "1" ]; then
    SERVICE_STATE="not restarted"
    NEXT_STEP="hedgehog restart"
    WEB_UI_NOTE="after restart"
  else
    SERVICE_STATE="not restarted"
    NEXT_STEP="hedgehog start --daemon"
    WEB_UI_NOTE="after start"
  fi
else
  DONE_MESSAGE="Hedgehog Gateway installed"
  DONE_TITLE="Hedgehog Gateway installed!"
  if [ "$SERVICE_STARTED" = true ]; then
    SERVICE_STATE="running"
    NEXT_STEP="hedgehog status"
    WEB_UI_NOTE="now"
  else
    SERVICE_STATE="not started"
    NEXT_STEP="hedgehog start --daemon"
    WEB_UI_NOTE="after start"
  fi
fi
if [ "$SILENT" = true ]; then
  printf '{"step":"done","status":"running","message":%s,"port":%s,"method":%s,"serviceStarted":%s,"serviceState":%s,"nextStep":%s,"elapsedSeconds":%s}\n' \
    "$(json_string "$DONE_MESSAGE")" \
    "$PORT" \
    "$(json_string "$INSTALL_METHOD")" \
    "$SERVICE_STARTED" \
    "$(json_string "$SERVICE_STATE")" \
    "$(json_string "$NEXT_STEP")" \
    "$ELAPSED_SECONDS"
else
echo ""
echo "========================================"
echo -e "${GREEN}[OK]${NC} ${DONE_TITLE}"
echo "========================================"
echo ""
echo "  Install method: ${INSTALL_METHOD}"
echo "  Install dir:    ${INSTALL_DIR}"
echo "  Data dir:       ${DATA_DIR}"
echo "  Web UI:         http://localhost:${PORT} (${WEB_UI_NOTE})"
echo "  Elapsed:        ${ELAPSED_SECONDS}s"
echo "  Service:        ${SERVICE_STATE}"
echo "  Next step:      ${NEXT_STEP}"
echo ""
echo "  Commands:"
echo "    hedgehog start       Start Gateway"
echo "    hedgehog start -d    Start Gateway in background"
echo "    hedgehog restart     Restart Gateway in background"
echo "    hedgehog stop        Stop Gateway"
echo "    hedgehog status      Check status"
echo "    hedgehog update      Update Gateway"
echo "    hedgehog autostart on|off  Manage auto-start"
echo "    hedgehog logs        Show log path"
echo "    hedgehog backup      Create backup"
echo "    hedgehog restore     Restore backup"
echo "    hedgehog migrate     Import or migrate data"
echo "    hedgehog uninstall   Uninstall Gateway (keeps data)"
echo ""
fi
