#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
#
# pocketds-steam-bootstrap — first-run-per-user installer for the
# native ARM64 Steam client on the AYANEO Pocket DS.
#
# Derived from Azkali/Switchdeck's install-steam.sh (GPL-3.0), trimmed
# of the interactive y/N prompts and the terminal-respawn dance because
# this runs from a user systemd oneshot, not from a Konsole window.
# Idempotent: bails early when the marker file already exists.
#
# NOTE: on the shipped steamos image this script is usually a NO-OP —
# mkosi.postinst.chroot pre-seeds /home/pocketds/.local/share/Steam
# (client + runtime + package zips) at image-build time and drops the
# marker, so first boot goes straight into Steam with zero downloads.
# This network path exists for users who wipe $STEAMROOT, create a
# second account, or run a non-preseeded image.
#
# What it does:
#   1. Lay out $HOME/.local/share/Steam and $HOME/.steam with the
#      symlinks Steam expects (root, steam).
#   2. Mark the install as `publicbeta` (Steam's ARM client is gated
#      behind the public beta channel).
#   3. Resolve the CURRENT client zip from Valve's publicbeta manifest
#      (the URL hash rotates on every client push — a pinned hash goes
#      stale in weeks and forces a big self-update on first launch),
#      fetch it, and extract the WHOLE zip. The previous version only
#      extracted `steamrtarm64/steam` and left the client to download
#      the other ~55 files itself on first launch — that's the
#      "downloads a bunch of stuff with errors" phase testers hit.
#   4. Fetch the Steam Linux Runtime (steamrt3c, public beta, arm64).
#   5. Drop the Switchdeck launch-steam.sh wrapper into $STEAMROOT so
#      the desktop entry can exec it directly.
#   6. Drop the marker file so subsequent boots are no-ops.
#
# Network failures are non-fatal: the systemd oneshot can retry on the
# next login (the marker is only written after every step succeeds).

set -euo pipefail

STEAMROOT="${HOME}/.local/share/Steam"
STEAMHOME="${HOME}/.steam"
RTARM64ROOT="${STEAMROOT}/steamrtarm64"
MARKER="${STEAMROOT}/.pocketds-steam-bootstrap.done"

# Current-client manifest for the publicbeta linuxarm64 channel. Every
# package zip the client is made of is listed here with its rotating
# URL hash; we resolve the bootstrap zip's current name from it.
STEAM_UPDATE_ROOT="https://client-update.steamstatic.com"
STEAM_MANIFEST_URL="${STEAM_UPDATE_ROOT}/steam_client_publicbeta_linuxarm64"

# Fallback when the manifest itself can't be fetched/parsed. Points at
# a known-good build; the client self-updates from it. Refresh when
# convenient — /etc/pocketds-steam/bootstrap-url overrides at runtime
# so a user can update without re-installing the RPM.
DEFAULT_STEAM_BOOTSTRAP_URL="${STEAM_UPDATE_ROOT}/bins_linuxarm64_linuxarm64.zip.169eb202d9ae774dfc92722bae853efce6b140c9"
STEAM_RUNTIME_URL="https://repo.steampowered.com/steamrt3c/images/latest-public-beta/steam-runtime-steamrt-arm64.tar.xz"

log() { printf 'pocketds-steam-bootstrap: %s\n' "$*" >&2; }

if [ -e "${MARKER}" ]; then
    log "marker present (${MARKER}) — already bootstrapped, exiting"
    exit 0
fi

# The gamescope session runs this synchronously while the user unit may
# already be running it; serialise them so they don't extract over each
# other, and let the loser no-op on the winner's marker.
mkdir -p "${STEAMROOT}"
exec 9>"${STEAMROOT}/.pocketds-steam-bootstrap.lock"
flock 9
if [ -e "${MARKER}" ]; then
    log "bootstrap finished in another instance, exiting"
    exit 0
fi

# 1. Skeleton + symlinks. Idempotent.
mkdir -p "${STEAMHOME}"
ln -fsn "${STEAMROOT}" "${STEAMHOME}/root"
ln -fsn "${STEAMROOT}" "${STEAMHOME}/steam"

