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

LAB_ROOT=${W3CS_LAB_ROOT:-/home/ubuntu/w3cs-lab}
CLASSIC_ROOT=${W3_CLASSIC_ROOT:-/opt/war3-runtime/classic}
GAME_DIR="$CLASSIC_ROOT/war3-1285/Warcraft III"
PREFIX=${WINEPREFIX:-"$CLASSIC_ROOT/prefix"}
DISPLAY_NUMBER=${W3_D3D9_DISPLAY:-:11}
SOURCE_WIDTH=${W3_D3D9_SOURCE_WIDTH:-1024}
SOURCE_HEIGHT=${W3_D3D9_SOURCE_HEIGHT:-768}
DISPLAY_WIDTH=${W3_D3D9_DISPLAY_WIDTH:-1920}
DISPLAY_HEIGHT=${W3_D3D9_DISPLAY_HEIGHT:-1440}
CAPTURE=${W3_D3D9_CAPTURE_FILE:-/tmp/w3cs-command-stream.bin}
REPLAY_SOURCE=${W3_D3D9_TEST_REPLAY:-"$LAB_ROOT/test.w3g"}
REPLAY_STORE=${W3CS_REPLAY_ROOT:-"$LAB_ROOT/replays"}
SESSION_COMMAND=${W3_D3D9_SESSION_COMMAND:-"$LAB_ROOT/lab-game-session.sh"}
SWITCH_COMMAND=${W3_D3D9_SWITCH_COMMAND:-"$LAB_ROOT/lab-switch-replay.sh"}
PERSISTENT_SESSION=${W3CS_PERSISTENT_SESSION:-1}
WARM_REPLAY=${W3CS_WARM_REPLAY:-default}
WARM_PROFILE=${W3CS_WARM_PROFILE:-native-1285}
REPLAY_DIRECTORY="$PREFIX/drive_c/users/ubuntu/Documents/Warcraft III/Replays"
REPLAY_WINDOWS='C:\users\ubuntu\Documents\Warcraft III\Replays\trace.w3g'
# Multi-seat: every seat is one full stack (Xvfb + relay + game) with its own
# display, signaling port, ICE range, capture/control files, prefix, pulse
# sink, and logs. The launcher (w3cs-seat-launch.sh) derives these per seat.
RELAY_PORT=${W3CS_RELAY_PORT:-8145}
ICE_MIN=${W3CS_ICE_MIN:-40000}
ICE_MAX=${W3CS_ICE_MAX:-40199}
GAME_CONTROL=${W3CS_GAME_CONTROL:-/tmp/w3cs-game-control}
PULSE_SINK_NAME=${W3CS_PULSE_SINK:-w3cs}
LOG_SUFFIX=${W3CS_LOG_SUFFIX:-}
BRIDGE_LOG=/tmp/w3cs-bridge$LOG_SUFFIX.log
XVFB_LOG=/tmp/w3cs-xvfb$LOG_SUFFIX.log
WAR3_LOG=/tmp/w3cs-war3$LOG_SUFFIX.log

export WINEPREFIX="$PREFIX"
export WINEARCH=win32
export WINEDEBUG=${WINEDEBUG:--all}
export PATH=/opt/wine-staging/bin:$PATH
export DISPLAY="$DISPLAY_NUMBER"
export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}
export PULSE_SERVER=${PULSE_SERVER:-unix:$XDG_RUNTIME_DIR/pulse/native}
export __GLX_VENDOR_LIBRARY_NAME=mesa
export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json
export GALLIUM_DRIVER=llvmpipe
export LP_NUM_THREADS=${LP_NUM_THREADS:-3}
export LIBGL_ALWAYS_SOFTWARE=1
export WINEDLLOVERRIDES='d3d9=n,b'
export W3_D3D9_STREAM_FILE=${W3_D3D9_STREAM_FILE:-'Z:\tmp\w3cs-command-stream.bin'}
export W3_D3D9_STREAM_CREATE=${W3_D3D9_STREAM_CREATE:-1}
export W3_D3D9_NO_RASTER=${W3_D3D9_NO_RASTER:-1}
export W3_D3D9_HEADLESS_FAST=${W3_D3D9_HEADLESS_FAST:-1}
export W3_D3D9_MAX_FPS=${W3_D3D9_MAX_FPS:-40}
export W3_D3D9_CAPTURE_FPS=${W3_D3D9_CAPTURE_FPS:-40}
export W3_D3D9_CONTROL_FILE=${W3_D3D9_CONTROL_FILE:-'Z:\tmp\w3cs-game-control'}
export W3CS_REPLAY_ROOT="$REPLAY_STORE"
NATIVE_RELAY=${W3CS_NATIVE_RELAY:-1}

# Kill only THIS seat's previous generation: patterns are scoped by display
# so concurrent seats never take each other down.
wineserver -k 2>/dev/null || true
pkill -f "Xvfb $DISPLAY_NUMBER " 2>/dev/null || true
pkill -f "lab_live_bridge.py.*--display $DISPLAY_NUMBER" 2>/dev/null || true
pkill -f "w3cs-webrtc-relay.*--display $DISPLAY_NUMBER" 2>/dev/null || true
for _ in $(seq 1 20); do
  if ! pgrep -f "Xvfb $DISPLAY_NUMBER |lab_live_bridge.py.*--display $DISPLAY_NUMBER|w3cs-webrtc-relay.*--display $DISPLAY_NUMBER" >/dev/null 2>&1; then
    break
  fi
  sleep .1
done
pkill -KILL -f "Xvfb $DISPLAY_NUMBER " 2>/dev/null || true
pkill -KILL -f "lab_live_bridge.py.*--display $DISPLAY_NUMBER" 2>/dev/null || true
pkill -KILL -f "w3cs-webrtc-relay.*--display $DISPLAY_NUMBER" 2>/dev/null || true

