#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
#
# pocketds-gamescope-session — SteamOS-style session entry point for the
# AYANEO Pocket DS `steamos` image profile.
#
# This is the Exec= target of the wayland-session desktop file the
# display manager (plasmalogin) autologins into on the steamos profile
# (see 15-pocketds-steam-session.conf). It does two things:
#
#   1. Acts as a session *dispatcher*: reads the user's last
#      "gaming vs desktop" choice (written by steamos-session-select)
#      and, when the user asked for the desktop, hands off to the stock
#      Plasma Wayland session instead of gamescope. This is what makes
#      Steam Big Picture's "Switch to Desktop" — and the desktop's
#      "Return to Gaming Mode" launcher — actually work: each writes the
#      selection then logs out, and this dispatcher runs again on the
#      autologin that follows.
#
#   2. In gaming mode, launches the Flip-DS gamescope fork holding the
#      TOP panel (DSI-1) for Steam Big Picture, and starts Steam in its
#      gamepad UI inside it (pocketds-steam already adds
#      -gamepadui -steamdeck -steampal).
#
# Everything device-specific below can be overridden without rebuilding
# the RPM by dropping shell assignments in
# /etc/pocketds-steam/gamescope-session.conf (sourced if present).

set -u

log() { echo "pocketds-gamescope-session[$$]: $*" >&2 || :; }

# ── session selection (gaming | desktop) ────────────────────────────
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/pocketds-steam"
SEL_FILE="$STATE_DIR/session"
mkdir -p "$STATE_DIR" 2>/dev/null || :

mode="gaming"
if [ -r "$SEL_FILE" ]; then
    mode="$(cat "$SEL_FILE" 2>/dev/null || echo gaming)"
fi

start_plasma() {
    # The display manager launched us from a wayland-session whose
    # DesktopNames=gamescope; force the Plasma identity back so
    # OnlyShowIn=KDE autostarts (pocketds-plasma-defaults, the
    # touchscreen mapper, …) still fire. startplasma-wayland also sets
    # XDG_CURRENT_DESKTOP=KDE itself, but set it here too for the phase
    # before it takes over.
    export XDG_SESSION_DESKTOP=KDE
    export XDG_CURRENT_DESKTOP=KDE
    export DESKTOP_SESSION=plasma
    # SteamOS-style "Return to Gaming Mode" shortcut on the desktop. An
    # executable copy, so Plasma trusts it; refreshed when the packaged
    # entry changes.
    local desktop_dir rtg=/usr/share/applications/pocketds-return-to-gaming.desktop
    desktop_dir="$(xdg-user-dir DESKTOP 2>/dev/null || echo "$HOME/Desktop")"
    if [ -r "$rtg" ] && ! cmp -s "$rtg" "$desktop_dir/${rtg##*/}"; then
        install -D -m 0755 "$rtg" "$desktop_dir/${rtg##*/}" || :
    fi
    # startplasma-wayland is the same binary plasma.desktop's Exec runs.
    exec /usr/bin/startplasma-wayland
}

if [ "$mode" = "desktop-once" ]; then
    printf 'gaming\n' > "$SEL_FILE" 2>/dev/null || :
    log "one-shot desktop selection — starting Plasma (Wayland)"
    start_plasma
fi
if [ "$mode" = "desktop" ]; then
    log "session selection is 'desktop' — starting Plasma (Wayland)"
    start_plasma
fi

# ── sanity: is the Steam client actually installed for this user? ──
# The steamos image pre-seeds /home/pocketds at build time, so this is
# normally present. If it isn't (fresh user, wiped $STEAMROOT), give
# the bootstrap one synchronous chance — then, if there is STILL no
# client (e.g. no Wi-Fi configured yet on a non-preseeded image), fall
# back to the Plasma desktop instead of handing gamescope a Steam
# launcher that exits immediately. The old behaviour was a black
# screen followed by a silent session exit and a greeter loop; the
# desktop at least lets the user connect Wi-Fi, after which the
# pocketds-steam-bootstrap user unit completes and the next login (or
# "Return to Gaming Mode") lands in Steam.
STEAM_BIN="${HOME}/.local/share/Steam/steamrtarm64/steam"
if [ ! -x "$STEAM_BIN" ] && command -v pocketds-steam-bootstrap >/dev/null 2>&1; then
    log "steam client missing — running bootstrap before starting gamescope"
    pocketds-steam-bootstrap || :
fi
if [ ! -x "$STEAM_BIN" ]; then
    log "no steam client after bootstrap attempt — falling back to Plasma"
    start_plasma
fi

