#!/usr/bin/env bash
#
# Install MAESTRO as a systemd service so it starts automatically on boot.
#
# Fills in deploy/maestro.service (a template) from the current checkout — node
# path, project directory and run user are auto-detected — then installs and
# enables the unit. systemd supervises `node dist/main.js` directly; it does not
# build, so build first (`scripts/server.sh start` or `npm run build`).
#
#   scripts/install-systemd.sh                 # user service (no root, runs as you) [default]
#   scripts/install-systemd.sh --print         # preview generated unit, install nothing
#   scripts/install-systemd.sh --mode system   # system-wide service (needs sudo)
#   scripts/install-systemd.sh --run-as bot    # run as a specific user (system mode only)
#   scripts/install-systemd.sh --name maestro  # override service name
#   scripts/install-systemd.sh --no-start      # enable for boot but don't start now
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
TEMPLATE="$PROJECT_DIR/deploy/maestro.service"

MODE="user"          # user | system  (default: user — no root, runs as you)
NAME="maestro"
RUN_AS=""            # system mode only; default resolved below
PRINT_ONLY=0
NO_START=0

die() { echo "error: $*" >&2; exit 1; }

# Consume the value of a `--opt value` flag, erroring cleanly if it's missing
# (a bare `shift 2` on the last arg would abort under `set -e` with no message).
need_val() { [[ $# -ge 2 ]] || die "$1 requires a value"; }

while [[ $# -gt 0 ]]; do
  case "$1" in
    --mode)    need_val "$@"; MODE="$2"; shift 2 ;;
    --mode=*)  MODE="${1#*=}"; shift ;;
    --name)    need_val "$@"; NAME="$2"; shift 2 ;;
    --name=*)  NAME="${1#*=}"; shift ;;
    --run-as)  need_val "$@"; RUN_AS="$2"; shift 2 ;;
    --run-as=*) RUN_AS="${1#*=}"; shift ;;
    --print|--dry-run) PRINT_ONLY=1; shift ;;
    --no-start) NO_START=1; shift ;;
    -h|--help)
      # Print the leading comment block (after the shebang) as usage text.
      awk 'NR==1{next} /^#/{sub(/^# ?/,""); print; next} {exit}' "$0"
      exit 0 ;;
    *) die "unknown argument: $1" ;;
  esac
done

[[ "$MODE" == "system" || "$MODE" == "user" ]] || die "--mode must be 'system' or 'user' (got '$MODE')"
[[ "$NAME" =~ ^[A-Za-z0-9_.-]+$ ]] || die "invalid --name '$NAME'"
[[ -f "$TEMPLATE" ]] || die "template not found: $TEMPLATE"

# --- Auto-detect substitution values ------------------------------------------
NODE_BIN="$(command -v node || true)"
[[ -n "$NODE_BIN" ]] || die "node not found in PATH"

if [[ "$MODE" == "system" ]]; then
  # Run user: explicit flag > invoking user under sudo > current user.
  # Never default to root (the app should not build/run as root).
  RUN_USER="${RUN_AS:-${SUDO_USER:-$USER}}"
  [[ "$RUN_USER" != "root" ]] || echo "warning: run user resolves to 'root'; pass --run-as <user> to run the app as a non-root user." >&2
  # Existence is enforced at install time (below), not for --print previews.
else
  # user mode: the service belongs to the invoking user's systemd manager.
  # Running under sudo would resolve $USER to root and install a stray unit
  # under /root — almost never intended. Steer to the right path instead.
  if [[ $EUID -eq 0 ]]; then
    die "user mode as root would install under /root. Run WITHOUT sudo, or for a machine-wide service use: --mode system --run-as <user>"
  fi
  [[ -z "$RUN_AS" ]] || echo "warning: --run-as is ignored in user mode (the service always runs as '$USER'); use --mode system to run as another user." >&2
  RUN_USER="$USER"
fi

# --- Preflight (skipped for --print) ------------------------------------------
if [[ "$PRINT_ONLY" -eq 0 ]]; then
  [[ -f "$PROJECT_DIR/dist/main.js" ]] || die "dist/main.js missing — build first: scripts/server.sh start  (or npm run build)"
  if [[ "$MODE" == "system" ]]; then
    id "$RUN_USER" >/dev/null 2>&1 || die "run user '$RUN_USER' does not exist (pass --run-as <user>)"
  fi
fi

# --- Generate the unit from the template --------------------------------------
generate_unit() {
  # Substitute placeholders. PROJECT_DIR/NODE_BIN are absolute paths without
  # '|' or '&', safe as sed replacements.
  sed \
    -e "s|@PROJECT_DIR@|$PROJECT_DIR|g" \
    -e "s|@NODE@|$NODE_BIN|g" \
    -e "s|@RUN_USER@|$RUN_USER|g" \
    "$TEMPLATE" | grep -v '^#' | grep -v '^$' \
  | if [[ "$MODE" == "user" ]]; then
      # A user manager owns the process — drop User=, use user-session targets,
      # and don't wait on the system-only network-online.target.
      sed \
        -e '/^User=/d' \
        -e '/^Wants=network-online.target/d' \
        -e 's|^After=network-online.target|After=default.target|' \
        -e 's|^WantedBy=multi-user.target|WantedBy=default.target|'
    else
      cat
    fi
}

UNIT_TEXT="$(generate_unit)"

if [[ "$PRINT_ONLY" -eq 1 ]]; then
  echo "# --- generated ${NAME}.service (mode=${MODE}) ---"
  echo "$UNIT_TEXT"
  exit 0
fi

# --- Install ------------------------------------------------------------------
if [[ "$MODE" == "system" ]]; then
  UNIT_PATH="/etc/systemd/system/${NAME}.service"
  if [[ $EUID -eq 0 ]]; then
    priv() { "$@"; }
  else
    command -v sudo >/dev/null 2>&1 || die "system install needs root; re-run with sudo"
    priv() { sudo "$@"; }
  fi
  echo "Installing $UNIT_PATH (run user: $RUN_USER)…"
  printf '%s\n' "$UNIT_TEXT" | priv tee "$UNIT_PATH" >/dev/null
  priv systemctl daemon-reload
  if [[ "$NO_START" -eq 1 ]]; then
    priv systemctl enable "$NAME"
    echo "Enabled for boot. Start later with: sudo systemctl start $NAME"
  else
    priv systemctl enable --now "$NAME"
  fi
  echo "Done. Status:  systemctl status $NAME"
  echo "      Logs:    journalctl -u $NAME -f"
else
  UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
  UNIT_PATH="$UNIT_DIR/${NAME}.service"
  mkdir -p "$UNIT_DIR"
  echo "Installing $UNIT_PATH …"
  printf '%s\n' "$UNIT_TEXT" > "$UNIT_PATH"
  systemctl --user daemon-reload
  # Linger lets the user service run at boot without an active login session.
  if ! loginctl enable-linger "$USER" 2>/dev/null; then
    echo "warning: could not enable linger for '$USER'; the service may not start until you log in." >&2
    echo "         Retry with: sudo loginctl enable-linger $USER" >&2
  fi
  if [[ "$NO_START" -eq 1 ]]; then
    systemctl --user enable "$NAME"
    echo "Enabled for boot. Start later with: systemctl --user start $NAME"
  else
    systemctl --user enable --now "$NAME"
  fi
  echo "Done. Status:  systemctl --user status $NAME"
  echo "      Logs:    journalctl --user -u $NAME -f"
fi
