#!/bin/sh
# rikkiti-snapshot — btrfs system-snapshot helper (docs/44). Snapshots the SYSTEM (@ /
# root) ONLY; /home (@home) is a separate subvolume and is NEVER touched. INERT unless
# root is btrfs AND snapper is present, so shipping it to ext4 or legacy GRUB boxes is a
# complete no-op (same retrofit-safe rule as the recovery hooks).
set -u
PRE_STATE=/run/rikkiti-snapshot-pre

is_btrfs_snapper() {
	command -v snapper >/dev/null 2>&1 || return 1
	[ "$(stat -f -c %T / 2>/dev/null)" = "btrfs" ] || return 1
	return 0
}

case "${1:-}" in
  setup)
	# First boot on a btrfs install: create the 'root' config, re-home /.snapshots onto the
	# standalone @snapshots subvolume, apply sane defaults, enable the prune timer. Idempotent.
	is_btrfs_snapper || exit 0
	snapper -c root get-config >/dev/null 2>&1 || snapper --no-dbus -c root create-config / >/dev/null 2>&1 || true

	# ★ Point snapper at the SEPARATE @snapshots subvolume the installer created. create-config
	# above makes a NESTED @/.snapshots, but a system rollback SWAPS @ — so the history has to
	# live OUTSIDE @ (in @snapshots) to survive it (see rikkiti-rollback). Do it once: only if
	# @snapshots exists AND /.snapshots isn't already the standalone mount. The nested
	# .snapshots is empty right after create-config, so deleting it is safe.
	if [ -d /.snapshots ] && ! grep -q '/\.snapshots' /etc/fstab 2>/dev/null \
	   && btrfs subvolume list / 2>/dev/null | grep -q ' @snapshots$'; then
		ruuid=$(findmnt -no UUID / 2>/dev/null)
		btrfs subvolume delete /.snapshots >/dev/null 2>&1 || true
		mkdir -p /.snapshots
		# nofail: /.snapshots is non-critical for boot — a mount hiccup here must never block it.
		[ -n "$ruuid" ] && printf 'UUID=%s  /.snapshots  btrfs  subvol=@snapshots,noatime,compress=zstd:1,nofail  0 0\n' "$ruuid" >> /etc/fstab
		mount /.snapshots 2>/dev/null || true
		chmod 750 /.snapshots 2>/dev/null || true
	fi

	# keep the last 10 before-update snapshots, no hourly timeline (lean; @-only = tiny deltas),
	# group-readable so Settings ▸ Snapshots can list them without root.
	snapper --no-dbus -c root set-config \
		NUMBER_LIMIT=10 NUMBER_LIMIT_IMPORTANT=10 TIMELINE_CREATE=no \
		ALLOW_GROUPS=sudo SYNC_ACL=yes >/dev/null 2>&1 || true
	systemctl enable --now snapper-cleanup.timer >/dev/null 2>&1 || true
	# Debian also enables snapper-boot.timer (a snapshot on EVERY boot) + snapper-timeline.timer.
	# Neither fits our lean "before-update + manual only" design — boot snapshots would churn the
	# keep-N retention on every reboot, pushing out the update restore points that matter. Disable
	# both (timeline is already inert via TIMELINE_CREATE=no); keep snapper-cleanup (pruning) +
	# snapperd (the Settings pane). Idempotent.
	systemctl disable --now snapper-boot.timer snapper-timeline.timer >/dev/null 2>&1 || true
	# Debian's snapper ships its OWN apt hook (/etc/apt/apt.conf.d/80snapper) that also
	# snapshots every apt run → without this we get DOUBLE pre/post pairs (ours + Debian's,
	# confirmed on real hw), filling the keep-N retention twice as fast. Ours
	# (80rikkiti-snapshot) is the one wired to the Settings toggle + nicer descriptions, so
	# turn Debian's off via its documented knob. Idempotent.
	if grep -q '^DISABLE_APT_SNAPSHOT=' /etc/default/snapper 2>/dev/null; then
		sed -i 's/^DISABLE_APT_SNAPSHOT=.*/DISABLE_APT_SNAPSHOT="yes"/' /etc/default/snapper 2>/dev/null || true
	else
		printf 'DISABLE_APT_SNAPSHOT="yes"\n' >> /etc/default/snapper 2>/dev/null || true
	fi
	;;
  pre)
	# before an apt transaction: ONE restore point (a standalone 'single', not a pre/post
	# pair). snapper's pre/post model exists mainly so `snapper diff` can show what an
	# update CHANGED — which we don't surface. For our "roll back a bad update" flow only
	# the before-state is ever used, and singles mean NUMBER_LIMIT=N keeps N updates of
	# history (a pre/post pair would burn two slots per update). See docs/44.
	is_btrfs_snapper || exit 0
	# Honour the Settings ▸ Snapshots "Snapshot before updates" toggle: if the user
	# turned it off, the pane drops this sentinel and we skip the snapshot.
	[ -e /etc/rikkiti/no-apt-snapshot ] && exit 0
	snapper --no-dbus -c root create -t single -c number -d "Before update" >/dev/null 2>&1 || true
	;;
  post)
	# deprecated: we no longer snapshot AFTER updates (before-only, see 'pre'). The apt
	# hook's Post-Invoke is removed, so this is normally never called; kept as an inert
	# no-op that just clears any stale pre-state from an older install.
	rm -f "$PRE_STATE" 2>/dev/null || true
	;;
  nodatacow)
	# First boot (per-user): mark the default game/shader dirs nodatacow while they're
	# still empty, so game files don't fragment. Custom Steam libraries are handled by the
	# file-manager "Optimise for gaming" action. Best-effort; +C only takes on empty dirs.
	is_btrfs_snapper || exit 0
	for d in \
		"$HOME/.local/share/Steam" "$HOME/Games" \
		"$HOME/.cache/mesa_shader_cache" "$HOME/.nv/GLCache" "$HOME/.cache/nvidia" \
		"$HOME/.var/app/com.valvesoftware.Steam"; do
		if [ ! -e "$d" ]; then mkdir -p "$d" 2>/dev/null && chattr +C "$d" 2>/dev/null || true; fi
	done
	;;
  *)
	echo "usage: rikkiti-snapshot {setup|pre|post|nodatacow}" >&2; exit 2 ;;
esac
exit 0
