#!/bin/sh

# Smart Printer Edge Server 的唯一安装与服务控制入口。
# GUI 调用这份脚本的内置副本；无界面安装也使用同一个文件。

set -eu
umask 077

PRODUCT_NAME="Smart Printer Edge Server"
DEFAULT_LABEL="dev.smart-printer"
DEFAULT_RELEASE_ROOT_URL="https://files.hanxiang.cloud/smart-printer/releases/edge-server"
DEFAULT_RELEASE_BASE_URL="$DEFAULT_RELEASE_ROOT_URL/latest"

COMMAND="install"
case "${1:-}" in
  install|upgrade|check-update|start|stop|restart|enable|disable|status|doctor|uninstall|help)
    COMMAND="$1"
    shift
    ;;
esac

JSON_OUTPUT=0
NO_START=0
AUTO_START_REQUEST=""
PURGE_DATA=0
CONFIRM_PURGE=0
SOURCE_BINARY=""
SOURCE_PACKAGE=""
SOURCE_CHECKSUM=""
REQUESTED_VERSION=""
INSTALL_ROOT_ARG="${SMART_PRINTER_INSTALL_ROOT:-}"
DATA_DIR_ARG="${SMART_PRINTER_DATA_DIR:-}"
HOST_ARG="${SMART_PRINTER_HOST:-}"
PORT_ARG="${SMART_PRINTER_PORT:-}"
PUBLIC_URL_ARG="${SMART_PRINTER_PUBLIC_URL:-}"
LABEL="${SMART_PRINTER_SERVICE_LABEL:-$DEFAULT_LABEL}"
LAUNCH_AGENTS_DIR_ARG="${SMART_PRINTER_LAUNCH_AGENTS_DIR:-}"
SYSTEMD_USER_DIR_ARG="${SMART_PRINTER_SYSTEMD_USER_DIR:-}"
RELEASE_BASE_URL="${SMART_PRINTER_RELEASE_BASE_URL:-$DEFAULT_RELEASE_BASE_URL}"
RELEASE_ROOT_URL="${SMART_PRINTER_RELEASE_ROOT_URL:-$DEFAULT_RELEASE_ROOT_URL}"
LAUNCHCTL="${SMART_PRINTER_LAUNCHCTL:-/bin/launchctl}"
SYSTEMCTL="${SMART_PRINTER_SYSTEMCTL:-systemctl}"
CURL="${SMART_PRINTER_CURL:-/usr/bin/curl}"

usage() {
  cat <<'EOF'
Smart Printer Edge Server 安装与服务控制

用法：
  install.sh install [选项]
  install.sh upgrade [选项]
  install.sh check-update [--json]
  install.sh start|stop|restart|enable|disable|status|doctor
  install.sh uninstall [--purge-data --yes]

安装选项：
  --binary PATH          使用本地 edge-server 可执行文件
  --package PATH         使用本地 .tar.gz 发布包
  --checksum VALUE       校验包或二进制的 SHA-256（也可传校验文件）
  --version VERSION      下载指定版本；默认下载 latest
  --host ADDRESS         监听地址，默认 0.0.0.0
  --port PORT            监听端口，默认 6176
  --public-url URL       手机访问时使用的可选公开地址
  --data-dir PATH        数据目录
  --install-root PATH    安装根目录
  --release-base-url URL latest 发布包目录
  --release-root-url URL 版本发布根目录；配合 --version 使用
  --no-start             安装后不立即启动
  --no-autostart         不在登录后自动启动
  --json                 输出适合 GUI 读取的 JSON Lines

Linux 使用 systemd 用户服务，需要当前用户的 systemd 会话；打印还需要 CUPS 命令。
环境变量可使用同名 SMART_PRINTER_* 配置覆盖默认值。
EOF
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --binary)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      SOURCE_BINARY="$2"
      shift 2
      ;;
    --package)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      SOURCE_PACKAGE="$2"
      shift 2
      ;;
    --checksum)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      SOURCE_CHECKSUM="$2"
      shift 2
      ;;
    --version)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      REQUESTED_VERSION="$2"
      shift 2
      ;;
    --host)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      HOST_ARG="$2"
      shift 2
      ;;
    --port)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      PORT_ARG="$2"
      shift 2
      ;;
    --public-url)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      PUBLIC_URL_ARG="$2"
      shift 2
      ;;
    --data-dir)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      DATA_DIR_ARG="$2"
      shift 2
      ;;
    --install-root)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      INSTALL_ROOT_ARG="$2"
      shift 2
      ;;
    --label)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      LABEL="$2"
      shift 2
      ;;
    --launch-agents-dir)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      LAUNCH_AGENTS_DIR_ARG="$2"
      shift 2
      ;;
    --release-base-url)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      RELEASE_BASE_URL="$2"
      shift 2
      ;;
    --release-root-url)
      [ "$#" -ge 2 ] || { usage >&2; exit 2; }
      RELEASE_ROOT_URL="$2"
      shift 2
      ;;
    --no-start)
      NO_START=1
      shift
      ;;
    --no-autostart)
      AUTO_START_REQUEST=0
      shift
      ;;
    --autostart)
      AUTO_START_REQUEST=1
      shift
      ;;
    --purge-data)
      PURGE_DATA=1
      shift
      ;;
    --yes)
      CONFIRM_PURGE=1
      shift
      ;;
    --json)
      JSON_OUTPUT=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      printf '未知参数：%s\n' "$1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