# 2. Beta channel marker.
mkdir -p "${STEAMROOT}/package"
if [ ! -f "${STEAMROOT}/package/beta" ] || \
   [ "$(cat "${STEAMROOT}/package/beta" 2>/dev/null)" != "publicbeta" ]; then
    rm -f "${STEAMROOT}/package/beta"
    echo "publicbeta" > "${STEAMROOT}/package/beta"
    chmod 444 "${STEAMROOT}/package/beta"
fi

# 3. Steam client bootstrap zip — resolve current name, download,
#    extract everything.
if [ ! -x "${RTARM64ROOT}/steam" ]; then
    URL_OVERRIDE="/etc/pocketds-steam/bootstrap-url"
    if [ -r "${URL_OVERRIDE}" ]; then
        STEAM_BOOTSTRAP_URL="$(head -1 "${URL_OVERRIDE}" | tr -d '[:space:]')"
        log "using override URL from ${URL_OVERRIDE}"
    else
        # "file"  "bins_linuxarm64_linuxarm64.zip.<sha1>" in the vdf.
        current_zip="$(wget -qO- -t 3 -T 30 "${STEAM_MANIFEST_URL}" \
            | awk -F'"' '$2 == "file" && $4 ~ /^bins_linuxarm64_linuxarm64\.zip\./ {print $4; exit}')" || :
        if [ -n "${current_zip:-}" ]; then
            STEAM_BOOTSTRAP_URL="${STEAM_UPDATE_ROOT}/${current_zip}"
            log "resolved current client zip: ${current_zip}"
        else
            STEAM_BOOTSTRAP_URL="${DEFAULT_STEAM_BOOTSTRAP_URL}"
            log "manifest fetch failed — falling back to pinned URL"
        fi
    fi

    log "fetching steamrtarm64 bootstrap from ${STEAM_BOOTSTRAP_URL}"
    tmpzip="$(mktemp -p "${STEAMROOT}" linuxarm64.XXXXXX.zip)"
    if ! wget -q --show-progress -c -t 5 -O "${tmpzip}" "${STEAM_BOOTSTRAP_URL}"; then
        rm -f "${tmpzip}"
        log "steam bootstrap download failed — will retry on next login"
        exit 1
    fi
    # Extract the whole client payload, not just the launcher. -o so a
    # partial previous extract is overwritten cleanly.
    unzip -o -q -d "${STEAMROOT}" "${tmpzip}"
    chmod +x "${RTARM64ROOT}/steam"
    rm -f "${tmpzip}"
fi

# 4. Steam Linux Runtime.
if [ ! -d "${RTARM64ROOT}/pv-runtime/steam-runtime-steamrt-arm64" ]; then
    log "fetching Steam Linux Runtime (steamrt3c arm64) — this is large"
    mkdir -p "${RTARM64ROOT}/pv-runtime"
    tmptar="$(mktemp -p "${RTARM64ROOT}/pv-runtime" steamrt.XXXXXX.tar.xz)"
    if ! wget -q --show-progress -c -t 5 -O "${tmptar}" "${STEAM_RUNTIME_URL}"; then
        rm -f "${tmptar}"
        log "steam runtime download failed — will retry on next login"
        exit 1
    fi
    tar -xf "${tmptar}" --directory "${RTARM64ROOT}/pv-runtime" \
        --checkpoint=200 --checkpoint-action=dot
    rm -f "${tmptar}"
fi

# 5. launch-steam.sh — copy from the system-installed location into
#    $STEAMROOT so the launcher can be invoked directly without
#    requiring the package to stay installed at the same path.
#    An existing launcher that differs (a prior Switchdeck install, or
#    local edits) is kept next to it rather than silently replaced.
if [ -e "${STEAMROOT}/launch-steam.sh" ] && \
   ! cmp -s /usr/share/pocketds-steam/launch-steam.sh "${STEAMROOT}/launch-steam.sh"; then
    backup="${STEAMROOT}/launch-steam.sh.pre-pocketds.$(date +%Y%m%d%H%M%S)"
    cp -p "${STEAMROOT}/launch-steam.sh" "${backup}"
    log "existing launch-steam.sh differs — kept as ${backup##*/}"
fi
install -m 0755 /usr/share/pocketds-steam/launch-steam.sh \
    "${STEAMROOT}/launch-steam.sh"

# 6. Marker. The user .desktop / first-launch symlinks are written by
#    launch-steam.sh itself on its first run (see Switchdeck's design).
touch "${MARKER}"
log "bootstrap complete"
