#!/usr/bin/env bash
# ============================================================================
#  UltraWidePatches - installer  (Linux / Proton, also usable on Windows via
#  manual extraction of the release zip)
#
#  Usage:
#     ./install.sh                      # list available games
#     ./install.sh GundamBreaker4       # install that game's patch
#     ./install.sh GundamBreaker4 uninstall
#
#  Overrides:
#     GAME_DIR=/path/to/Binaries/Win64  ./install.sh <Game>   # nonstandard install
#     PREFIX_INI_FILE=/path/to/Engine.ini ./install.sh <Game> # nonstandard prefix
#     LOADER_NAME=version.dll           ./install.sh <Game>   # loader collision
# ============================================================================
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GAMES_DIR="$HERE/games"

list_games() {
  echo "Available patches:"
  for d in "$GAMES_DIR"/*/; do
    [ -f "$d/game.conf" ] || continue
    ( TITLE=""; STATUS=""; . "$d/game.conf" >/dev/null 2>&1 || true
      printf "  %-22s %s\n" "$(basename "$d")" "${TITLE:-} — ${STATUS:-}" )
  done
  echo
  echo "Usage: ./install.sh <GameName> [uninstall]"
}

GAME="${1:-}"
ACTION="${2:-install}"
if [ -z "$GAME" ]; then list_games; exit 0; fi

GAME_CONF="$GAMES_DIR/$GAME/game.conf"
if [ ! -f "$GAME_CONF" ]; then
  echo "[!] Unknown game: $GAME"; echo; list_games; exit 1
fi
# shellcheck disable=SC1090
. "$GAME_CONF"
LOADER="${LOADER_NAME:-${LOADER:-dsound.dll}}"

echo "=== ${TITLE:-$GAME} ==="

# --- locate the game's exe directory across Steam libraries -------------------
find_gamedir() {
  local cand
  for base in \
      "$HOME/.steam/steam" "$HOME/.local/share/Steam" \
      "/media/$USER"/*/steam "/media/$USER"/*/SteamLibrary \
      "$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam"; do
    cand="$base/steamapps/common/$COMMON_SUBDIR"
    [ -f "$cand/$EXE" ] && { echo "$cand"; return 0; }
  done
  cand=$(find /home /media /mnt -maxdepth 8 -name "$EXE" 2>/dev/null | head -1)
  [ -n "$cand" ] && { dirname "$cand"; return 0; }
  return 1
}

GAMEDIR="${GAME_DIR:-$(find_gamedir || true)}"
if [ -z "${GAMEDIR:-}" ] || [ ! -f "$GAMEDIR/$EXE" ]; then
  echo "[!] Could not find $EXE."
  echo "    Set it manually:  GAME_DIR=/path/to/exe/dir ./install.sh $GAME"
  exit 1
fi
echo "[+] Game dir: $GAMEDIR"

# --- locate the Proton prefix ini (optional, per-game) ------------------------
find_prefix_ini() {
  [ -n "${PREFIX_INI_FILE:-}" ] && { [ -f "$PREFIX_INI_FILE" ] && echo "$PREFIX_INI_FILE" && return 0; return 1; }
  [ -z "${PREFIX_INI:-}" ] && return 1
  local cand
  for base in \
      "$HOME/.steam/steam" "$HOME/.local/share/Steam" \
      "/media/$USER"/*/steam "/media/$USER"/*/SteamLibrary \
      "$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam"; do
    cand="$base/steamapps/compatdata/$APPID/pfx/$PREFIX_INI"
    [ -f "$cand" ] && { echo "$cand"; return 0; }
  done
  return 1
}
MARK_BEGIN="; >>> UltraWidePatches ($GAME) >>>"
MARK_END="; <<< UltraWidePatches ($GAME) <<<"

apply_ini() {
  [ -z "${INI_BLOCK:-}" ] && return
  local ini; ini="$(find_prefix_ini || true)"
  [ -z "$ini" ] && { echo "[i] Prefix ini not found (launch the game once first); skipping config tweak."; return; }
  if grep -qF "$MARK_BEGIN" "$ini"; then echo "[i] Config tweak already present."; return; fi
  cp "$ini" "$ini.bak-uwp"
  { echo ""; echo "$MARK_BEGIN"; echo "$INI_BLOCK"; echo "$MARK_END"; } >> "$ini"
  echo "[+] Config tweak applied (backup: $(basename "$ini").bak-uwp)"
}

remove_ini() {
  local ini; ini="$(find_prefix_ini || true)"
  [ -z "$ini" ] && return
  if grep -qF "$MARK_BEGIN" "$ini"; then
    local esc_b esc_e
    esc_b=$(printf '%s' "$MARK_BEGIN" | sed 's/[][\/.*^$]/\\&/g')
    esc_e=$(printf '%s' "$MARK_END"   | sed 's/[][\/.*^$]/\\&/g')
    sed -i "/$esc_b/,/$esc_e/d" "$ini"
    echo "[+] Config tweak removed."
  fi
}

METHOD="${METHOD:-suwsf}"

if [ "$ACTION" = "uninstall" ]; then
  echo "[+] Uninstalling..."
  if [ "$METHOD" = "external" ]; then
    for f in $EXTERNAL_FILES; do [ -f "$GAMEDIR/$f" ] && rm -v "$GAMEDIR/$f"; done
  elif [ "$METHOD" = "bepinex" ]; then
    rm -vf "$GAMEDIR/winhttp.dll" "$GAMEDIR/doorstop_config.ini" "$GAMEDIR/.doorstop_version" \
           "$GAMEDIR/changelog.txt" "$GAMEDIR/BepInEx/plugins/$PLUGIN_DLL"
    # leave BepInEx/ itself: the user may have other mods installed
    echo "[i] Left BepInEx/ in place (other mods may rely on it). Delete it manually if unused."
  else
    for f in SUWSF.asi SUWSF.ini dsound.dll dinput8.dll version.dll winmm.dll; do
      [ -f "$GAMEDIR/$f" ] && rm -v "$GAMEDIR/$f"
    done
  fi
  remove_ini
  echo "[+] Done. No game file was ever modified."
  exit 0
fi

# --- install ------------------------------------------------------------------
if [ "$METHOD" = "external" ]; then
  SRC="$HERE/vendor/$VENDOR_PAYLOAD"
  [ -d "$SRC" ] || { echo "[!] missing vendored payload: $SRC"; exit 1; }
  cp -v "$SRC"/* "$GAMEDIR/" 2>/dev/null || true
  # our tuned config wins over the upstream default
  if [ -n "${EXTERNAL_CONFIG:-}" ] && [ -f "$GAMES_DIR/$GAME/$EXTERNAL_CONFIG" ]; then
    cp -v "$GAMES_DIR/$GAME/$EXTERNAL_CONFIG" "$GAMEDIR/$EXTERNAL_CONFIG"
  fi
elif [ "$METHOD" = "bepinex" ]; then
  BEPZIP=$(ls "$HERE"/vendor/BepInEx_win_x64_*.zip 2>/dev/null | head -1)
  PLUGIN="$GAMES_DIR/$GAME/$PLUGIN_DLL"
  [ -f "$BEPZIP" ] || { echo "[!] missing BepInEx zip in vendor/"; exit 1; }
  [ -f "$PLUGIN" ] || { echo "[!] missing prebuilt plugin: $PLUGIN"; exit 1; }

  if [ -f "$GAMEDIR/winhttp.dll" ]; then
    echo "[i] BepInEx already present; updating plugin only."
  else
    command -v unzip >/dev/null || { echo "[!] unzip required"; exit 1; }
    unzip -o -q "$BEPZIP" -d "$GAMEDIR"
    echo "[+] Installed BepInEx ($(basename "$BEPZIP"))"
  fi
  mkdir -p "$GAMEDIR/BepInEx/plugins"
  cp -v "$PLUGIN" "$GAMEDIR/BepInEx/plugins/"
else
  ASI="$HERE/vendor/SUWSF-x64/SUWSF.asi"
  LOADER_SRC="$HERE/vendor/SUWSF-x64/dsound.dll"   # Ultimate ASI Loader (adapts by filename)
  INI="$GAMES_DIR/$GAME/SUWSF.ini"
  for f in "$ASI" "$LOADER_SRC" "$INI"; do
    [ -f "$f" ] || { echo "[!] missing $f"; exit 1; }
  done

  cp -v "$ASI"        "$GAMEDIR/SUWSF.asi"
  cp -v "$INI"        "$GAMEDIR/SUWSF.ini"
  cp -v "$LOADER_SRC" "$GAMEDIR/$LOADER"
fi
apply_ini

cat <<EOF

[+] Installed ($METHOD): $(case "$METHOD" in
  bepinex)  echo "BepInEx + $PLUGIN_DLL + $LOADER" ;;
  external) echo "$EXTERNAL_FILES" ;;
  *)        echo "SUWSF.asi, SUWSF.ini, $LOADER" ;;
esac)

NEXT (Proton) — REQUIRED, or the loader is ignored and the fix won't apply in gameplay.
  Steam > right-click ${TITLE:-$GAME} > Properties > Launch Options:
      ${LAUNCH_OPTION:-WINEDLLOVERRIDES="${LOADER%.dll}=n,b" %command%}

  Then set the in-game resolution to your native ultrawide res, fullscreen.

Tuning (METHOD=bepinex games):
  Config is generated on first launch at
      <game>/BepInEx/config/*.cfg      (edits apply live, ~2s, no restart)
  Plugin log (proves whether it applied):
      <game>/BepInEx/LogOutput.log

Troubleshooting:
  Different loader name:  LOADER_NAME=version.dll ./install.sh $GAME
  Diagnose injection:     add PROTON_LOG=1 to launch options, then
                          ./tools/read_protonlog.sh $APPID
  Remove everything:      ./install.sh $GAME uninstall
EOF
