#!/bin/sh
# Nightdesk for Linux: installs the host for this user, starts it now and at every boot, and shows the pairing code.
#   curl -fsSL https://nightdesk.codedrealities.com/linux/install.sh | sh
# No root needed for Nightdesk itself; missing system packages are offered (that part asks for sudo).
# NIGHTDESK_FROM=<dir or URL> installs from elsewhere (a test build); NIGHTDESK_YES=1 answers yes to every question.
set -eu
umask 077 # the pairing code and logs are for this user only

FROM=${NIGHTDESK_FROM:-https://nightdesk.codedrealities.com/linux}
BIN="$HOME/.local/bin"
DATA="$HOME/.local/share/nightdesk"

say()  { printf '\033[1m%s\033[0m\n' "$*"; }
fail() { printf '\033[31m%s\033[0m\n' "$*" >&2; exit 1; }
ask()  { # ask "question" → 0 yes / 1 no (from the terminal even when piped from curl)
	[ "${NIGHTDESK_YES:-}" = 1 ] && return 0
	[ -r /dev/tty ] || return 1
	printf '%s [Y/n] ' "$1" > /dev/tty
	read -r a < /dev/tty || return 1
	case "$a" in n*|N*) return 1 ;; *) return 0 ;; esac
}
fetch() { # fetch name dest
	case "$FROM" in
		http*) curl -fsSL "$FROM/$1" -o "$2" ;;
		*) cp "$FROM/$1" "$2" ;;
	esac
}

[ "$(uname -s)" = Linux ] || fail "Nightdesk for Linux runs on Linux. (On a Mac, get Nightdesk for Mac.)"
[ "$(id -u)" != 0 ] || fail "Run this as the user whose desktop you want to see, not as root."
case "$(uname -m)" in
	aarch64|arm64) ARCH=arm64 ;;
	x86_64|amd64) ARCH=amd64 ;;
	armv7l|armv7*) ARCH=armv7 ;;
	*) fail "This processor ($(uname -m)) isn't supported yet." ;;
esac

# What the host needs: GNOME Shell (the desktop, run on a screen of its own), PipeWire (to share it), GStreamer with
# x264 (to send it), D-Bus, and avahi (so phones nearby find it; optional).
missing=""
command -v gnome-shell >/dev/null || missing="$missing gnome-shell"
command -v pipewire >/dev/null || missing="$missing pipewire"
command -v pipewire-media-session >/dev/null || command -v wireplumber >/dev/null || missing="$missing session-manager"
command -v dbus-daemon >/dev/null || missing="$missing dbus"
if command -v gst-inspect-1.0 >/dev/null; then
	for e in pipewiresrc x264enc rtph264pay rtpstreampay videoconvert fdsink; do gst-inspect-1.0 "$e" >/dev/null 2>&1 || missing="$missing gst:$e"; done
else
	missing="$missing gstreamer"
fi
command -v avahi-publish-service >/dev/null || missing="$missing avahi"
if [ -n "$missing" ]; then
	say "Nightdesk needs a few system packages:$missing"
	if command -v apt-get >/dev/null && ask "Install them now with apt (asks for your password)?"; then
		pkgs="gnome-shell dbus pipewire gstreamer1.0-pipewire gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly avahi-utils"
		if apt-cache show wireplumber >/dev/null 2>&1; then pkgs="$pkgs wireplumber"; else pkgs="$pkgs pipewire-media-session"; fi
		sudo apt-get update -qq && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $pkgs
	elif command -v dnf >/dev/null && ask "Install them now with dnf (asks for your password)?"; then
		sudo dnf install -y gnome-shell dbus-daemon pipewire wireplumber gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugin-x264 pipewire-gstreamer avahi-tools
	else
		case "$missing" in *avahi*) ;; esac
		echo "Install them with your package manager, then run this again."
		[ "$missing" = " avahi" ] || exit 1
	fi
fi

say "Getting Nightdesk for Linux ($ARCH)…"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
fetch "nightdesk-host-linux-$ARCH.bin" "$tmp/nightdesk-host"
fetch SHA256SUMS.txt "$tmp/SHA256SUMS"
want=$(grep " nightdesk-host-linux-$ARCH.bin\$" "$tmp/SHA256SUMS" | cut -d' ' -f1)
have=$(sha256sum "$tmp/nightdesk-host" | cut -d' ' -f1)
[ -n "$want" ] && [ "$want" = "$have" ] || fail "The download didn't check out (its checksum is wrong). Try again."
mkdir -p "$BIN" "$DATA"
chmod +x "$tmp/nightdesk-host"
# Stop a running copy before replacing it (the new one starts below): the service first, so systemd doesn't start
# the old file again in between.
systemctl --user stop nightdesk-host.service 2>/dev/null || true
pkill -x nightdesk-host 2>/dev/null && sleep 2 || true
mv "$tmp/nightdesk-host" "$BIN/nightdesk-host"

# Start now and at every boot: a systemd user service when this user has one that outlives logging out (linger),
# else a crontab @reboot line (no root needed either way).
started=""
if command -v systemctl >/dev/null && systemctl --user show-environment >/dev/null 2>&1; then
	linger=$(loginctl show-user "$USER" -p Linger --value 2>/dev/null || echo no)
	[ "$linger" = yes ] || loginctl enable-linger "$USER" 2>/dev/null && linger=yes || true
	if [ "$linger" = yes ]; then
		mkdir -p "$HOME/.config/systemd/user"
		cat > "$HOME/.config/systemd/user/nightdesk-host.service" <<UNIT
[Unit]
Description=Nightdesk for Linux (see and control this computer from your phone)
After=network-online.target

[Service]
ExecStart=$BIN/nightdesk-host run
Restart=always
RestartSec=3

[Install]
WantedBy=default.target
UNIT
		systemctl --user daemon-reload
		systemctl --user enable nightdesk-host.service >/dev/null 2>&1 && systemctl --user restart nightdesk-host.service && started="a systemd user service"
	fi
fi
if [ -z "$started" ]; then
	line="@reboot $BIN/nightdesk-host run >> $DATA/host.log 2>&1"
	( crontab -l 2>/dev/null | grep -v 'nightdesk-host run' ; echo "$line" ) | crontab -
	nohup "$BIN/nightdesk-host" run >> "$DATA/host.log" 2>&1 &
	started="crontab (@reboot)"
fi

say "Starting…"
i=0
while [ ! -s "$DATA/pairing-code" ] && [ $i -lt 45 ]; do sleep 1; i=$((i + 1)); done
sleep 2
"$BIN/nightdesk-host" pair || fail "Nightdesk didn't start. Its log: $DATA/host.log"
say "Nightdesk for Linux is installed and starts by itself ($started)."
echo "  Show the pairing code again any time: $BIN/nightdesk-host pair"