# ── gaming mode: gamescope + Steam Big Picture ──────────────────────
# Defaults tuned for the Pocket DS panel layout (see
# pocketds-userspace/kwinoutputconfig.json):
#   DSI-1 — 1080x1920 native, mounted rotated → 1920x1080 landscape,
#           the main gaming panel. Touch: "generic ft5x06 (44)".
#   DSI-2 — 768x1024 bottom companion panel. Touch:
#           "Goodix Capacitive TouchScreen".
OUTPUT="DSI-1"
# The top panel's native portrait mode: with the rotated 1920x1080,
# gamescope drove DSI-1 at 165 Hz whatever REFRESH said.
WIDTH=1080
HEIGHT=1920
REFRESH=120
# Panel is physically rotated 90° vs. its native portrait scanout. The
# DPU can't rotate 90° at scanout, so gamescope rotates in the
# compositor, where "left" is upright on this panel ("right" renders
# upside down).
ORIENTATION="left"
# Bottom-panel touchscreen — kept OFF the top compositor so a thumb on
# the lower screen doesn't drive the Big Picture cursor.
IGNORE_TOUCH="Goodix Capacitive TouchScreen"
# Bottom-panel DRM lease for the game-mode flip-companion, on when it
# is installed. With LEASE_BOTTOM=1 gamescope leases LEASE_CONNECTOR and
# hands the lease fd out on LEASE_SOCK (created 0600), and COMPANION_CMD is
# started once that socket exists. COMPANION_CMD is evaluated by the
# shell with GAMESCOPE_LEASE_SOCK exported; it runs only as long as
# gamescope does, is restarted if it dies early, and logs to
# COMPANION_LOG.
LEASE_BOTTOM=0
command -v flip-companion >/dev/null 2>&1 && LEASE_BOTTOM=1
LEASE_CONNECTOR="DSI-2"
LEASE_SOCK="${XDG_RUNTIME_DIR:-/tmp}/gamescope-lease.sock"
# shellcheck disable=SC2016
COMPANION_CMD='flip-companion --lease-socket "$GAMESCOPE_LEASE_SOCK"'
COMPANION_LOG="$STATE_DIR/companion.log"
# Extra flags appended verbatim to the gamescope command line.
EXTRA_ARGS=""

# Local overrides.
if [ -r /etc/pocketds-steam/gamescope-session.conf ]; then
    # shellcheck disable=SC1091
    . /etc/pocketds-steam/gamescope-session.conf
fi

GAMESCOPE_ARGS=(
    --prefer-output "$OUTPUT"
    -W "$WIDTH" -H "$HEIGHT"
    -r "$REFRESH"
    --force-orientation "$ORIENTATION"
    --xwayland-count 2
    --steam
)
[ -n "$IGNORE_TOUCH" ] && GAMESCOPE_ARGS+=(--ignore-touch-device "$IGNORE_TOUCH")
[ "$LEASE_BOTTOM" = "1" ] && GAMESCOPE_ARGS+=(--lease-connector "$LEASE_CONNECTOR")
# shellcheck disable=SC2206
[ -n "$EXTRA_ARGS" ] && GAMESCOPE_ARGS+=($EXTRA_ARGS)

# Supervise the companion from a child of this shell. After the exec
# below this shell's PID is gamescope's, so the child polls it: the
# companion starts once the lease socket exists and is killed when
# gamescope exits — the session scope is not torn down on logout.
start_companion() {
    local gs_pid=$$ tries=0 started pid=
    exec >>"$COMPANION_LOG" 2>&1 </dev/null
    log "companion: waiting for $GAMESCOPE_LEASE_SOCK"
    while [ ! -S "$GAMESCOPE_LEASE_SOCK" ]; do
        kill -0 "$gs_pid" 2>/dev/null || exit 0
        tries=$((tries + 1))
        if [ "$tries" -gt 300 ]; then
            log "companion: lease socket never appeared, giving up"
            exit 1
        fi
        sleep 0.1
    done
    trap '[ -n "${pid:-}" ] && kill "$pid" 2>/dev/null; exit 0' TERM INT
    local failures=0
    while [ "$failures" -lt 5 ]; do
        log "companion: starting: $COMPANION_CMD"
        started=$SECONDS
        eval "exec $COMPANION_CMD" &
        pid=$!
        while kill -0 "$pid" 2>/dev/null; do
            if ! kill -0 "$gs_pid" 2>/dev/null; then
                log "companion: gamescope gone, stopping companion"
                kill "$pid" 2>/dev/null
                sleep 2
                kill -KILL "$pid" 2>/dev/null
                exit 0
            fi
            sleep 1
        done
        wait "$pid"
        log "companion: exited with status $?"
        kill -0 "$gs_pid" 2>/dev/null || exit 0
        if [ $((SECONDS - started)) -ge 30 ]; then
            failures=0
        else
            failures=$((failures + 1))
        fi
        sleep 2
    done
    log "companion: crashed repeatedly, not restarting"
}

if [ "$LEASE_BOTTOM" = "1" ]; then
    export GAMESCOPE_LEASE_SOCK="$LEASE_SOCK"
    rm -f "$GAMESCOPE_LEASE_SOCK"
    if [ -n "$COMPANION_CMD" ]; then
        mkdir -p "${COMPANION_LOG%/*}" 2>/dev/null || :
        : >"$COMPANION_LOG" 2>/dev/null || COMPANION_LOG=/dev/null
        start_companion &
    fi
fi

# Tell Steam it's in a gamescope session (enables the in-client power
# menu / "Switch to Desktop", matching SteamOS behaviour).
export STEAM_DISPLAY_TRANSFORM_HINT=1
export gamescope_session=1
# Steam handles the volume keys itself in gaming mode (no Plasma there).
export STEAM_ENABLE_VOLUME_HANDLER=1

pocketds-steam-no-idle-suspend || log "no-idle-suspend failed (continuing)"

# Gaming mode never suspends: the GT911 and the Renesas xHCI do not
# survive it yet, and logind would otherwise suspend on the power-key
# press and wake on its release. The block lock lives as long as
# gamescope; Plasma keeps its normal suspend.
log "starting gamescope: ${GAMESCOPE_ARGS[*]} -- pocketds-steam"
exec systemd-inhibit --mode=block \
    --what=sleep:handle-suspend-key:handle-hibernate-key:handle-power-key \
    --who="Pocket DS gaming mode" --why="Suspend is not supported in gaming mode yet" \
    gamescope "${GAMESCOPE_ARGS[@]}" -- /usr/bin/pocketds-steam -steamos3
