#!/bin/bash
set -euo pipefail
LOG_FILE="$HOME/.local/logs/session.log"

log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; }

CONF_FILE="$HOME/.config/gamescope/gamescope.conf"
[ -f "$CONF_FILE" ] && source "$CONF_FILE"

RESOLUTION=${RESOLUTION:-1920x1080}
WIDTH="${RESOLUTION%x*}"
HEIGHT="${RESOLUTION#*x}"
FRAMERATE=${FRAMERATE:-60}

export __GL_GSYNC_ALLOWED=1
export __GL_VRR_ALLOWED=1
export __GL_SHADER_DISK_CACHE=1
export __GL_SYNC_TO_VBLANK=0
export __GLX_VENDOR_LIBRARY_NAME=nvidia
export LIBVA_DRIVER_NAME=nvidia
export NVD_BACKEND=direct

GAMESCOPE_BIN="$(command -v gamescope || true)"
if [ -z "$GAMESCOPE_BIN" ]; then
	log "ERROR: gamescope not found in PATH"
	exit 127
fi

HDR_FLAG=""
if [[ "$HDR_ENABLED" == "1" || "$HDR_ENABLED" == "true" || "$HDR_ENABLED" == "yes" ]]; then
    HDR_FLAG="--hdr-enabled"
    log "HDR flag added: --hdr-enabled"
else
    log "HDR disabled, no HDR flag added"
fi

# Create run directory file for startup and stats sockets
#   shellcheck disable=SC2030 # (broken warning)
tmpdir="$([[ -n ${XDG_RUNTIME_DIR+x} ]] && mktemp -p "$XDG_RUNTIME_DIR" -d -t gamescope.XXXXXXX)"
socket="${tmpdir:+$tmpdir/startup.socket}"
stats="${tmpdir:+$tmpdir/stats.pipe}"
# Fail early if we don't have a proper runtime directory setup
#   shellcheck disable=SC2031 # (broken warning)
if [[ -z $tmpdir || -z ${XDG_RUNTIME_DIR+x} ]]; then
	echo >&2 "!! Failed to find run directory in which to create stats session sockets (is \$XDG_RUNTIME_DIR set?)"
	exit 0
fi

# Setup MangoHud config file in temp directory
export MANGOHUD_CONFIGFILE="${tmpdir:+$tmpdir/mangohud.config}"

# Initially write no_display to our config file
# so we don't get mangoapp showing up before Steam initializes
# on OOBE and stuff.
mkdir -p "$(dirname "$MANGOHUD_CONFIGFILE")"
echo "no_display" > "$MANGOHUD_CONFIGFILE"

# Chromium (and therefore Steam) ignore XCursor and use on the GTK config
kwriteconfig6 --file gtk-3.0/settings.ini  --group Settings --key gtk-cursor-theme-name steam

# Workaround for Steam login issue while Steam client change propagates out of Beta
touch ~/.steam/root/config/SteamAppData.vdf || true

# Increase open file limit for gamescope session
ulimit -n 524288

# 1048576 = 1M - passing it like that omits the 'M' suffix - xargs removes whitespace
free_disk_space_megs=$(df ~/ --output=avail -B1048576 | sed -n '2 p' | xargs)
minimum_free_disk_space_needed_megs=500

if [[ "$free_disk_space_megs" -lt "$minimum_free_disk_space_needed_megs" ]]; then
	echo >&2 "gamescope-session: not enough disk space to proceed, trying to find game to delete"

	find ~/.local/share/Steam/steamapps/common/ -mindepth 1 -maxdepth 1 -type d -printf "%T@ %p\0" | sort -n -z | while IFS= read -r -d $'\0' line; do
		timestamp=${line%% *}
                game_folder=${line#* }

		[[ -d $game_folder ]]  || continue

		acf=$(grep -F -- "$(basename -- "$game_folder")" ~/.local/share/Steam/steamapps/*.acf | grep \"installdir\" | cut -d: -f1)
		[[ -e "$acf" ]] || continue

		echo >&2 "gamescope-session: deleting $(basename "$game_folder")"
		appid=$(basename "$acf" | cut -d_ -f2 | cut -d. -f1)

		# TODO leave a note for Steam to display UI to explain what happened, if this logic stays
		# intentionally leave compatdata; could be unclouded save files there
		rm -rf --one-file-system -- "$game_folder" "$acf" ~/.local/share/Steam/steamapps/shadercache/"$appid"

		free_disk_space_megs=$(df ~/ --output=avail -B1048576 | sed -n '2 p' | xargs)
		[[ "$free_disk_space_megs" -lt "$minimum_free_disk_space_needed_megs" ]] || break
	done
fi

export GAMESCOPE_STATS="$stats"
mkfifo -- "$stats"
mkfifo -- "$socket"

# Attempt to claim global session if we're the first one running (e.g. /run/1000/gamescope)
linkname="gamescope-stats"
#   shellcheck disable=SC2031 # (broken warning)
sessionlink="${XDG_RUNTIME_DIR:+$XDG_RUNTIME_DIR/}${linkname}" # Account for XDG_RUNTIME_DIR="" (notfragileatall)
lockfile="$sessionlink".lck
exec 9>"$lockfile" # Keep as an fd such that the lock lasts as long as the session if it is taken
if flock -n 9 && rm -f "$sessionlink" && ln -sf "$tmpdir" "$sessionlink"; then
	# Took the lock.  Don't blow up if those commands fail, though.
	echo >&2 "Claimed global gamescope stats session at \"$sessionlink\""
else
	echo >&2 "!! Failed to claim global gamescope stats session"
fi

read_gamescope_env() {
	log "Waiting for gamescope to provide DISPLAY and GAMESCOPE_WAYLAND_DISPLAY via socket..."
	if read -r -t 3 response_x_display response_wl_display <> "$socket"; then
		log "Received gamescope environment:"
		log "  DISPLAY=$response_x_display"
		log "  GAMESCOPE_WAYLAND_DISPLAY=$response_wl_display"
		export DISPLAY="$response_x_display"
		export GAMESCOPE_WAYLAND_DISPLAY="$response_wl_display"

		# Sync environment variables to systemd, then notify we are ready to launch subsequent services
		log "Storing gamescope environment for systemd..."
		env > $XDG_RUNTIME_DIR/gamescope-environment
		systemd-notify --ready
	fi
}

# Spawned in parallel to read values from gamescope
(read_gamescope_env &)

log "Starting Gamescope session..."

# Build gamescope argument array for safe quoting and readability
GAMESCOPE_ARGS=(
	--generate-drm-mode fixed
	--fade-out-duration 200
	--cursor-scale-height 720
	-f
	-W "$WIDTH" -H "$HEIGHT"
	-w "$WIDTH" -h "$HEIGHT"
	--rt --mangoapp -e -R "$socket" -T "$stats"
)

# Append HDR flag if enabled
if [ -n "${HDR_FLAG:-}" ]; then
    GAMESCOPE_ARGS+=("$HDR_FLAG")
fi

export XDG_CURRENT_DESKTOP=gamescope
export XDG_SESSION_TYPE=wayland
export DESKTOP_SESSION=gamescope

log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*"
sudo setcap 'CAP_SYS_NICE=eip' "$GAMESCOPE_BIN"

exec "$GAMESCOPE_BIN" "${GAMESCOPE_ARGS[@]}" >>"$LOG_FILE" 2>&1

