#!/usr/bin/env bash
# punktfunk — build the HDR-capable `punktfunk-gamescope` for a SteamOS host (called by
# install.sh and update.sh; safe to run by hand).
#
# Stock gamescope offers no 10-bit PQ formats on its PipeWire capture node, so every session on
# the gamescope backend stays 8-bit SDR. This builds gamescope + punktfunk's `pipewire-hdr`
# patches (the ONE canonical recipe, packaging/gamescope/build-punktfunk-gamescope.sh) inside the
# same Debian-trixie distrobox the host is built in, installs it as
# ~/.local/bin/punktfunk-gamescope, and pins the host to it via PUNKTFUNK_GAMESCOPE_BIN in
# host.env. HDR is on by default in the host; with this binary present a 10-bit-capable client
# streams true HDR10 from Game Mode.
#
# BEST-EFFORT BY DESIGN, mirroring the CI packaging paths: streaming works without it (sessions
# stay SDR), so a failure here warns loudly and exits 0 — it must never cost the host install or
# update it runs inside. The one hard rule is honesty at the seams: host.env points at the binary
# ONLY while `--version` proves it runs on SteamOS glass and carries the `+pfhdr` marker; on any
# failure both the binary and the host.env line are removed (a stale absolute override would
# otherwise break gamescope session spawning entirely, which is worse than SDR).
#
# The build clones gamescope fresh each run (submodules included). That costs bandwidth, but it
# only runs when the packaging/gamescope tree changed (pin bump, patch change — tracked by a
# content stamp) or the installed binary stopped working; a no-op re-run is milliseconds.
set -euo pipefail

