#!/usr/bin/env bash

set -u

if [[ $# -lt 2 ]]; then
    echo "Usage: $0 <Steam AppID> <process regex>" >&2
    exit 2
fi

APPID="$1"
PROCESS_REGEX="$2"

START_TIMEOUT="${START_TIMEOUT:-120}"
EXIT_STABLE_TIME="${EXIT_STABLE_TIME:-3}"

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="${SCRIPT_DIR}/steam-game.log"

log() {
    printf '[%s] [STEAM:%s] %s\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "${APPID}" \
        "$*" >> "${LOG_FILE}"
}

if ! command -v steam >/dev/null 2>&1; then
    log "ERROR: steam command not found"
    exit 127
fi

#
# PIDs du jeu.
#
# On inspecte /proc nous-mêmes afin d'éviter que pgrep -f ne matche
# accidentellement le wrapper avec le regex passé en argument.
#
game_pids() {
    local proc
    local pid
    local cmdline
    local -a argv

    for proc in /proc/[0-9]*; do
        pid="${proc##*/}"

        # Ne jamais nous matcher nous-mêmes.
        [[ "${pid}" == "$$" ]] && continue

        [[ -r "${proc}/cmdline" ]] || continue

        argv=()

        mapfile -d '' -t argv < "${proc}/cmdline" 2>/dev/null || true

        [[ ${#argv[@]} -gt 0 ]] || continue

        cmdline="${argv[*]}"

        if [[ "${cmdline}" =~ ${PROCESS_REGEX} ]]; then
            printf '%s\n' "${pid}"
        fi
    done
}

terminate_game() {
    local -a pids

    mapfile -t pids < <(game_pids)

    if [[ ${#pids[@]} -gt 0 ]]; then
        log "Stopping game processes: ${pids[*]}"

        kill -TERM "${pids[@]}" 2>/dev/null || true

        sleep 3

        mapfile -t pids < <(game_pids)

        if [[ ${#pids[@]} -gt 0 ]]; then
            log "Force stopping remaining processes: ${pids[*]}"
            kill -KILL "${pids[@]}" 2>/dev/null || true
        fi
    fi
}

#
# Important pour la suite :
# si Sunshine arrête ce wrapper, on ferme également le jeu.
#
trap 'log "Wrapper received termination signal"; terminate_game; exit 143' \
    TERM INT HUP

log "Launching Steam AppID ${APPID}"
log "Process regex: ${PROCESS_REGEX}"

nohup steam -applaunch "${APPID}" \
    >> "${LOG_FILE}" 2>&1 &

#
# Attendre que le vrai processus du jeu apparaisse.
#
start_time="${SECONDS}"

while true; do
    mapfile -t pids < <(game_pids)

    if [[ ${#pids[@]} -gt 0 ]]; then
        log "Game detected: ${pids[*]}"
        break
    fi

    if (( SECONDS - start_time >= START_TIMEOUT )); then
        log "ERROR: game did not appear within ${START_TIMEOUT}s"
        exit 124
    fi

    sleep 1
done

#
# Rester vivant aussi longtemps que le jeu.
#
missing_since=""

while true; do
    mapfile -t pids < <(game_pids)

    if [[ ${#pids[@]} -gt 0 ]]; then
        missing_since=""
    else
        if [[ -z "${missing_since}" ]]; then
            missing_since="${SECONDS}"
        fi

        if (( SECONDS - missing_since >= EXIT_STABLE_TIME )); then
            log "Game exited"
            break
        fi
    fi

    sleep 1
done

exit 0