case "$0" in
  /*) SCRIPT_PATH="$0" ;;
  *) SCRIPT_PATH="$(pwd)/$0" ;;
esac
SCRIPT_DIRECTORY="$(CDPATH='' cd -- "$(dirname -- "$SCRIPT_PATH")" 2>/dev/null && pwd || true)"
if [ "$COMMAND" = "install" ] && \
   [ -z "$SOURCE_BINARY" ] && [ -z "$SOURCE_PACKAGE" ] && \
   [ -n "$SCRIPT_DIRECTORY" ] && [ -x "$SCRIPT_DIRECTORY/smart-printer-edge-server" ]; then
  SOURCE_BINARY="$SCRIPT_DIRECTORY/smart-printer-edge-server"
fi

json_escape() {
  printf '%s' "$1" | /usr/bin/sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
}

emit() {
  event="$1"
  progress="$2"
  message="$3"
  if [ "$JSON_OUTPUT" -eq 1 ]; then
    printf '{"event":"%s","progress":%s,"message":"%s"}\n' \
      "$(json_escape "$event")" "$progress" "$(json_escape "$message")"
  else
    printf '%s\n' "$message"
  fi
}

fail() {
  message="$1"
  if [ "$JSON_OUTPUT" -eq 1 ]; then
    printf '{"event":"error","progress":0,"message":"%s"}\n' \
      "$(json_escape "$message")" >&2
  else
    printf '错误：%s\n' "$message" >&2
  fi
  exit 1
}

require_command() {
  command -v "$1" >/dev/null 2>&1 || fail "缺少必需命令：$1"
}

valid_release_tag() {
  printf '%s\n' "$1" | /usr/bin/awk '
    /^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/ { valid = 1 }
    END { exit valid ? 0 : 1 }
  '
}

config_value() {
  key="$1"
  [ -f "$CONFIG_PATH" ] || return 0
  /usr/bin/awk -F= -v wanted="$key" '
    $1 == wanted {
      sub(/^[^=]*=/, "")
      print
      exit
    }
  ' "$CONFIG_PATH"
}

SYSTEM_NAME="$(/usr/bin/uname -s)"
MACHINE_ARCH="$(/usr/bin/uname -m)"
case "$SYSTEM_NAME" in
  Darwin) PLATFORM="darwin" ;;
  Linux) PLATFORM="linux" ;;
  *) fail "暂不支持的系统：$SYSTEM_NAME" ;;
esac
case "$MACHINE_ARCH" in
  arm64|aarch64) RELEASE_ARCH="arm64" ;;
  armv7l|armv7hl|armv7) RELEASE_ARCH="armv7" ;;
  x86_64|amd64) RELEASE_ARCH="x86_64" ;;
  mips|mipsel|mips64|mips64el|mipsle|mips64le)
    fail "MIPS 尚无经验证的发布包；需要按 32/64 位、大小端、libc 和 ABI 分别构建，不能使用通用 mips 包"
    ;;
  *) fail "暂不支持的处理器架构：$MACHINE_ARCH" ;;
esac

if [ "$PLATFORM" = "darwin" ] && [ "$RELEASE_ARCH" = "armv7" ]; then
  fail "macOS 不支持 armv7 发布包"
fi

if [ "$PLATFORM" = "linux" ]; then
  USER_HOME="${HOME:?HOME 未设置}"
  INSTALL_ROOT="${INSTALL_ROOT_ARG:-$USER_HOME/.local/share/smart-printer}"
  BIN_DIR="$INSTALL_ROOT/bin"
  SERVICE_DIR="$INSTALL_ROOT/service"
  INSTALLED_BINARY="$BIN_DIR/smart-printer-edge-server"
  INSTALLED_CONTROL="$BIN_DIR/smart-printer-edge-ctl"
  CONFIG_PATH="$SERVICE_DIR/service.conf"
  SETUP_CODE_PATH="$SERVICE_DIR/setup-code"
  SYSTEMD_USER_DIR="${SYSTEMD_USER_DIR_ARG:-$USER_HOME/.config/systemd/user}"
  UNIT_PATH="$SYSTEMD_USER_DIR/$LABEL.service"
  DATA_DIR="${DATA_DIR_ARG:-$INSTALL_ROOT/data}"

  linux_config_value() {
    [ -f "$CONFIG_PATH" ] || return 0
    awk -F= -v wanted="$1" '$1 == wanted { sub(/^[^=]*=/, ""); print; exit }' "$CONFIG_PATH"
  }
  HOST="${HOST_ARG:-$(linux_config_value host)}"
  PORT="${PORT_ARG:-$(linux_config_value port)}"
  PUBLIC_URL="${PUBLIC_URL_ARG:-$(linux_config_value public_url)}"
  [ -n "$HOST" ] || HOST=0.0.0.0
  [ -n "$PORT" ] || PORT=6176
  [ -n "$DATA_DIR_ARG" ] || DATA_DIR="$(linux_config_value data_dir)"
  [ -n "$DATA_DIR" ] || DATA_DIR="$INSTALL_ROOT/data"
  case "$PORT" in ''|*[!0-9]*) fail "端口必须是 1 到 65535 的整数" ;; esac
  [ "$PORT" -ge 1 ] && [ "$PORT" -le 65535 ] || fail "端口必须是 1 到 65535 的整数"

  linux_require_user_service() {
    require_command "$SYSTEMCTL"
    "$SYSTEMCTL" --user show-environment >/dev/null 2>&1 || \
      fail "当前用户无法连接 systemd 用户会话；请先登录该 Linux 用户并确认 systemctl --user 可用"
  }
  linux_require_managed_unit() {
    [ -f "$UNIT_PATH" ] && \
      grep -Fq '# Managed by Smart Printer Edge Server installer' "$UNIT_PATH" || \
      fail "找不到由 Smart Printer 管理的 systemd 用户服务：$UNIT_PATH"
  }
  linux_unit_escape() {
    printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/%/%%/g'
  }
  linux_health_url() {
    case "$HOST" in 0.0.0.0|::) health_host=127.0.0.1 ;; *) health_host="$HOST" ;; esac
    case "$health_host" in *:*) health_host="[$health_host]" ;; esac
    printf 'http://%s:%s/healthz' "$health_host" "$PORT"
  }
  linux_dashboard_url() {
    printf '%s' "$(linux_health_url)" | sed 's@/healthz$@@'
  }
  linux_is_running() {
    "$SYSTEMCTL" --user is-active --quiet "$LABEL.service" >/dev/null 2>&1
  }
  linux_is_enabled() {
    "$SYSTEMCTL" --user is-enabled --quiet "$LABEL.service" >/dev/null 2>&1
  }
  linux_is_healthy() {
    "$CURL" --silent --fail --max-time 2 "$(linux_health_url)" >/dev/null 2>&1
  }
  linux_wait_for_health() {
    attempts=0
    while [ "$attempts" -lt 40 ]; do
      linux_is_healthy && return 0
      attempts=$((attempts + 1))
      sleep 0.5
    done
    return 1
  }
  linux_verify_checksum() {
    [ -n "$2" ] || return 0
    if [ -f "$2" ]; then expected="$(awk 'NF { print $1; exit }' "$2")"; else expected="$2"; fi
    actual="$(sha256sum "$1" | awk '{ print $1 }')"
    [ "$actual" = "$expected" ] || fail "SHA-256 校验失败"
  }
  linux_release_tag() {
    case "$1" in v*) tag="$1" ;; *) tag="v$1" ;; esac
    valid_release_tag "$tag" || fail "发布版本必须使用 X.Y.Z 或 vX.Y.Z 格式"
    printf '%s' "$tag"
  }
  linux_latest_version() {
    pointer="$1"
    "$CURL" --fail --location --silent --show-error --max-time 20 \
      "${RELEASE_BASE_URL%/}/version.txt" --output "$pointer"
    tag="$(awk 'NF { print $1; exit }' "$pointer")"
    valid_release_tag "$tag" || fail "发布服务返回了无效版本"
    printf '%s' "$tag"
  }
  linux_version_is_newer() {
    awk -v latest="$1" -v current="$2" 'BEGIN {
      split(latest, l, "."); split(current, c, ".")
      for (i = 1; i <= 3; i++) {
        if ((l[i] + 0) > (c[i] + 0)) exit 0
        if ((l[i] + 0) < (c[i] + 0)) exit 1
      }
      exit 1
    }'
  }
  linux_version() {
    [ -x "$INSTALLED_BINARY" ] || return 0
    "$INSTALLED_BINARY" --version 2>/dev/null | awk 'NR == 1 { print $NF; exit }' || true
  }
  linux_status() {
    installed=false; managed=false; running=false; healthy=false; auto_start=false
    [ -x "$INSTALLED_BINARY" ] && installed=true
    [ -x "$INSTALLED_CONTROL" ] && [ -f "$UNIT_PATH" ] && managed=true
    linux_is_running && running=true
    linux_is_healthy && healthy=true
    linux_is_enabled && auto_start=true
    version="$(linux_version)"
    if [ "$JSON_OUTPUT" -eq 1 ]; then
      printf '{"installed":%s,"managed":%s,"running":%s,"healthy":%s,"autoStart":%s,"version":"%s","host":"%s","port":%s,"url":"%s","installRoot":"%s","dataDir":"%s","logDir":""}\n' \
        "$installed" "$managed" "$running" "$healthy" "$auto_start" \
        "$(json_escape "$version")" "$(json_escape "$HOST")" "$PORT" \
        "$(json_escape "$(linux_dashboard_url)")" \
        "$(json_escape "$INSTALL_ROOT")" "$(json_escape "$DATA_DIR")"
    else
      printf '已安装：%s\n运行中：%s\n健康：%s\n登录后自动启动：%s\n版本：%s\n管理地址：%s\n' \
        "$installed" "$running" "$healthy" "$auto_start" "${version:-未知}" "$(linux_dashboard_url)"
      printf '日志：journalctl --user -u %s.service\n' "$LABEL"
    fi
  }
  linux_check_update() {
    require_command "$CURL"
    pointer="$(mktemp "${TMPDIR:-/tmp}/smart-printer-version.XXXXXX")"
    latest_tag="$(linux_latest_version "$pointer")"
    rm -f "$pointer"
    latest_version="${latest_tag#v}"
    current_version="$(linux_version)"
    [ -n "$current_version" ] || current_version=0.0.0
    update_available=false
    linux_version_is_newer "$latest_version" "$current_version" && update_available=true
    if [ "$JSON_OUTPUT" -eq 1 ]; then
      printf '{"currentVersion":"%s","latestVersion":"%s","updateAvailable":%s,"installSupported":true}\n' \
        "$(json_escape "$current_version")" "$(json_escape "$latest_version")" "$update_available"
    elif [ "$update_available" = true ]; then
      printf '发现新版本：%s（当前 %s）\n' "$latest_version" "$current_version"
    else
      printf '当前已是最新版本：%s\n' "$current_version"
    fi
  }
  linux_start() {
    [ -x "$INSTALLED_BINARY" ] && [ -f "$UNIT_PATH" ] || fail "$PRODUCT_NAME 尚未安装"
    linux_require_managed_unit
    linux_require_user_service
    "$SYSTEMCTL" --user daemon-reload
    "$SYSTEMCTL" --user start "$LABEL.service"
    linux_wait_for_health || fail "服务未通过健康检查；请运行 journalctl --user -u $LABEL.service"
    emit running 100 "$PRODUCT_NAME 已启动"
  }
  linux_stop() {
    linux_require_managed_unit
    linux_require_user_service
    "$SYSTEMCTL" --user stop "$LABEL.service"
    emit stopped 100 "$PRODUCT_NAME 已停止"
  }
  linux_enable() {
    linux_require_managed_unit
    linux_require_user_service
    "$SYSTEMCTL" --user daemon-reload
    "$SYSTEMCTL" --user enable "$LABEL.service"
    emit autostart-enabled 100 "已设置登录后自动启动"
  }
  linux_disable() {
    linux_require_managed_unit
    linux_require_user_service
    "$SYSTEMCTL" --user disable "$LABEL.service"
    emit autostart-disabled 100 "已关闭登录后自动启动；当前服务状态不变"
  }

  LINUX_TEMP_ROOT=""
  LINUX_BACKUP_DIR=""
  LINUX_ROLLBACK=0
  LINUX_WAS_RUNNING=0
  LINUX_WAS_ENABLED=0
  linux_restore_file() {
    if [ -f "$LINUX_BACKUP_DIR/$2" ]; then
      cp "$LINUX_BACKUP_DIR/$2" "$1"
    else
      rm -f "$1"
    fi
  }
  linux_cleanup() {
    result=$?
    trap - EXIT INT TERM
    if [ "$result" -ne 0 ] && [ "$LINUX_ROLLBACK" -eq 1 ]; then
      set +e
      "$SYSTEMCTL" --user stop "$LABEL.service" >/dev/null 2>&1
      linux_restore_file "$INSTALLED_BINARY" binary
      linux_restore_file "$INSTALLED_CONTROL" control
      linux_restore_file "$UNIT_PATH" unit
      linux_restore_file "$CONFIG_PATH" config
      linux_restore_file "$SETUP_CODE_PATH" setup-code
      if [ -f "$LINUX_BACKUP_DIR/database.sqlite3" ]; then
        rm -f "$DATA_DIR/edge-server.sqlite3-wal" "$DATA_DIR/edge-server.sqlite3-shm"
        cp "$LINUX_BACKUP_DIR/database.sqlite3" "$DATA_DIR/edge-server.sqlite3"
      fi
      "$SYSTEMCTL" --user daemon-reload >/dev/null 2>&1
      if [ "$LINUX_WAS_ENABLED" -eq 1 ]; then
        "$SYSTEMCTL" --user enable "$LABEL.service" >/dev/null 2>&1
      else
        "$SYSTEMCTL" --user disable "$LABEL.service" >/dev/null 2>&1
      fi
      [ "$LINUX_WAS_RUNNING" -eq 0 ] || "$SYSTEMCTL" --user start "$LABEL.service" >/dev/null 2>&1
      set -e
    fi
    if [ -n "$LINUX_TEMP_ROOT" ] && [ -d "$LINUX_TEMP_ROOT" ]; then rm -rf "$LINUX_TEMP_ROOT"; fi
    exit "$result"
  }
  linux_install() {
    linux_require_user_service
    require_command "$CURL"
    require_command tar
    require_command sha256sum
    require_command getconf
    if ! getconf GNU_LIBC_VERSION >/dev/null 2>&1; then
      fail "当前 Linux 不是 glibc 环境；此发布包暂不支持 musl 或 uClibc"
    fi
    case "$LABEL" in
      ''|*[!a-zA-Z0-9_.-]*) fail "Linux 服务名称只能包含字母、数字、点、下划线和连字符" ;;
    esac
    if [ -n "$SOURCE_BINARY" ] && [ -n "$SOURCE_PACKAGE" ]; then
      fail "--binary 和 --package 不能同时使用"
    fi
    if [ -f "$UNIT_PATH" ] && ! grep -Fq '# Managed by Smart Printer Edge Server installer' "$UNIT_PATH"; then
      fail "同名 systemd 用户服务已存在，拒绝覆盖：$UNIT_PATH"
    fi
    case "$HOST$PUBLIC_URL$INSTALL_ROOT$DATA_DIR$LABEL" in
      *'
'*) fail "Linux 服务配置不能包含换行符" ;;
    esac
    LINUX_TEMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/smart-printer-install.XXXXXX")"
    trap linux_cleanup EXIT INT TERM
    installer_source=""
    expected_release_version=""
    if [ -n "$SOURCE_BINARY" ]; then
      [ -f "$SOURCE_BINARY" ] || fail "找不到本地 Edge Server：$SOURCE_BINARY"
      linux_verify_checksum "$SOURCE_BINARY" "$SOURCE_CHECKSUM"
      candidate="$LINUX_TEMP_ROOT/smart-printer-edge-server"
      cp "$SOURCE_BINARY" "$candidate"
    else
      package_path="$SOURCE_PACKAGE"
      if [ -z "$package_path" ]; then
        if [ -n "$REQUESTED_VERSION" ]; then
          release_tag="$(linux_release_tag "$REQUESTED_VERSION")"
        else
          release_tag="$(linux_latest_version "$LINUX_TEMP_ROOT/version.txt")"
        fi
        expected_release_version="${release_tag#v}"
        asset="smart-printer-edge-server-linux-$RELEASE_ARCH.tar.gz"
        release_url="${RELEASE_ROOT_URL%/}/$release_tag"
        package_path="$LINUX_TEMP_ROOT/$asset"
        emit download 10 "正在下载 $PRODUCT_NAME（Linux $RELEASE_ARCH）"
        "$CURL" --fail --location --silent --show-error --max-time 120 \
          "$release_url/$asset" --output "$package_path"
        checksum_path="$LINUX_TEMP_ROOT/$asset.sha256"
        "$CURL" --fail --location --silent --show-error --max-time 30 \
          "$release_url/$asset.sha256" --output "$checksum_path"
        SOURCE_CHECKSUM="$checksum_path"
      fi
      [ -f "$package_path" ] || fail "找不到发布包：$package_path"
      linux_verify_checksum "$package_path" "$SOURCE_CHECKSUM"
      mkdir -p "$LINUX_TEMP_ROOT/package"
      tar -xzf "$package_path" -C "$LINUX_TEMP_ROOT/package"
      candidate="$LINUX_TEMP_ROOT/package/smart-printer-edge-server"
      [ -f "$candidate" ] || fail "发布包中缺少 smart-printer-edge-server"
      [ ! -f "$LINUX_TEMP_ROOT/package/install.sh" ] || \
        installer_source="$LINUX_TEMP_ROOT/package/install.sh"
    fi
    chmod 755 "$candidate"
    if [ -n "$REQUESTED_VERSION" ] || [ -n "$expected_release_version" ]; then
      expected_version="${expected_release_version:-${REQUESTED_VERSION#v}}"
      candidate_version="$("$candidate" --version | awk 'NR == 1 { print $NF; exit }')"
      [ "$candidate_version" = "$expected_version" ] || fail "发布包版本不匹配"
    fi
    if [ -z "$installer_source" ]; then
      case "$SCRIPT_PATH" in
        */install.sh|*/smart-printer-edge-ctl)
          [ ! -f "$SCRIPT_PATH" ] || installer_source="$SCRIPT_PATH"
          ;;
      esac
    fi
    [ -n "$installer_source" ] || fail "无法找到安装器脚本副本"
    emit validate 20 "正在验证发布文件和现有数据"
    mkdir -p "$LINUX_TEMP_ROOT/data-check" "$INSTALL_ROOT" "$BIN_DIR" "$SERVICE_DIR" "$DATA_DIR" "$SYSTEMD_USER_DIR"
    chmod 700 "$INSTALL_ROOT" "$BIN_DIR" "$SERVICE_DIR" "$DATA_DIR"
    for legacy in config.json jobs.json pairing-token; do
      [ ! -f "$DATA_DIR/$legacy" ] || cp "$DATA_DIR/$legacy" "$LINUX_TEMP_ROOT/data-check/$legacy"
    done
    database="$DATA_DIR/edge-server.sqlite3"
    stamp="$(date -u '+%Y%m%dT%H%M%SZ')-$$"
    LINUX_BACKUP_DIR="$DATA_DIR/backups/edge-install-$stamp"
    mkdir -p "$LINUX_BACKUP_DIR"
    chmod 700 "$LINUX_BACKUP_DIR"
    if [ -f "$database" ]; then
      require_command sqlite3
      escaped_backup="$(printf '%s' "$LINUX_BACKUP_DIR/database.sqlite3" | sed 's/"/""/g')"
      sqlite3 "$database" ".backup \"$escaped_backup\""
      cp "$LINUX_BACKUP_DIR/database.sqlite3" "$LINUX_TEMP_ROOT/data-check/edge-server.sqlite3"
    fi
    if [ -f "$SETUP_CODE_PATH" ]; then
      setup_code="$(head -n 1 "$SETUP_CODE_PATH")"
    else
      setup_code="$(od -An -N3 -tu4 /dev/urandom | tr -d ' ')"
      setup_code="$(printf '%06d' "$((setup_code % 1000000))")"
    fi
    SMART_PRINTER_DATA_DIR="$LINUX_TEMP_ROOT/data-check" \
      SMART_PRINTER_SETUP_CODE="$setup_code" \
      SMART_PRINTER_HOST="$HOST" SMART_PRINTER_PORT="$PORT" \
      SMART_PRINTER_PUBLIC_URL="$PUBLIC_URL" \
      "$candidate" --check-data >/dev/null
    linux_is_running && LINUX_WAS_RUNNING=1
    linux_is_enabled && LINUX_WAS_ENABLED=1
    for entry in "binary:$INSTALLED_BINARY" "control:$INSTALLED_CONTROL" \
      "unit:$UNIT_PATH" "config:$CONFIG_PATH" "setup-code:$SETUP_CODE_PATH"; do
      backup_name="${entry%%:*}"
      backup_path="${entry#*:}"
      [ ! -f "$backup_path" ] || cp "$backup_path" "$LINUX_BACKUP_DIR/$backup_name"
    done
    if [ -z "$AUTO_START_REQUEST" ]; then
      if [ "$LINUX_WAS_ENABLED" -eq 1 ] || [ ! -f "$INSTALLED_BINARY" ]; then
        AUTO_START_REQUEST=1
      else
        AUTO_START_REQUEST=0
      fi
    fi
    LINUX_ROLLBACK=1
    emit stop 35 "正在停止旧服务"
    "$SYSTEMCTL" --user stop "$LABEL.service" >/dev/null 2>&1 || true
    emit copy 50 "正在安装 Edge Server"
    cp "$candidate" "$INSTALLED_BINARY.new"
    chmod 755 "$INSTALLED_BINARY.new"
    mv -f "$INSTALLED_BINARY.new" "$INSTALLED_BINARY"
    cp "$installer_source" "$INSTALLED_CONTROL.new"
    chmod 755 "$INSTALLED_CONTROL.new"
    mv -f "$INSTALLED_CONTROL.new" "$INSTALLED_CONTROL"
    printf '%s\n' "$setup_code" > "$SETUP_CODE_PATH.new"
    chmod 600 "$SETUP_CODE_PATH.new"
    mv -f "$SETUP_CODE_PATH.new" "$SETUP_CODE_PATH"
    {
      printf 'host=%s\nport=%s\npublic_url=%s\ndata_dir=%s\n' "$HOST" "$PORT" "$PUBLIC_URL" "$DATA_DIR"
    } > "$CONFIG_PATH.new"
    chmod 600 "$CONFIG_PATH.new"
    mv -f "$CONFIG_PATH.new" "$CONFIG_PATH"
    escaped_binary="$(linux_unit_escape "$INSTALLED_BINARY")"
    escaped_root="$(linux_unit_escape "$INSTALL_ROOT")"
    escaped_data="$(linux_unit_escape "$DATA_DIR")"
    escaped_host="$(linux_unit_escape "$HOST")"
    escaped_public_url="$(linux_unit_escape "$PUBLIC_URL")"
    cat > "$UNIT_PATH.new" <<EOF