log()  { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
ok()   { printf '\033[1;32m  ok\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m  !!\033[0m %s\n' "$*" >&2; }

SRC="${PUNKTFUNK_SRC:-$HOME/punktfunk}"
BOX="${PUNKTFUNK_BOX:-pf2}"
GS_BIN="$HOME/.local/bin/punktfunk-gamescope"
STAMP="$HOME/.local/share/punktfunk/gamescope.stamp"
HOST_ENV="$HOME/.config/punktfunk/host.env"
PKGDIR="$SRC/packaging/gamescope"

# host.env may only name the binary while it verifiably works (see header). sed -i is fine: the
# file is ours (install.sh §3) and the line is one this script wrote.
unwire() {
    [ -f "$HOST_ENV" ] || return 0
    if grep -q '^PUNKTFUNK_GAMESCOPE_BIN=' "$HOST_ENV"; then
        sed -i '/^# HDR gamescope built by scripts\/steamdeck/d;/^PUNKTFUNK_GAMESCOPE_BIN=/d' "$HOST_ENV"
        warn "host.env: removed PUNKTFUNK_GAMESCOPE_BIN (no working punktfunk-gamescope) — sessions stream SDR"
    fi
}
wire() {
    [ -f "$HOST_ENV" ] || return 0 # install.sh runs this after §3 wrote host.env; by-hand runs may predate it
    grep -q '^PUNKTFUNK_GAMESCOPE_BIN=' "$HOST_ENV" && return 0
    printf '\n# HDR gamescope built by scripts/steamdeck/build-gamescope.sh (10-bit BT.2020 PQ capture;\n# rebuilt by update.sh; PUNKTFUNK_GAMESCOPE_HDR=0 forces SDR).\nPUNKTFUNK_GAMESCOPE_BIN=%s\n' "$GS_BIN" >> "$HOST_ENV"
    ok "host.env: PUNKTFUNK_GAMESCOPE_BIN=$GS_BIN"
}
# The on-glass truth: the binary must RUN ON STEAMOS (not merely in the build container — this is
# the ABI seam the whole distrobox approach exists for) and carry the +pfhdr banner marker.
verifies() { [ -x "$GS_BIN" ] && "$GS_BIN" --version 2>&1 | head -1 | grep -q '+pfhdr'; }

[ -d "$PKGDIR/patches" ] || { warn "no $PKGDIR — skipping the HDR gamescope build"; exit 0; }

# Content stamp over the packaging tree: a pin bump or patch edit re-triggers the build; anything
# else makes this a fast no-op.
want_stamp="$(find "$PKGDIR" -type f | LC_ALL=C sort | xargs sha256sum | sha256sum | cut -d' ' -f1)"
if [ -f "$STAMP" ] && [ "$(cat "$STAMP")" = "$want_stamp" ] && verifies; then
    ok "punktfunk-gamescope up to date ($("$GS_BIN" --version 2>&1 | head -1))"
    wire
    exit 0
fi

log "Building punktfunk-gamescope (HDR 10-bit capture; ~5-10 min, best-effort)"
# gamescope's build deps in the box (trixie names, mirroring packaging/gamescope/PKGBUILD — keep
# the two lists in step). Provisioned here, not in install.sh's main pass, so a dep problem can
# only ever cost this feature. glm/stb come in as meson wraps; wlroots/libliftoff/vkroots/
# libdisplay-info are vendored submodules — none of those need packages.
if ! distrobox enter "$BOX" -- bash -lc '
set -e
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends \
    meson ninja-build cmake glslang-tools \
    libwayland-dev wayland-protocols libxkbcommon-dev \
    libx11-dev libxcomposite-dev libxdamage-dev libxext-dev libxmu-dev \
    libxrender-dev libxres-dev libxtst-dev libxxf86vm-dev libxcursor-dev \
    libxcb-errors-dev libxcb-icccm4-dev libxcb-ewmh-dev \
    libxcb1-dev libxcb-composite0-dev libxcb-render0-dev libxcb-xfixes0-dev \
    libxcb-shm0-dev libxcb-res0-dev libxcb-present-dev libxcb-xinput-dev \
    libxcb-randr0-dev libxcb-dri3-dev libxcb-shape0-dev \
    libcap-dev libdrm-dev libinput-dev libudev-dev libseat-dev \
    libvulkan-dev libglm-dev libpixman-1-dev libeis-dev \
    libavif-dev libdecor-0-dev hwdata libluajit-5.1-dev \
    libpipewire-0.3-dev libspa-0.2-dev libsdl2-dev \
    xwayland liblcms2-dev >/dev/null
' ; then
    warn "could not provision gamescope build deps in '$BOX' — sessions stay SDR (re-run update.sh to retry)"
    exit 0
fi
if ! distrobox enter "$BOX" -- bash -lc "
set -e
bash '$PKGDIR/build-punktfunk-gamescope.sh' --prefix \"\$HOME/.local\" --no-setcap
"; then
    warn "punktfunk-gamescope failed to build — sessions stay SDR (re-run update.sh to retry)"
    unwire
    exit 0
fi

if verifies; then
    # CAP_SYS_NICE is gamescope's scheduling boost — worth it, never required. Filesystem caps
    # can't be set from the rootless box, so it happens here on the SteamOS side.
    if sudo -n true 2>/dev/null; then
        sudo setcap 'CAP_SYS_NICE=eip' "$GS_BIN" 2>/dev/null \
            && ok "setcap CAP_SYS_NICE (frame-pacing boost)" \
            || warn "could not setcap CAP_SYS_NICE (gamescope still works, pacing slightly worse)"
    fi
    mkdir -p "$(dirname "$STAMP")"
    printf '%s' "$want_stamp" > "$STAMP"
    wire
    ok "punktfunk-gamescope ready: $("$GS_BIN" --version 2>&1 | head -1)"
else
    # Built in the box but does not run on SteamOS (an ABI/soname seam) or lacks the marker. A
    # broken binary must not linger where PATH or host.env could resolve it.
    warn "built binary failed its on-glass check on SteamOS — removing it; sessions stay SDR"
    "$GS_BIN" --version 2>&1 | head -3 >&2 || true
    rm -f "$GS_BIN" "$STAMP"
    unwire
fi
exit 0
