#!/usr/bin/env bash
# NotesQR Linux installer (user-local, no sudo).
# Puts the app in ~/.local (survives Downloads cleanup) + menu entry + `notesqr` command.
# Safe to re-run: stops a running NotesQR, replaces the AppImage, relaunches.
#
#   curl -fsSL https://notesqr.com/install-linux.sh | bash
#
set -euo pipefail

API_BASE="${NOTESQR_API:-https://notesqr.com}"
INSTALL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/NotesQR"
mkdir -p "$INSTALL_DIR"
echo "==== $(date -Iseconds) pid=$$ cgroup=$(tr '\n' ' ' </proc/self/cgroup 2>/dev/null) ====" >>"$INSTALL_DIR/install.log"
BIN_DIR="${XDG_BIN_HOME:-$HOME/.local/bin}"
APPS_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
APPIMAGE="$INSTALL_DIR/NotesQR.AppImage"
ICON_FILE="$INSTALL_DIR/notesqr.png"
DESKTOP="$APPS_DIR/notesqr.desktop"
WRAPPER="$BIN_DIR/notesqr"
HICOLOR="${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor"

# In-app update starts this script as a child of NotesQR. systemd KillMode=control-group
# then kills the installer when we SIGKILL NotesQR. Hop to our own unit first.
if [[ "${NOTESQR_INSTALL_SCOPED:-}" != 1 ]] && [[ -r /proc/self/cgroup ]] \
  && grep -qE 'app-notesqr' /proc/self/cgroup 2>/dev/null \
  && command -v systemd-run >/dev/null 2>&1; then
  extra=()
  [[ -n "${DISPLAY:-}" ]] && extra+=(--setenv="DISPLAY=$DISPLAY")
  [[ -n "${WAYLAND_DISPLAY:-}" ]] && extra+=(--setenv="WAYLAND_DISPLAY=$WAYLAND_DISPLAY")
  [[ -n "${XDG_RUNTIME_DIR:-}" ]] && extra+=(--setenv="XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR")
  [[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]] && extra+=(--setenv="DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS")
  [[ -n "${XAUTHORITY:-}" ]] && extra+=(--setenv="XAUTHORITY=$XAUTHORITY")
  [[ -n "${HOME:-}" ]] && extra+=(--setenv="HOME=$HOME")
  echo "==> Re-running installer outside the NotesQR process group…"
  exec systemd-run --user --no-block --collect \
    --unit="notesqr-install-$$.service" \
    --property=Type=oneshot \
    --property=KillMode=process \
    --setenv=NOTESQR_INSTALL_SCOPED=1 \
    "${extra[@]}" \
    bash -lc "curl -fsSL ${API_BASE}/install-linux.sh | bash"
fi

echo "==> NotesQR Linux installer"
echo "    Install dir: $INSTALL_DIR"

mkdir -p "$INSTALL_DIR" "$BIN_DIR" "$APPS_DIR"

notesqr_running() {
  # Match the Electron binary only — pgrep -f AppImage also hits systemd-run /
  # the installer itself and reports a false "Opened."
  if command -v pgrep >/dev/null 2>&1; then
    pgrep -x NotesQR >/dev/null 2>&1 && return 0
    pgrep -x NotesQR.AppImag >/dev/null 2>&1 && return 0
  fi
  if command -v pidof >/dev/null 2>&1; then
    pidof NotesQR >/dev/null 2>&1 && return 0
  fi
  return 1
}

stop_notesqr_scopes() {
  if ! command -v systemctl >/dev/null 2>&1; then
    return 0
  fi
  while read -r unit _; do
    [[ -n "$unit" ]] || continue
    systemctl --user stop "$unit" >/dev/null 2>&1 || true
  done < <(systemctl --user list-units 'app-notesqr-*' --no-legend --no-pager 2>/dev/null || true)
}

clear_notesqr_singleton_lock() {
  local cfg="${XDG_CONFIG_HOME:-$HOME/.config}/NotesQR"
  rm -f "$cfg/SingletonLock" "$cfg/SingletonSocket" "$cfg/SingletonCookie" 2>/dev/null || true
}

wait_notesqr_stopped() {
  local i
  for i in $(seq 1 80); do
    notesqr_running || return 0
    stop_notesqr
    stop_notesqr_scopes
    sleep 0.25
  done
  return 1
}

