#!/bin/bash
# nextdoer-connector — operator/business CLI for the installed connector.
#
#   sudo nextdoer-connector enroll --bundle <bundle.json> --user <desktop-user> \
#        [--display :0] [--xauthority /home/<user>/.Xauthority]
#   nextdoer-connector status          # run AS the desktop user
#   nextdoer-connector restart|stop    # run AS the desktop user (no sudo)
#   nextdoer-connector update          # run AS the desktop user (no sudo)
#
# PER-USER MODEL (docs/plans/connector-update-app.md): the connector RUNTIME runs
# as a `systemd --user` service with its code under the user's home, so the
# desktop app's one-click Update and the updater swap code + restart WITHOUT root.
# `enroll` is the ONE root step (WireGuard tunnel is root); it also seeds the
# user runtime + enables the user service. status/restart/stop/update need NO
# sudo — they act on the calling user's own service.
set -euo pipefail
APP=/opt/nextdoer-connector                       # .deb bootstrap install (root)
USER_CODE_REL=.local/share/nextdoer-connector     # per-user runtime code root
USER_CONF_REL=.config/nextdoer-connector          # per-user runtime config

usage() {
  echo "usage:"
  echo "  sudo nextdoer-connector enroll --bundle <f> --user <desktop-user> [--display :0] [--xauthority <path>] [--profile <dir>]"
  echo "  nextdoer-connector status|restart|stop|update      # as the desktop user, no sudo"
}

# systemctl --user for the desktop user, callable from a root enroll (sudo -u)
user_systemctl() {  # $1=user  rest=args
  local u="$1"; shift
  local uid; uid="$(id -u "$u")"
  sudo -u "$u" XDG_RUNTIME_DIR="/run/user/${uid}" systemctl --user "$@"
}