# Managed by Smart Printer Edge Server installer
[Unit]
Description=Smart Printer Edge Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart="$escaped_binary"
WorkingDirectory="$escaped_root"
Environment="PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
Environment="RUST_LOG=smart_printer_edge_server=info"
Environment="SMART_PRINTER_DATA_DIR=$escaped_data"
Environment="SMART_PRINTER_HOST=$escaped_host"
Environment="SMART_PRINTER_PORT=$PORT"
Environment="SMART_PRINTER_PUBLIC_URL=$escaped_public_url"
Environment="SMART_PRINTER_SETUP_CODE=$setup_code"
Restart=on-failure
RestartSec=3

[Install]
WantedBy=default.target
EOF
    chmod 600 "$UNIT_PATH.new"
    mv -f "$UNIT_PATH.new" "$UNIT_PATH"
    "$SYSTEMCTL" --user daemon-reload
    if [ "$AUTO_START_REQUEST" -eq 1 ]; then
      "$SYSTEMCTL" --user enable "$LABEL.service" >/dev/null
    else
      "$SYSTEMCTL" --user disable "$LABEL.service" >/dev/null 2>&1 || true
    fi
    if [ "$NO_START" -eq 0 ]; then
      emit start 70 "正在启动 Edge Server"
      "$SYSTEMCTL" --user start "$LABEL.service"
      linux_wait_for_health || fail "新服务未通过健康检查；旧版本将自动恢复"
    fi
    installed_version="$(linux_version)"
    LINUX_ROLLBACK=0
    emit complete 100 "$PRODUCT_NAME $installed_version 已安装；现有数据和配对信息已保留"
    if [ "$JSON_OUTPUT" -eq 0 ]; then
      printf '安装位置：%s\n数据目录：%s\n迁移备份：%s\n首次管理初始化验证码：%s\n' \
        "$INSTALLED_BINARY" "$DATA_DIR" "$LINUX_BACKUP_DIR" "$setup_code"
    fi
  }
  linux_uninstall() {
    linux_require_managed_unit
    if [ "$PURGE_DATA" -eq 1 ] && [ "$CONFIRM_PURGE" -ne 1 ]; then
      fail "删除历史和配对信息需要同时传入 --purge-data --yes"
    fi
    if [ "$PURGE_DATA" -eq 1 ]; then
      case "$DATA_DIR" in
        "$INSTALL_ROOT"/data|"$INSTALL_ROOT"/data/*) ;;
        *) fail "拒绝自动删除自定义数据目录：$DATA_DIR" ;;
      esac
    fi
    linux_require_user_service
    "$SYSTEMCTL" --user stop "$LABEL.service" >/dev/null 2>&1 || true
    "$SYSTEMCTL" --user disable "$LABEL.service" >/dev/null 2>&1 || true
    rm -f "$UNIT_PATH" "$CONFIG_PATH" "$SETUP_CODE_PATH" "$INSTALLED_BINARY" "$INSTALLED_CONTROL"
    "$SYSTEMCTL" --user daemon-reload
    if [ "$PURGE_DATA" -eq 1 ]; then
      rm -rf "$DATA_DIR"
      emit uninstalled 100 "$PRODUCT_NAME 已卸载，历史和配对信息已删除"
    else
      emit uninstalled 100 "$PRODUCT_NAME 已卸载；历史、文件和配对信息仍保留在 $DATA_DIR"
    fi
  }

  case "$COMMAND" in
    install|upgrade) linux_install ;;
    start) linux_start ;;
    stop) linux_stop ;;
    restart) linux_stop; linux_start ;;
    enable) linux_enable ;;
    disable) linux_disable ;;
    status) linux_status ;;
    check-update) linux_check_update ;;
    doctor)
      linux_require_user_service
      for required in lp lpstat lpoptions cancel img2pdf; do require_command "$required"; done
      linux_status
      command -v libreoffice >/dev/null 2>&1 || \
        emit doctor 100 "Office 文件还需要安装 LibreOffice；PDF 和图片不受影响"
      ;;
    uninstall) linux_uninstall ;;
    help) usage ;;
  esac
  exit 0
fi

USER_HOME="${HOME:?HOME 未设置}"
INSTALL_ROOT="${INSTALL_ROOT_ARG:-$USER_HOME/Library/Application Support/Smart Printer}"
BIN_DIR="$INSTALL_ROOT/bin"
SERVICE_DIR="$INSTALL_ROOT/service"
INSTALLED_BINARY="$BIN_DIR/smart-printer-edge-server"
INSTALLED_CONTROL="$BIN_DIR/smart-printer-edge-ctl"
CONFIG_PATH="$SERVICE_DIR/service.conf"
CANONICAL_PLIST="$SERVICE_DIR/$LABEL.plist"
LAUNCH_AGENTS_DIR="${LAUNCH_AGENTS_DIR_ARG:-$USER_HOME/Library/LaunchAgents}"
AUTOSTART_PLIST="$LAUNCH_AGENTS_DIR/$LABEL.plist"
DOMAIN="gui/$(/usr/bin/id -u)"
SERVICE_TARGET="$DOMAIN/$LABEL"

plist_environment_value() {
  environment_key="$1"
  plist_to_read=""
  if [ -f "$CANONICAL_PLIST" ]; then
    plist_to_read="$CANONICAL_PLIST"
  elif [ -f "$AUTOSTART_PLIST" ]; then
    plist_to_read="$AUTOSTART_PLIST"
  fi
  if [ -n "$plist_to_read" ] && [ -x /usr/libexec/PlistBuddy ]; then
    /usr/libexec/PlistBuddy \
      -c "Print :EnvironmentVariables:$environment_key" \
      "$plist_to_read" 2>/dev/null || true
  fi
}

saved_host="$(config_value host || true)"
saved_port="$(config_value port || true)"
saved_public_url="$(config_value public_url || true)"
saved_data_dir="$(config_value data_dir || true)"
if [ -z "$saved_host" ]; then saved_host="$(plist_environment_value SMART_PRINTER_HOST)"; fi
if [ -z "$saved_port" ]; then saved_port="$(plist_environment_value SMART_PRINTER_PORT)"; fi
if [ -z "$saved_public_url" ]; then saved_public_url="$(plist_environment_value SMART_PRINTER_PUBLIC_URL)"; fi
if [ -z "$saved_data_dir" ]; then saved_data_dir="$(plist_environment_value SMART_PRINTER_DATA_DIR)"; fi
HOST="${HOST_ARG:-${saved_host:-0.0.0.0}}"
PORT="${PORT_ARG:-${saved_port:-6176}}"
PUBLIC_URL="${PUBLIC_URL_ARG:-$saved_public_url}"
DATA_DIR="${DATA_DIR_ARG:-${saved_data_dir:-$INSTALL_ROOT/data}}"
LOGS_DIR="$DATA_DIR/logs"

case "$PORT" in
  ''|*[!0-9]*) fail "端口必须是 1 到 65535 的整数" ;;
esac
[ "$PORT" -ge 1 ] && [ "$PORT" -le 65535 ] || fail "端口必须是 1 到 65535 的整数"

health_host() {
  case "$HOST" in
    0.0.0.0|::) printf '127.0.0.1' ;;
    *) printf '%s' "$HOST" ;;
  esac
}

health_url() {
  resolved_host="$(health_host)"
  case "$resolved_host" in
    *:*) resolved_host="[$resolved_host]" ;;
  esac
  printf 'http://%s:%s/healthz' "$resolved_host" "$PORT"
}

dashboard_url() {
  resolved_host="$(health_host)"
  case "$resolved_host" in
    *:*) resolved_host="[$resolved_host]" ;;
  esac
  printf 'http://%s:%s' "$resolved_host" "$PORT"
}

service_is_loaded() {
  "$LAUNCHCTL" print "$SERVICE_TARGET" >/dev/null 2>&1
}

service_is_healthy() {
  [ -x "$CURL" ] || command -v "$CURL" >/dev/null 2>&1 || return 1
  "$CURL" --silent --show-error --fail --max-time 2 "$(health_url)" >/dev/null 2>&1
}

wait_for_health() {
  attempts=0
  while [ "$attempts" -lt 40 ]; do
    if service_is_healthy; then
      return 0
    fi
    attempts=$((attempts + 1))
    /bin/sleep 0.5
  done
  return 1
}

bootout_service() {
  if service_is_loaded; then
    "$LAUNCHCTL" bootout "$SERVICE_TARGET" >/dev/null 2>&1 || \
      "$LAUNCHCTL" bootout "$DOMAIN" "$CANONICAL_PLIST" >/dev/null 2>&1 || true
  fi
}

start_service() {
  [ -x "$INSTALLED_BINARY" ] || fail "$PRODUCT_NAME 尚未安装"
  [ -f "$CANONICAL_PLIST" ] || fail "服务定义不存在，请重新安装"
  if service_is_loaded && service_is_healthy; then
    emit "running" 100 "$PRODUCT_NAME 已经在运行"
    return 0
  fi
  bootout_service
  "$LAUNCHCTL" bootstrap "$DOMAIN" "$CANONICAL_PLIST" >/dev/null
  "$LAUNCHCTL" kickstart -k "$SERVICE_TARGET" >/dev/null
  wait_for_health || fail "服务已启动，但健康检查未通过；请查看 $LOGS_DIR/service-error.log"
  emit "running" 100 "$PRODUCT_NAME 已启动"
}

stop_service() {
  if service_is_loaded; then
    bootout_service
    emit "stopped" 100 "$PRODUCT_NAME 已停止；登录自动启动设置保持不变"
  else
    emit "stopped" 100 "$PRODUCT_NAME 当前未运行"
  fi
}

enable_autostart() {
  [ -f "$CANONICAL_PLIST" ] || fail "服务定义不存在，请先安装"
  /bin/mkdir -p "$LAUNCH_AGENTS_DIR"
  /bin/cp "$CANONICAL_PLIST" "$AUTOSTART_PLIST.new"
  /bin/chmod 600 "$AUTOSTART_PLIST.new"
  /bin/mv -f "$AUTOSTART_PLIST.new" "$AUTOSTART_PLIST"
  emit "autostart-enabled" 100 "已设置登录后自动启动"
}

disable_autostart() {
  /bin/rm -f "$AUTOSTART_PLIST"
  emit "autostart-disabled" 100 "已关闭登录后自动启动；当前服务状态不变"
}

print_status() {
  installed=false
  managed=false
  loaded=false
  healthy=false
  autostart=false
  version=""
  [ -x "$INSTALLED_BINARY" ] && installed=true
  [ -x "$INSTALLED_CONTROL" ] && [ -f "$CANONICAL_PLIST" ] && managed=true
  service_is_loaded && loaded=true
  service_is_healthy && healthy=true
  [ -f "$AUTOSTART_PLIST" ] && autostart=true
  if [ "$installed" = true ]; then
    version_output="$("$INSTALLED_BINARY" --version 2>/dev/null || true)"
    version="$(printf '%s' "$version_output" | /usr/bin/awk 'NR == 1 { print $NF; exit }')"
  fi
  if [ -z "$version" ] && [ "$healthy" = true ]; then
    health_document="$("$CURL" --silent --fail --max-time 2 "$(health_url)" 2>/dev/null || true)"
    version="$(printf '%s' "$health_document" | /usr/bin/sed -n \
      's/.*"serverVersion"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
  fi

  if [ "$JSON_OUTPUT" -eq 1 ]; then
    printf '{"installed":%s,"managed":%s,"running":%s,"healthy":%s,"autoStart":%s,"version":"%s","host":"%s","port":%s,"url":"%s","installRoot":"%s","dataDir":"%s","logDir":"%s"}\n' \
      "$installed" "$managed" "$loaded" "$healthy" "$autostart" \
      "$(json_escape "$version")" "$(json_escape "$HOST")" "$PORT" \
      "$(json_escape "$(dashboard_url)")" \
      "$(json_escape "$INSTALL_ROOT")" "$(json_escape "$DATA_DIR")" \
      "$(json_escape "$LOGS_DIR")"
  else
    printf '已安装：%s\n' "$installed"
    printf '已由统一安装器管理：%s\n' "$managed"
    printf '运行中：%s\n' "$loaded"
    printf '健康：%s\n' "$healthy"
    printf '登录后自动启动：%s\n' "$autostart"
    printf '版本：%s\n' "${version:-未知}"
    printf '管理地址：%s\n' "$(dashboard_url)"
    printf '数据目录：%s\n' "$DATA_DIR"
  fi
}

version_is_newer() {
  latest="$1"
  current="$2"
  /usr/bin/awk -v latest="$latest" -v current="$current" '
    BEGIN {
      split(latest, l, "."); split(current, c, ".")
      for (i = 1; i <= 3; i++) {
        if ((l[i] + 0) > (c[i] + 0)) exit 0
        if ((l[i] + 0) < (c[i] + 0)) exit 1
      }
      exit 1
    }
  '
}

print_update_status() {
  require_command "$CURL"
  latest_pointer="$(/usr/bin/mktemp "${TMPDIR:-/tmp}/smart-printer-version.XXXXXX")"
  trap '/bin/rm -f "$latest_pointer"' EXIT INT TERM
  version_url="${RELEASE_BASE_URL%/}/version.txt"
  case "$version_url" in
    http://*|https://*) version_url="$version_url?checkedAt=$(/bin/date +%s)" ;;
  esac
  "$CURL" --fail --location --silent --show-error --max-time 12 \
    "$version_url" \
    --output "$latest_pointer"
  latest_tag="$(/usr/bin/awk 'NF { print $1; exit }' "$latest_pointer")"
  valid_release_tag "$latest_tag" || fail "发布服务返回了无效版本"
  latest_version="${latest_tag#v}"
  current_version=""
  if [ -x "$INSTALLED_BINARY" ]; then
    current_version="$("$INSTALLED_BINARY" --version 2>/dev/null | /usr/bin/awk 'NR == 1 { print $NF; exit }')"
  fi
  [ -n "$current_version" ] || current_version="0.0.0"
  update_available=false
  if version_is_newer "$latest_version" "$current_version"; then
    update_available=true
  fi
  if [ "$JSON_OUTPUT" -eq 1 ]; then
    printf '{"currentVersion":"%s","latestVersion":"%s","updateAvailable":%s,"installSupported":true}\n' \
      "$(json_escape "$current_version")" "$(json_escape "$latest_version")" "$update_available"
  elif [ "$update_available" = true ]; then
    printf '发现新版本：%s（当前 %s）\n' "$latest_version" "$current_version"
    printf '运行 smart-printer-edge-ctl upgrade --version %s 即可更新。\n' "$latest_version"
  else
    printf '当前已是最新版本：%s\n' "$current_version"
  fi
  /bin/rm -f "$latest_pointer"
  trap cleanup EXIT INT TERM
}

verify_checksum() {
  source_path="$1"
  checksum_input="$2"
  [ -n "$checksum_input" ] || return 0
  if [ -f "$checksum_input" ]; then
    expected="$(/usr/bin/awk 'NF { print $1; exit }' "$checksum_input")"
  else
    expected="$checksum_input"
  fi
  actual="$(/usr/bin/shasum -a 256 "$source_path" | /usr/bin/awk '{ print $1 }')"
  [ "$actual" = "$expected" ] || fail "SHA-256 校验失败"
}

xml_escape() {
  printf '%s' "$1" | /usr/bin/sed \
    -e 's/&/\&amp;/g' \
    -e 's/</\&lt;/g' \
    -e 's/>/\&gt;/g' \
    -e 's/"/\&quot;/g' \
    -e "s/'/\\&apos;/g"
}

generate_setup_code() {
  random_number="$(/usr/bin/od -An -N4 -tu4 /dev/urandom | /usr/bin/tr -d ' ')"
  printf '%06d' "$((random_number % 1000000))"
}

read_existing_setup_code() {
  plist_to_read=""
  if [ -f "$CANONICAL_PLIST" ]; then
    plist_to_read="$CANONICAL_PLIST"
  elif [ -f "$AUTOSTART_PLIST" ]; then
    plist_to_read="$AUTOSTART_PLIST"
  fi
  if [ -n "$plist_to_read" ] && [ -x /usr/libexec/PlistBuddy ]; then
    /usr/libexec/PlistBuddy \
      -c 'Print :EnvironmentVariables:SMART_PRINTER_SETUP_CODE' \
      "$plist_to_read" 2>/dev/null || true
  fi
}

TEMP_ROOT=""
ROLLBACK_ARMED=0
INSTALL_COMPLETE=0
BACKUP_DIR=""
WAS_RUNNING=0
HAD_BINARY=0
HAD_CANONICAL_PLIST=0
HAD_AUTOSTART_PLIST=0
HAD_CONFIG=0
HAD_DATABASE=0

rollback_install() {
  [ "$ROLLBACK_ARMED" -eq 1 ] || return 0
  set +e
  bootout_service
  if [ "$HAD_BINARY" -eq 1 ]; then
    /bin/cp "$BACKUP_DIR/smart-printer-edge-server" "$INSTALLED_BINARY"
    /bin/chmod 755 "$INSTALLED_BINARY"
  else
    /bin/rm -f "$INSTALLED_BINARY"
  fi
  if [ "$HAD_CANONICAL_PLIST" -eq 1 ]; then
    /bin/cp "$BACKUP_DIR/canonical.plist" "$CANONICAL_PLIST"
  else
    /bin/rm -f "$CANONICAL_PLIST"
  fi
  if [ "$HAD_AUTOSTART_PLIST" -eq 1 ]; then
    /bin/cp "$BACKUP_DIR/autostart.plist" "$AUTOSTART_PLIST"
  else
    /bin/rm -f "$AUTOSTART_PLIST"
  fi
  if [ "$HAD_CONFIG" -eq 1 ]; then
    /bin/cp "$BACKUP_DIR/service.conf" "$CONFIG_PATH"
  else
    /bin/rm -f "$CONFIG_PATH"
  fi
  database_path="$DATA_DIR/edge-server.sqlite3"
  if [ "$HAD_DATABASE" -eq 1 ] && [ -f "$BACKUP_DIR/edge-server.sqlite3" ]; then
    /bin/rm -f "$database_path-wal" "$database_path-shm"
    /bin/cp "$BACKUP_DIR/edge-server.sqlite3" "$database_path"
    /bin/chmod 600 "$database_path"
  elif [ "$HAD_DATABASE" -eq 0 ]; then
    /bin/rm -f "$database_path" "$database_path-wal" "$database_path-shm"
  fi
  if [ "$WAS_RUNNING" -eq 1 ] && [ -f "$CANONICAL_PLIST" ]; then
    "$LAUNCHCTL" bootstrap "$DOMAIN" "$CANONICAL_PLIST" >/dev/null 2>&1
    "$LAUNCHCTL" kickstart -k "$SERVICE_TARGET" >/dev/null 2>&1
  fi
  set -e
}

cleanup() {
  result=$?
  trap - EXIT INT TERM
  if [ "$result" -ne 0 ] && [ "$INSTALL_COMPLETE" -eq 0 ]; then
    rollback_install
  fi
  if [ -n "$TEMP_ROOT" ] && [ -d "$TEMP_ROOT" ]; then
    /bin/rm -rf "$TEMP_ROOT"
  fi
  exit "$result"
}
trap cleanup EXIT INT TERM

install_server() {
  require_command /usr/bin/tar
  require_command /usr/bin/shasum
  require_command "$CURL"
  require_command "$LAUNCHCTL"

  TEMP_ROOT="$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/smart-printer-install.XXXXXX")"
  candidate=""
  installer_source=""

  if [ -n "$SOURCE_BINARY" ] && [ -n "$SOURCE_PACKAGE" ]; then
    fail "--binary 和 --package 不能同时使用"
  fi

  if [ -n "$SOURCE_BINARY" ]; then
    [ -f "$SOURCE_BINARY" ] || fail "找不到本地 Edge Server：$SOURCE_BINARY"
    verify_checksum "$SOURCE_BINARY" "$SOURCE_CHECKSUM"
    candidate="$SOURCE_BINARY"
  else
    package_path="$SOURCE_PACKAGE"
    if [ -z "$package_path" ]; then
      asset="smart-printer-edge-server-$PLATFORM-$RELEASE_ARCH.tar.gz"
      if [ -n "$REQUESTED_VERSION" ]; then
        case "$REQUESTED_VERSION" in
          v*) release_tag="$REQUESTED_VERSION" ;;
          *) release_tag="v$REQUESTED_VERSION" ;;
        esac
        valid_release_tag "$release_tag" || \
          fail "指定版本必须使用 X.Y.Z 或 vX.Y.Z 格式"
        release_url="${RELEASE_ROOT_URL%/}/$release_tag"
      else
        # latest/version.txt is published last. Following that pointer keeps an
        # install on one immutable release even while latest is being updated.
        latest_pointer="$TEMP_ROOT/version.txt"
        if "$CURL" --fail --location --silent --show-error \
          "${RELEASE_BASE_URL%/}/version.txt" --output "$latest_pointer"; then
          release_tag="$(/usr/bin/awk 'NF { print $1; exit }' "$latest_pointer")"
          valid_release_tag "$release_tag" || \
            fail "latest/version.txt 中的版本格式无效"
          release_url="${RELEASE_ROOT_URL%/}/$release_tag"
        else
          # Compatibility with deployments published before version.txt.
          release_url="${RELEASE_BASE_URL%/}"
        fi
      fi
      package_path="$TEMP_ROOT/$asset"
      emit "download" 10 "正在下载 $PRODUCT_NAME"
      "$CURL" --fail --location --silent --show-error \
        "$release_url/$asset" --output "$package_path"
      checksum_path="$TEMP_ROOT/$asset.sha256"
      "$CURL" --fail --location --silent --show-error \
        "$release_url/$asset.sha256" --output "$checksum_path"
      SOURCE_CHECKSUM="$checksum_path"
    fi
    [ -f "$package_path" ] || fail "找不到发布包：$package_path"
    verify_checksum "$package_path" "$SOURCE_CHECKSUM"
    extract_dir="$TEMP_ROOT/package"
    /bin/mkdir -p "$extract_dir"
    /usr/bin/tar -xzf "$package_path" -C "$extract_dir"
    for candidate_path in \
      "$extract_dir/smart-printer-edge-server" \
      "$extract_dir/bin/smart-printer-edge-server"; do
      if [ -f "$candidate_path" ]; then
        candidate="$candidate_path"
        break
      fi
    done
    [ -n "$candidate" ] || fail "发布包中缺少 smart-printer-edge-server"
    if [ -f "$extract_dir/install.sh" ]; then
      installer_source="$extract_dir/install.sh"
    fi
  fi

  /bin/chmod 755 "$candidate"
  if [ -n "$REQUESTED_VERSION" ]; then
    expected_version="${REQUESTED_VERSION#v}"
    candidate_version_output="$("$candidate" --version 2>/dev/null || true)"
    candidate_version="$(printf '%s' "$candidate_version_output" | /usr/bin/awk 'NR == 1 { print $NF; exit }')"
    [ "$candidate_version" = "$expected_version" ] || \
      fail "发布包版本不匹配：请求 $expected_version，实际 ${candidate_version:-未知}"
  fi
  if [ -z "$installer_source" ]; then
    case "$SCRIPT_PATH" in
      */install.sh|*/smart-printer-edge-ctl)
        [ -f "$SCRIPT_PATH" ] && installer_source="$SCRIPT_PATH"
        ;;
    esac
  fi

  emit "validate" 20 "正在验证发布文件和现有数据"
  check_dir="$TEMP_ROOT/data-check"
  /bin/mkdir -p "$check_dir"

  /bin/mkdir -p "$INSTALL_ROOT" "$BIN_DIR" "$SERVICE_DIR" "$DATA_DIR" "$LOGS_DIR" "$LAUNCH_AGENTS_DIR"
  /bin/chmod 700 "$INSTALL_ROOT" "$BIN_DIR" "$SERVICE_DIR" "$DATA_DIR" "$LOGS_DIR"
  for log_name in service.log service-error.log; do
    /usr/bin/touch "$LOGS_DIR/$log_name"
    /bin/chmod 600 "$LOGS_DIR/$log_name"
  done

  stamp="$(/bin/date -u '+%Y%m%dT%H%M%SZ')-$$"
  BACKUP_DIR="$DATA_DIR/backups/edge-install-$stamp"
  /bin/mkdir -p "$BACKUP_DIR"
  /bin/chmod 700 "$BACKUP_DIR"

  for legacy_name in config.json jobs.json pairing-token; do
    if [ -f "$DATA_DIR/$legacy_name" ]; then
      /bin/cp "$DATA_DIR/$legacy_name" "$BACKUP_DIR/$legacy_name"
      /bin/cp "$DATA_DIR/$legacy_name" "$check_dir/$legacy_name"
      /bin/chmod 600 "$BACKUP_DIR/$legacy_name" "$check_dir/$legacy_name"
    fi
  done

  database_path="$DATA_DIR/edge-server.sqlite3"
  expected_jobs=""
  if [ -f "$database_path" ]; then
    HAD_DATABASE=1
    require_command /usr/bin/sqlite3
    escaped_database_backup="$(printf '%s' "$BACKUP_DIR/edge-server.sqlite3" | /usr/bin/sed 's/"/""/g')"
    /usr/bin/sqlite3 "$database_path" ".backup \"$escaped_database_backup\""
    /bin/chmod 600 "$BACKUP_DIR/edge-server.sqlite3"
    /bin/cp "$BACKUP_DIR/edge-server.sqlite3" "$check_dir/edge-server.sqlite3"
    expected_jobs="$(/usr/bin/sqlite3 "$database_path" 'SELECT COUNT(*) FROM jobs;' 2>/dev/null || true)"
  fi

  setup_code="$(read_existing_setup_code)"
  [ -n "$setup_code" ] || setup_code="$(generate_setup_code)"
  SMART_PRINTER_DATA_DIR="$check_dir" \
    SMART_PRINTER_SETUP_CODE="$setup_code" \
    SMART_PRINTER_HOST="$HOST" \
    SMART_PRINTER_PORT="$PORT" \
    SMART_PRINTER_PUBLIC_URL="$PUBLIC_URL" \
    "$candidate" --check-data >/dev/null
  if [ -z "$expected_jobs" ] && [ -f "$check_dir/edge-server.sqlite3" ]; then
    require_command /usr/bin/sqlite3
    expected_jobs="$(/usr/bin/sqlite3 "$check_dir/edge-server.sqlite3" 'SELECT COUNT(*) FROM jobs;' 2>/dev/null || true)"
  fi

  if service_is_loaded; then WAS_RUNNING=1; fi
  if [ -f "$INSTALLED_BINARY" ]; then
    HAD_BINARY=1
    /bin/cp "$INSTALLED_BINARY" "$BACKUP_DIR/smart-printer-edge-server"
  fi
  if [ -f "$CANONICAL_PLIST" ]; then
    HAD_CANONICAL_PLIST=1
    /bin/cp "$CANONICAL_PLIST" "$BACKUP_DIR/canonical.plist"
  fi
  if [ -f "$AUTOSTART_PLIST" ]; then
    HAD_AUTOSTART_PLIST=1
    /bin/cp "$AUTOSTART_PLIST" "$BACKUP_DIR/autostart.plist"
  fi
  if [ -f "$CONFIG_PATH" ]; then
    HAD_CONFIG=1
    /bin/cp "$CONFIG_PATH" "$BACKUP_DIR/service.conf"
  fi
  if [ -z "$AUTO_START_REQUEST" ]; then
    if [ "$HAD_AUTOSTART_PLIST" -eq 1 ] || [ "$HAD_BINARY" -eq 0 ]; then
      AUTO_START_REQUEST=1
    else
      AUTO_START_REQUEST=0
    fi
  fi

  ROLLBACK_ARMED=1
  emit "stop" 35 "正在停止旧服务"
  bootout_service

  emit "copy" 50 "正在安装 Edge Server"
  /bin/cp "$candidate" "$INSTALLED_BINARY.new"
  /bin/chmod 755 "$INSTALLED_BINARY.new"
  /bin/mv -f "$INSTALLED_BINARY.new" "$INSTALLED_BINARY"
  if [ -n "$installer_source" ]; then
    /bin/cp "$installer_source" "$INSTALLED_CONTROL.new"
    /bin/chmod 755 "$INSTALLED_CONTROL.new"
    /bin/mv -f "$INSTALLED_CONTROL.new" "$INSTALLED_CONTROL"
  fi

  config_temp="$CONFIG_PATH.new"
  {
    printf 'host=%s\n' "$HOST"
    printf 'port=%s\n' "$PORT"
    printf 'public_url=%s\n' "$PUBLIC_URL"
    printf 'data_dir=%s\n' "$DATA_DIR"
  } > "$config_temp"
  /bin/chmod 600 "$config_temp"
  /bin/mv -f "$config_temp" "$CONFIG_PATH"

  escaped_binary="$(xml_escape "$INSTALLED_BINARY")"
  escaped_root="$(xml_escape "$INSTALL_ROOT")"
  escaped_data="$(xml_escape "$DATA_DIR")"
  escaped_logs="$(xml_escape "$LOGS_DIR")"
  escaped_host="$(xml_escape "$HOST")"
  escaped_public_url="$(xml_escape "$PUBLIC_URL")"
  plist_temp="$CANONICAL_PLIST.new"
  cat > "$plist_temp" <<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>$LABEL</string>
  <key>ProgramArguments</key>
  <array><string>$escaped_binary</string></array>
  <key>WorkingDirectory</key><string>$escaped_root</string>
  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    <key>RUST_LOG</key><string>smart_printer_edge_server=info</string>
    <key>SMART_PRINTER_DATA_DIR</key><string>$escaped_data</string>
    <key>SMART_PRINTER_HOST</key><string>$escaped_host</string>
    <key>SMART_PRINTER_PORT</key><string>$PORT</string>
    <key>SMART_PRINTER_PUBLIC_URL</key><string>$escaped_public_url</string>
    <key>SMART_PRINTER_SETUP_CODE</key><string>$setup_code</string>
  </dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>ThrottleInterval</key><integer>10</integer>
  <key>StandardOutPath</key><string>$escaped_logs/service.log</string>
  <key>StandardErrorPath</key><string>$escaped_logs/service-error.log</string>