# Create the new generation's mutable files only after the prior bridge and
# Wine server have stopped.
mkdir -p "$REPLAY_DIRECTORY" "$PREFIX/drive_c/users/ubuntu/Temp" \
  "$REPLAY_STORE"
cmp -s "$REPLAY_SOURCE" "$REPLAY_STORE/default.w3g" 2>/dev/null || \
  cp "$REPLAY_SOURCE" "$REPLAY_STORE/default.w3g"
rm -f "$CAPTURE" "$WAR3_LOG" "$BRIDGE_LOG" "$GAME_CONTROL"

# Install the proxy only after the previous lab generation has stopped. An old
# generation must never remove a proxy that the new generation just installed.
# The base-dir targets are shared by every seat; only rewrite a stale proxy
# so two seats starting together never truncate a dll the other is loading.
install_proxy() {
  cmp -s "$LAB_ROOT/d3d9.dll" "$1" 2>/dev/null || cp "$LAB_ROOT/d3d9.dll" "$1"
}
install_proxy "$GAME_DIR/d3d9.dll"
if [[ -d "$CLASSIC_ROOT/war3rk/Warcraft III" ]]; then
  install_proxy "$CLASSIC_ROOT/war3rk/Warcraft III/d3d9.dll"
fi
if [[ -d "$CLASSIC_ROOT/war3-1140/Warcraft III" ]]; then
  install_proxy "$CLASSIC_ROOT/war3-1140/Warcraft III/d3d9.dll"
fi
if [[ -d /opt/war3-runtime/classic-131/source/Warcraft\ III/x86 ]]; then
  install_proxy /opt/war3-runtime/classic-131/source/Warcraft\ III/x86/d3d9.dll
fi

Xvfb "$DISPLAY_NUMBER" -screen 0 "${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}x24" \
  -nolisten tcp -ac \
  +extension GLX +render -extension MIT-SHM -noreset \
  >"$XVFB_LOG" 2>&1 &
xvfb_pid=$!

cleaned=0
bridge_pid=0
cleanup() {
  if [[ "$cleaned" == 1 ]]; then
    return
  fi
  cleaned=1
  if [[ "$bridge_pid" -gt 0 ]]; then
    kill "$bridge_pid" 2>/dev/null || true
  fi
  kill "$xvfb_pid" 2>/dev/null || true
  for _ in $(seq 1 20); do
    if [[ "$bridge_pid" -le 0 ]] || ! kill -0 "$bridge_pid" 2>/dev/null; then
      break
    fi
    sleep .1
  done
  if [[ "$bridge_pid" -gt 0 ]]; then
    kill -KILL "$bridge_pid" 2>/dev/null || true
  fi
  kill -KILL "$xvfb_pid" 2>/dev/null || true
  wineserver -k 2>/dev/null || true
}
terminate() {
  cleanup
  exit 0
}
trap cleanup EXIT
trap terminate INT TERM

sleep 1
# One pulse daemon serves every seat; each seat only ensures the daemon is
# up and owns a private null sink. Never kill the daemon here - that would
# silence the other seats mid-session.
W3CS_PULSE_SERVER="$PULSE_SERVER"
unset PULSE_SERVER
if ! pactl info >/dev/null 2>&1; then
  pulseaudio --start --exit-idle-time=-1 2>/dev/null || true
fi
export PULSE_SERVER="$W3CS_PULSE_SERVER"
for _ in $(seq 1 40); do
  pactl info >/dev/null 2>&1 && break
  sleep .05
done
pactl info >/dev/null
pactl list short sinks | awk '{print $2}' | grep -qx "$PULSE_SINK_NAME" || \
  pactl load-module module-null-sink sink_name="$PULSE_SINK_NAME" >/dev/null
# libpulse routes this seat's game to its own sink; no global default needed.
export PULSE_SINK="$PULSE_SINK_NAME"

if [[ "$NATIVE_RELAY" == 1 ]]; then
  relay_args=(--capture "$CAPTURE" \
    --display "$DISPLAY_NUMBER" --session-command "$SESSION_COMMAND" \
    --audio-device "$PULSE_SINK_NAME.monitor" --game-control "$GAME_CONTROL" \
    --port "$RELAY_PORT" \
    --ice-min "$ICE_MIN" --ice-max "$ICE_MAX")
  if [[ "$PERSISTENT_SESSION" == 1 ]]; then
    relay_args+=(--persistent-session --switch-command "$SWITCH_COMMAND" \
      --warm-replay "$WARM_REPLAY" --warm-profile "$WARM_PROFILE")
  fi
  "$LAB_ROOT/w3cs-webrtc-relay" "${relay_args[@]}" \
    >"$BRIDGE_LOG" 2>&1 &
else
  python3 "$LAB_ROOT/lab_live_bridge.py" --capture "$CAPTURE" \
    --display "$DISPLAY_NUMBER" --session-command "$SESSION_COMMAND" \
    >"$BRIDGE_LOG" 2>&1 &
fi
bridge_pid=$!

for _ in $(seq 1 40); do
  if grep -q 'listening' "$BRIDGE_LOG" 2>/dev/null; then
    break
  fi
  sleep .25
done

wine reg add 'HKCU\Software\Blizzard Entertainment\Warcraft III\Video' \
  /v reswidth /t REG_DWORD /d "$SOURCE_WIDTH" /f >/dev/null 2>&1 || true
wine reg add 'HKCU\Software\Blizzard Entertainment\Warcraft III\Video' \
  /v resheight /t REG_DWORD /d "$SOURCE_HEIGHT" /f >/dev/null 2>&1 || true

wait "$bridge_pid"
