#!/usr/bin/env bash
set -euo pipefail

ROOT="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
RUNTIME_ROOT="${ROOT}/runtime/native"
OUT_ROOT="${ROOT}/runtime/native-smoke"
DEMO_SELECTOR="${ROOT}/port/native/select-server-demo.sh"
RAW_LOG_FILE="${OUT_ROOT}/playback.raw.log"
LOG_FILE="${OUT_ROOT}/playback.log"
CONTROL_FIFO="${OUT_ROOT}/playback-console.in"
TIMEOUT_SECONDS="${Q4_PLAYBACK_TIMEOUT:-90}"

if [[ $# -gt 1 ]]; then
    echo "Usage: $0 [demo.q4sd]" >&2
    exit 2
fi

if [[ $# -eq 1 ]]; then
    DEMO_FILE="$(realpath -- "$1")"
else
    # A map-rotation smoke can leave a short final demo immediately before
    # shutdown. Prefer the largest finalized recording so playback exercises
    # the useful match rather than that trailing fragment.
    DEMO_FILE="$("${DEMO_SELECTOR}" "${OUT_ROOT}/replays" 2>/dev/null)" || {
        echo "No server demo found; run port/native/smoke-dedicated.sh first" >&2
        exit 1
    }
fi

[[ -x "${RUNTIME_ROOT}/openQ4-client_x64" ]] || {
    echo "Native client is missing; run tools/build-native.sh first" >&2
    exit 1
}
[[ -f "${DEMO_FILE}" && "${DEMO_FILE}" == *.q4sd ]] || {
    echo "Server demo is missing or has the wrong extension: ${DEMO_FILE}" >&2
    exit 1
}
for command in pgrep script xvfb-run; do
    command -v "${command}" >/dev/null 2>&1 || {
        echo "Required playback command is missing: ${command}" >&2
        exit 1
    }
done

mkdir -p -- "${OUT_ROOT}" "${RUNTIME_ROOT}/home-playback"
rm -f -- "${RAW_LOG_FILE}" "${LOG_FILE}" "${CONTROL_FIFO}"
mkfifo -- "${CONTROL_FIFO}"
exec 3<>"${CONTROL_FIFO}"

client_pid=""
cleanup() {
    if [[ -n "${client_pid}" ]]; then
        child_pids="$(pgrep -P "${client_pid}" 2>/dev/null || true)"
        [[ -z "${child_pids}" ]] || kill ${child_pids} 2>/dev/null || true
        kill "${client_pid}" 2>/dev/null || true
        wait "${client_pid}" 2>/dev/null || true
    fi
    exec 3>&-
    rm -f -- "${CONTROL_FIFO}"
}
trap cleanup EXIT INT TERM

wait_for_log() {
    local pattern="$1"
    local timeout="$2"
    local started=${SECONDS}

    until grep -Fq -- "${pattern}" "${RAW_LOG_FILE}" 2>/dev/null; do
        if ! kill -0 "${client_pid}" 2>/dev/null; then
            echo "Native client exited while waiting for: ${pattern}" >&2
            return 1
        fi
        if (( SECONDS - started >= timeout )); then
            echo "Timed out waiting for replay evidence: ${pattern}" >&2
            return 1
        fi
        sleep 0.25
    done
}

client_command=(
    "${RUNTIME_ROOT}/openQ4-client_x64"
    +set fs_basepath "${RUNTIME_ROOT}"
    +set fs_savepath "${RUNTIME_ROOT}/home-playback"
    +set com_skipLogoVideos 1
    +set r_fullscreen 0
    +set r_mode 3
    +set s_noSound 1
    +set si_gameType dm
    +playServerDemo "${DEMO_FILE}"
)
printf -v client_command_line '%q ' "${client_command[@]}"

set +e
ALSOFT_DRIVERS=null TERM=xterm xvfb-run -a -s '-screen 0 1280x720x24' \
    script -qefc "${client_command_line}" "${RAW_LOG_FILE}" <&3 >/dev/null 2>&1 &
client_pid=$!
set -e

wait_for_log "playing full-state server demo ${DEMO_FILE}" "${TIMEOUT_SECONDS}"
wait_for_log "finished server demo ${DEMO_FILE}" "${TIMEOUT_SECONDS}"
printf 'quit\n' >&3

set +e
for (( i = 0; i < 80; i++ )); do
    kill -0 "${client_pid}" 2>/dev/null || break
    sleep 0.25
done
if kill -0 "${client_pid}" 2>/dev/null; then
    client_rc=124
else
    wait "${client_pid}"
    client_rc=$?
    client_pid=""
fi
set -e

tr -d '\r' <"${RAW_LOG_FILE}" >"${LOG_FILE}"

failure=0
if [[ ${client_rc} -ne 0 ]]; then
    echo "Native replay client exited with code ${client_rc}" >&2
    failure=1
fi
for pattern in 'truncated server demo' 'invalid server demo' 'unsupported server demo' 'could not open server demo' 'Fatal Error'; do
    if grep -Fq "${pattern}" "${LOG_FILE}"; then
        echo "Replay log contains failure: ${pattern}" >&2
        failure=1
    fi
done

echo "Playback demo: ${DEMO_FILE}"
echo "Playback log: ${LOG_FILE}"
echo "Native client exit code: ${client_rc}"
exit "${failure}"