cmd="${1:-}"; shift || true
case "$cmd" in
  enroll)
    USER_ARG=""; XAUTH=""; PROFILE=""; DISPLAY_ARG=":0"; BUNDLE=""; SERVER=""; TOKEN=""; ENROLL_TOKEN=""
    while [ $# -gt 0 ]; do case "$1" in
      --user)         USER_ARG="$2"; shift 2;;
      --xauthority)   XAUTH="$2"; shift 2;;
      --profile)      PROFILE="$2"; shift 2;;
      --display)      DISPLAY_ARG="$2"; shift 2;;
      --bundle)       BUNDLE="$2"; shift 2;;
      --server)       SERVER="$2"; shift 2;;
      --token)        TOKEN="$2"; shift 2;;
      --enroll-token) ENROLL_TOKEN="$2"; shift 2;;
      *) shift;;
    esac; done
    [ "$(id -u)" -eq 0 ] || { echo "run enroll with sudo/pkexec (writes /etc/wireguard)"; exit 2; }
    # the GUI/pkexec path does not pass --user; default to the invoking desktop
    # user (pkexec sets PKEXEC_UID) so onboarding needs only the pasted token
    [ -n "$USER_ARG" ] || USER_ARG="$(getent passwd "${PKEXEC_UID:-$(id -u)}" | cut -d: -f1)"
    [ -n "$USER_ARG" ] || { echo "--user <desktop-user> required (owns the graphical session)"; exit 2; }
    [ -n "$ENROLL_TOKEN$SERVER$BUNDLE" ] || { echo "need --enroll-token <t>  OR  --server <url> --token <t>  OR  --bundle <file>"; exit 2; }
    HOME_DIR="$(getent passwd "$USER_ARG" | cut -d: -f6)"
    [ -n "$HOME_DIR" ] || { echo "unknown user: $USER_ARG"; exit 2; }
    [ -n "$PROFILE" ]  || PROFILE="$HOME_DIR/.nextdoer-connector"
    [ -n "$XAUTH" ]    || XAUTH="$HOME_DIR/.Xauthority"

    # 1) WireGuard tunnel + /etc connector.env (root)
    cd "$APP"
    if [ -n "$ENROLL_TOKEN" ]; then
      PYTHONPATH="$APP" python3 -m connector.core.enroll \
        --enroll-token "$ENROLL_TOKEN" --profile "$PROFILE" --display "$DISPLAY_ARG"
    elif [ -n "$SERVER" ]; then
      PYTHONPATH="$APP" python3 -m connector.core.enroll \
        --server "$SERVER" --token "$TOKEN" --profile "$PROFILE" --display "$DISPLAY_ARG"
    else
      PYTHONPATH="$APP" python3 -m connector.core.enroll \
        --bundle "$BUNDLE" --profile "$PROFILE" --display "$DISPLAY_ARG"
    fi

    # 2) seed the PER-USER runtime: code under the user's home + config
    USER_CODE="$HOME_DIR/$USER_CODE_REL"
    USER_CONF="$HOME_DIR/$USER_CONF_REL"
    install -d -o "$USER_ARG" -g "$USER_ARG" "$USER_CODE" "$USER_CONF" "$PROFILE"
    rm -rf "$USER_CODE/connector"
    cp -r "$APP/connector" "$USER_CODE/connector"
    # runtime config: reuse the /etc connector.env the python enroll just wrote
    install -o "$USER_ARG" -g "$USER_ARG" -m600 \
      /etc/nextdoer-connector/connector.env "$USER_CONF/connector.env"
    chown -R "$USER_ARG:$USER_ARG" "$USER_CODE"

    # 3) install + enable the PER-USER systemd service
    USER_UNIT_DIR="$HOME_DIR/.config/systemd/user"
    install -d -o "$USER_ARG" -g "$USER_ARG" "$USER_UNIT_DIR"
    install -o "$USER_ARG" -g "$USER_ARG" -m644 \
      /usr/lib/nextdoer-connector/nextdoer-connector.user.service \
      "$USER_UNIT_DIR/nextdoer-connector.service"
    loginctl enable-linger "$USER_ARG"      # keep the user service across logout/boot
    user_systemctl "$USER_ARG" daemon-reload
    user_systemctl "$USER_ARG" enable --now nextdoer-connector.service
    echo "connector enrolled + per-user service started (user=$USER_ARG, display=$DISPLAY_ARG)."
    echo "the business can now open the NextDoer app and press Update (no sudo)."
    ;;
  status)
    systemctl --user status nextdoer-connector.service --no-pager || true
    . "$HOME/$USER_CONF_REL/connector.env" 2>/dev/null || true
    echo "--- CDP endpoint check (${CONNECTOR_LISTEN:-unknown}) ---"
    [ -n "${CONNECTOR_LISTEN:-}" ] && curl -s --max-time 4 "http://${CONNECTOR_LISTEN}/json/version" | head -3 || echo "(no listen set)"
    ;;
  restart) systemctl --user restart nextdoer-connector.service ;;
  stop)    systemctl --user stop nextdoer-connector.service ;;
  sync-code)
    # Make a plain `.deb` reinstall "just work": refresh the per-user runtime
    # code (+ service unit) from the /opt bootstrap when the installed .deb is
    # NEWER than the user's copy. Runs as the desktop user, NO root, NO token.
    # `apt purge` never removes the per-user tree and the launcher/service run
    # THAT tree, so without this a reinstalled newer .deb stays shadowed by the
    # old user code (the 0.2.0->0.3.x shadowing incident). A self-update writes
    # the user copy NEWER than /opt, so the version gate below never clobbers it.
    USER_CODE="$HOME/$USER_CODE_REL"
    OPT_VER="$(cat "$APP/connector/VERSION" 2>/dev/null || echo 0)"
    USR_VER="$(cat "$USER_CODE/connector/VERSION" 2>/dev/null || echo 0)"
    if [ ! -d "$USER_CODE/connector" ] || dpkg --compare-versions "$OPT_VER" gt "$USR_VER"; then
      install -d "$USER_CODE"
      rm -rf "$USER_CODE/connector.new"
      cp -r "$APP/connector" "$USER_CODE/connector.new"
      rm -rf "$USER_CODE/connector"
      mv "$USER_CODE/connector.new" "$USER_CODE/connector"
      echo "connector code synced from /opt (${USR_VER} -> ${OPT_VER})"
    fi
    # keep the per-user service unit current too (so ExecStartPre + any future
    # unit changes from a reinstall take effect without a re-enroll)
    UNIT_SRC=/usr/lib/nextdoer-connector/nextdoer-connector.user.service
    UNIT_DST="$HOME/.config/systemd/user/nextdoer-connector.service"
    if [ -f "$UNIT_SRC" ] && ! cmp -s "$UNIT_SRC" "$UNIT_DST"; then
      install -d "$(dirname "$UNIT_DST")"
      install -m644 "$UNIT_SRC" "$UNIT_DST"
      XDG_RUNTIME_DIR="/run/user/$(id -u)" systemctl --user daemon-reload 2>/dev/null || true
      echo "connector service unit refreshed"
    fi
    ;;
  update)
    . "$HOME/$USER_CONF_REL/connector.env" 2>/dev/null || true
    [ -n "${CONNECTOR_UPDATE_URL:-}" ] || { echo "no CONNECTOR_UPDATE_URL in connector.env"; exit 2; }
    python3 -m connector.core.updater apply --url "$CONNECTOR_UPDATE_URL" \
      --pkg "$HOME/$USER_CODE_REL/connector"
    ;;
  *) usage; exit 2;;
esac