</dict>
</plist>
EOF
  /bin/chmod 600 "$plist_temp"
  /bin/mv -f "$plist_temp" "$CANONICAL_PLIST"

  if [ "$AUTO_START_REQUEST" -eq 1 ]; then
    /bin/cp "$CANONICAL_PLIST" "$AUTOSTART_PLIST.new"
    /bin/chmod 600 "$AUTOSTART_PLIST.new"
    /bin/mv -f "$AUTOSTART_PLIST.new" "$AUTOSTART_PLIST"
  else
    /bin/rm -f "$AUTOSTART_PLIST"
  fi

  if [ "$NO_START" -eq 0 ]; then
    emit "start" 70 "正在启动 Edge Server"
    "$LAUNCHCTL" bootstrap "$DOMAIN" "$CANONICAL_PLIST" >/dev/null
    "$LAUNCHCTL" kickstart -k "$SERVICE_TARGET" >/dev/null
    wait_for_health || fail "新服务未通过健康检查；旧版本将自动恢复"

    if [ -n "$expected_jobs" ] && [ -f "$database_path" ]; then
      actual_jobs="$(/usr/bin/sqlite3 "$database_path" 'SELECT COUNT(*) FROM jobs;')"
      [ "$actual_jobs" = "$expected_jobs" ] || fail "打印历史兼容校验失败；旧版本将自动恢复"
    fi
    if [ -f "$DATA_DIR/pairing-token" ] && [ -f "$database_path" ]; then
      pairing_token="$(/bin/cat "$DATA_DIR/pairing-token")"
      if [ -n "$pairing_token" ]; then
        token_hash="$(printf '%s' "$pairing_token" | /usr/bin/shasum -a 256 | /usr/bin/awk '{ print $1 }')"
        token_count="$(/usr/bin/sqlite3 "$database_path" "SELECT COUNT(*) FROM devices WHERE token_hash = '$token_hash' AND enabled = 1;" 2>/dev/null || true)"
        [ -z "$token_count" ] || [ "$token_count" -ge 1 ] || fail "原配对凭证兼容校验失败；旧版本将自动恢复"
      fi
    fi
  fi

  installed_version="$("$INSTALLED_BINARY" --version 2>/dev/null || true)"
  if [ -n "$REQUESTED_VERSION" ]; then
    expected_version="${REQUESTED_VERSION#v}"
    installed_version_number="$(printf '%s' "$installed_version" | /usr/bin/awk 'NR == 1 { print $NF; exit }')"
    [ "$installed_version_number" = "$expected_version" ] || \
      fail "安装后的版本校验失败：请求 $expected_version，实际 ${installed_version_number:-未知}"
  fi
  INSTALL_COMPLETE=1
  ROLLBACK_ARMED=0
  emit "complete" 100 "$PRODUCT_NAME ${installed_version##* } 已安装；现有数据和配对信息已保留"
  if [ "$JSON_OUTPUT" -eq 0 ]; then
    printf '安装位置：%s\n' "$INSTALLED_BINARY"
    printf '数据目录：%s\n' "$DATA_DIR"
    printf '迁移备份：%s\n' "$BACKUP_DIR"
    printf '首次管理初始化验证码：%s\n' "$setup_code"
  fi
}