echo "==> Force-stopping NotesQR…"
stop_notesqr() {
  if command -v pkill >/dev/null 2>&1; then
    pkill -9 -f "$APPIMAGE" >/dev/null 2>&1 || true
    pkill -9 -f 'NotesQR\.AppImage' >/dev/null 2>&1 || true
    pkill -9 -x NotesQR >/dev/null 2>&1 || true
    pkill -9 -f '/NotesQR$' >/dev/null 2>&1 || true
  fi
  if command -v pidof >/dev/null 2>&1; then
    for pid in $(pidof NotesQR 2>/dev/null || true); do
      kill -9 "$pid" >/dev/null 2>&1 || true
    done
  fi
  if command -v fuser >/dev/null 2>&1 && [[ -f "$APPIMAGE" ]]; then
    fuser -k -9 "$APPIMAGE" >/dev/null 2>&1 || true
  fi
}
stop_notesqr
stop_notesqr_scopes
wait_notesqr_stopped || true
clear_notesqr_singleton_lock
sleep 0.5
for _ in 1 2 3 4 5 6; do
  stop_notesqr
  notesqr_running || break
  sleep 0.25
done
sleep 0.2

TMP="$(mktemp)"
cleanup() { rm -f "$TMP" "$APPIMAGE.new"; }
trap cleanup EXIT

echo "==> Downloading…"
if command -v curl >/dev/null 2>&1; then
  curl -fL --progress-bar "$API_BASE/api/download?platform=linux-appimage" -o "$TMP"
elif command -v wget >/dev/null 2>&1; then
  wget -O "$TMP" "$API_BASE/api/download?platform=linux-appimage"
else
  echo "Need curl or wget." >&2
  exit 1
fi

size="$(wc -c < "$TMP" | tr -d ' ')"
if [[ "$size" -lt 1000000 ]]; then
  echo "Download looks invalid (${size} bytes)." >&2
  exit 1
fi

install -m 755 "$TMP" "$APPIMAGE.new"
mv -f "$APPIMAGE.new" "$APPIMAGE"
chmod 755 "$APPIMAGE"

install_icon_png() {
  if [[ -s "$ICON_FILE" ]]; then
    :
  elif command -v curl >/dev/null 2>&1; then
    curl -fsSL "$API_BASE/assets/notesqr-icon.png" -o "$ICON_FILE" || true
  elif command -v wget >/dev/null 2>&1; then
    wget -q -O "$ICON_FILE" "$API_BASE/assets/notesqr-icon.png" || true
  fi
  if [[ -s "$ICON_FILE" ]]; then
    for sz in 48 128 256 512; do
      mkdir -p "$HICOLOR/${sz}x${sz}/apps"
      install -m 644 "$ICON_FILE" "$HICOLOR/${sz}x${sz}/apps/notesqr.png"
    done
    if command -v gtk-update-icon-cache >/dev/null 2>&1; then
      gtk-update-icon-cache -f "$HICOLOR" >/dev/null 2>&1 || true
    fi
  fi
}
install_icon_png

ICON_KEY="$ICON_FILE"
[[ -s "$ICON_FILE" ]] || ICON_KEY=notesqr

# systemd scope app-notesqr-NNN.scope is what KDE Applications lists
# (same scheme as No-IP: app-org.noip.tray-*.scope).
cat > "$WRAPPER" <<EOF
#!/usr/bin/env bash
export APPIMAGE_EXTRACT_AND_RUN=1
export CHROME_DESKTOP=notesqr.desktop
cd "\$HOME" || true

if [[ -r /proc/self/cgroup ]] && grep -qE 'app-notesqr' /proc/self/cgroup 2>/dev/null; then
  exec "$APPIMAGE" "\$@"
fi

if command -v systemd-run >/dev/null 2>&1; then
  extra=()
  [[ -n "\${DISPLAY:-}" ]] && extra+=(--setenv="DISPLAY=\$DISPLAY")
  [[ -n "\${WAYLAND_DISPLAY:-}" ]] && extra+=(--setenv="WAYLAND_DISPLAY=\$WAYLAND_DISPLAY")
  [[ -n "\${XDG_RUNTIME_DIR:-}" ]] && extra+=(--setenv="XDG_RUNTIME_DIR=\$XDG_RUNTIME_DIR")
  [[ -n "\${DBUS_SESSION_BUS_ADDRESS:-}" ]] && extra+=(--setenv="DBUS_SESSION_BUS_ADDRESS=\$DBUS_SESSION_BUS_ADDRESS")
  [[ -n "\${XAUTHORITY:-}" ]] && extra+=(--setenv="XAUTHORITY=\$XAUTHORITY")
  [[ -n "\${HOME:-}" ]] && extra+=(--setenv="HOME=\$HOME")
  extra+=(--setenv=APPIMAGE_EXTRACT_AND_RUN=1)
  extra+=(--setenv=CHROME_DESKTOP=notesqr.desktop)
  exec systemd-run --user --scope \\
    --slice=app.slice \\
    --unit="app-notesqr-\${RANDOM}.scope" \\
    --property=KillMode=control-group \\
    "\${extra[@]}" \\
    -- "$APPIMAGE" "\$@" &
  exit 0
fi

exec "$APPIMAGE" "\$@"
EOF
chmod 755 "$WRAPPER"