case "$COMMAND" in
  install|upgrade)
    install_server
    ;;
  start)
    start_service
    ;;
  stop)
    stop_service
    ;;
  restart)
    stop_service
    start_service
    ;;
  enable)
    enable_autostart
    ;;
  disable)
    disable_autostart
    ;;
  status)
    print_status
    ;;
  check-update)
    print_update_status
    ;;
  doctor)
    emit "doctor" 20 "正在检查安装目录和系统依赖"
    [ -d "$DATA_DIR" ] || fail "数据目录不存在：$DATA_DIR"
    require_command "$LAUNCHCTL"
    require_command "$CURL"
    require_command /usr/bin/sqlite3
    print_status
    ;;
  uninstall)
    if [ "$PURGE_DATA" -eq 1 ] && [ "$CONFIRM_PURGE" -ne 1 ]; then
      fail "删除历史和配对信息需要同时传入 --purge-data --yes"
    fi
    bootout_service
    /bin/rm -f "$AUTOSTART_PLIST" "$CANONICAL_PLIST" "$CONFIG_PATH"
    /bin/rm -f "$INSTALLED_BINARY" "$INSTALLED_CONTROL"
    if [ "$PURGE_DATA" -eq 1 ]; then
      case "$DATA_DIR" in
        "$INSTALL_ROOT"/data|"$INSTALL_ROOT"/data/*)
          /bin/rm -rf "$DATA_DIR"
          emit "uninstalled" 100 "$PRODUCT_NAME 已卸载，历史和配对信息已删除"
          ;;
        *)
          fail "拒绝自动删除自定义数据目录：$DATA_DIR"
          ;;
      esac
    else
      emit "uninstalled" 100 "$PRODUCT_NAME 已卸载；历史、文件和配对信息仍保留在 $DATA_DIR"
    fi
    ;;
  help)
    usage
    ;;
esac