cat > "$DESKTOP" <<EOF
[Desktop Entry]
Type=Application
Name=NotesQR
Comment=P2P file sharing via WebRTC
Exec="$WRAPPER" %U
Icon=$ICON_KEY
Terminal=false
Categories=Network;FileTransfer;Utility;
StartupNotify=false
StartupWMClass=NotesQR
EOF
chmod 644 "$DESKTOP"

if command -v update-desktop-database >/dev/null 2>&1; then
  update-desktop-database "$APPS_DIR" >/dev/null 2>&1 || true
fi

case ":$PATH:" in
  *":$BIN_DIR:"*) ;;
  *)
    echo
    echo "Add to PATH (once), then re-open the terminal:"
    echo "  echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc && source ~/.bashrc"
    ;;
esac

ensure_gui_env() {
  if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
    return 0
  fi
  if [[ -n "${XDG_RUNTIME_DIR:-}" && -S "${XDG_RUNTIME_DIR}/wayland-0" ]]; then
    export WAYLAND_DISPLAY=wayland-0
  fi
  if [[ -z "${DISPLAY:-}" && -S /tmp/.X11-unix/X0 ]]; then
    export DISPLAY=:0
  fi
}

launch_notesqr_systemd() {
  local extra=()
  [[ -n "${DISPLAY:-}" ]] && extra+=(--setenv="DISPLAY=$DISPLAY")
  [[ -n "${WAYLAND_DISPLAY:-}" ]] && extra+=(--setenv="WAYLAND_DISPLAY=$WAYLAND_DISPLAY")
  [[ -n "${XDG_RUNTIME_DIR:-}" ]] && extra+=(--setenv="XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR")
  [[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]] && extra+=(--setenv="DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS")
  [[ -n "${XAUTHORITY:-}" ]] && extra+=(--setenv="XAUTHORITY=$XAUTHORITY")
  [[ -n "${HOME:-}" ]] && extra+=(--setenv="HOME=$HOME")
  extra+=(--setenv=APPIMAGE_EXTRACT_AND_RUN=1)
  extra+=(--setenv=CHROME_DESKTOP=notesqr.desktop)
  # --no-block is invalid with --scope on systemd 257; background instead.
  nohup systemd-run --user --scope \
    --slice=app.slice \
    --unit="app-notesqr-${RANDOM}.scope" \
    --property=KillMode=control-group \
    "${extra[@]}" \
    -- "$APPIMAGE" --show >/dev/null 2>&1 &
  disown >/dev/null 2>&1 || true
}

notesqr_notify() {
  command -v notify-send >/dev/null 2>&1 || return 0
  ( timeout 3 notify-send -a NotesQR NotesQR "$1" >/dev/null 2>&1 ) &
  disown >/dev/null 2>&1 || true
}

prepare_notesqr_relaunch() {
  echo "    Ensuring previous instance is fully stopped…"
  stop_notesqr
  stop_notesqr_scopes
  wait_notesqr_stopped || true
  clear_notesqr_singleton_lock
  # SIGKILL leaves Electron single-instance locks until the old process tree is gone.
  sleep 1.5
}

launch_notesqr() {
  export APPIMAGE_EXTRACT_AND_RUN=1
  export CHROME_DESKTOP=notesqr.desktop
  cd "$HOME" || true
  ensure_gui_env
  if [[ -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
    echo "    No GUI session detected — start with: notesqr --show"
    return 0
  fi

  prepare_notesqr_relaunch

  if command -v systemd-run >/dev/null 2>&1; then
    launch_notesqr_systemd
  elif [[ -x "$WRAPPER" ]]; then
    nohup "$WRAPPER" --show >/dev/null 2>&1 &
    disown >/dev/null 2>&1 || true
  elif command -v setsid >/dev/null 2>&1; then
    setsid -f "$APPIMAGE" --show >/dev/null 2>&1 || true
  else
    nohup "$APPIMAGE" --show >/dev/null 2>&1 &
    disown >/dev/null 2>&1 || true
  fi

  echo "    Relaunching in background (tray icon in a few seconds)."
  notesqr_notify "Updated — look for the NotesQR tray icon."
}

write_run_update_script() {
  cat > "$INSTALL_DIR/run-update.sh" <<'EOF'
#!/usr/bin/env bash
set +e
exec bash -lc 'curl -fsSL https://notesqr.com/install-linux.sh | bash'
EOF
  chmod 755 "$INSTALL_DIR/run-update.sh"
}
write_run_update_script

echo
echo "==> Installed (not in Downloads — safe from cleanup)."
echo "    App:     $APPIMAGE"
echo "    Command: notesqr"
echo "    Menu:    NotesQR"
echo
echo "==> Launching NotesQR…"
launch_notesqr
echo
echo "Uninstall:  rm -rf \"$INSTALL_DIR\" \"$WRAPPER\" \"$DESKTOP\" \"$HICOLOR\"/*/apps/notesqr.png"
