#!/bin/bash
set -eu
cdn_list="https://client-update.steamstatic.com https://client-update.akamai.steamstatic.com https://client-update.fastly.steamstatic.com"
beta_channel=steamdeck_publicbeta
stable_channel=steamdeck_stable
steam_root=${XDG_DATA_HOME:-$HOME/.local/share}/Steam
channel_state=$steam_root/package/droiddeck-channel
pinned=1
wanted=${BL_STEAM_CHANNEL:-$(cat "$HOME/.config/droiddeck/steam-channel" 2>/dev/null || true)}
case $wanted in
  stable|"$stable_channel") steam_channel=$stable_channel ;;
  beta|"$beta_channel") steam_channel=$beta_channel ;;
  *)
    pinned=
    steam_channel=$beta_channel
    [ "$(cat "$channel_state" 2>/dev/null)" = "$stable_channel" ] && steam_channel=$stable_channel
    ;;
esac
if [ "${1:-}" = --channel ]; then
  echo "$steam_channel"
  exit 0
fi
manifest=steam_client_${steam_channel}_linuxarm64
stamp=$steam_root/package/droiddeck-installed
legacy_stamp=$steam_root/package/bannerlator-installed
unconfirmed=$steam_root/package/droiddeck-unconfirmed
repair_request=$HOME/.bl-steam-repair
if [ -f "$legacy_stamp" ] && [ ! -f "$stamp" ]; then
  mv -f "$legacy_stamp" "$stamp" || true
fi
repair=""
fallback=""
starts=0
[ -f "$unconfirmed" ] && starts=$(grep -cx start "$unconfirmed" || true)
if [ -e "$repair_request" ]; then
  repair="requested"
elif [ "$starts" -ge 2 ] && ! grep -qx repaired "$unconfirmed"; then
  repair="the client was started $starts times without showing anything"
elif [ "$starts" -ge 2 ] && [ -z "$pinned" ] && [ "$steam_channel" = "$beta_channel" ] && [ "${1:-}" != --sync ]; then
  repair="the repaired $beta_channel client was started $starts more times without showing anything"
  fallback=1
fi
if [ -n "$fallback" ]; then
  echo "== STEP $(date -u +%H:%M:%S) falling back to Valve's $stable_channel Steam client: $repair"
  steam_channel=$stable_channel
  manifest=steam_client_${steam_channel}_linuxarm64
fi
if [ -n "$repair" ]; then
  echo "== STEP $(date -u +%H:%M:%S) repairing the Steam client ($repair)"
  rm -f "$stamp" "$legacy_stamp" "$steam_root/.crash" "$steam_root/steam.pid" \
    "$steam_root"/package/steam_client_*.manifest "$steam_root"/package/steam_client_*.installed
  for part in "$steam_root"/package/*.zip.*; do
    [ -f "$part" ] || continue
    sum=${part##*.}
    sum=${sum%%_*}
    case $sum in
      *[!0-9a-f]*|"") continue ;;
    esac
    [ ${#sum} -eq 40 ] || continue
    [ "$(sha1sum "$part" | cut -d' ' -f1)" = "$sum" ] || rm -f "$part"
  done
fi
sync=
if [ "${1:-}" = --sync ]; then
  case "${2:-}" in publicbeta|steamdeck_publicbeta) sync=$2 ;; *) sync=$steam_channel ;; esac
  manifest=steam_client_${sync}_linuxarm64
fi
[ -z "$sync" ] && [ -x "$steam_root/steamrtarm64/steam" ] && [ -f "$stamp" ] && exit 0

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
fetch_manifest() {
  cdn=""
  for candidate in $cdn_list; do
    if curl -fsSL --connect-timeout 10 --max-time 30 --retry 2 --retry-connrefused --retry-delay 3 \
        "$candidate/$manifest" -o "$work/manifest"; then
      cdn=$candidate
      break
    fi
  done
  [ -n "$cdn" ] || { echo "droiddeck-steam-install: no Steam client CDN answered for $manifest" >&2; exit 1; }
  cdn_order=("$cdn")
  for candidate in $cdn_list; do
    [ "$candidate" = "$cdn" ] || cdn_order+=("$candidate")
  done
  version=$(awk -F'"' '$2 == "version" { print $4; exit }' "$work/manifest")
  awk -F'"' '
    /^\t"/ && NF >= 3 && $4 == "" { block = $2 }
    $2 == "file" { file[block] = $4 }
    $2 == "sha2" { sha[block] = $4 }
    END { for (b in file) if (b ~ /_all$/ || b ~ /_linuxarm64_linuxarm64$/) print b, file[b], sha[b] }
  ' "$work/manifest" | sort > "$work/parts"
  [ -s "$work/parts" ] && return 0
  echo "droiddeck-steam-install: no client components in $manifest; its blocks are:" \
    "$(awk -F'"' '/^\t"/ && NF >= 3 && $4 == "" { printf "%s ", $2 }' "$work/manifest")" >&2
  return 1
}
if ! fetch_manifest; then
  if [ -n "$sync" ] || [ -n "$pinned" ] || [ "$steam_channel" = "$stable_channel" ]; then
    exit 1
  fi
  echo "== STEP $(date -u +%H:%M:%S) falling back to Valve's $stable_channel Steam client: $manifest has no arm64 client"
  steam_channel=$stable_channel
  manifest=steam_client_${steam_channel}_linuxarm64
  fallback=1
  fetch_manifest || exit 1
fi
if [ -n "$sync" ]; then
  installed=$(awk -F'"' '$2 == "version" { print $4; exit }' "$steam_root/package/$manifest.manifest" 2>/dev/null || true)
  if [ -x "$steam_root/steamrtarm64/steam" ] && [ "$installed" = "$version" ]; then
    chmod -R a+x "$steam_root/steamrtarm64" "$steam_root/linuxarm64" 2>/dev/null || true
    exit 0
  fi
  echo "== STEP $(date -u +%H:%M:%S) updating the arm64 Steam client to $version (was ${installed:-none}) for the x86-64 client"
fi
total=$(grep -c . "$work/parts" 2>/dev/null || echo 0)

mkdir -p "$steam_root/package"
while read -r block file sum; do
  i=$((${i:-0} + 1))
  echo "== STEP $(date -u +%H:%M:%S) downloading Steam: $block ($i/$total)"
  fetched=""
  for host in "${cdn_order[@]}"; do
    if curl -fsSL --connect-timeout 10 --speed-limit 1024 --speed-time 60 --max-time 1800 \
        "$host/$file" -o "$work/$file" && echo "$sum  $work/$file" | sha256sum -c --quiet; then
      fetched=$host
      break
    fi
    rm -f "$work/$file"
  done
  [ -n "$fetched" ] || { echo "droiddeck-steam-install: $file failed on every CDN" >&2; exit 1; }
  unzip -qo "$work/$file" -d "$steam_root"
  rm -f "$work/$file"
done < "$work/parts"
find "$steam_root" -depth -name '*\\*' | while read -r odd; do
  fixed=${odd//\\//}
  mkdir -p "$(dirname "$fixed")"
  if [ -d "$odd" ]; then
    cp -a "$odd/." "$fixed/" && rm -rf "$odd"
  else
    mv -f "$odd" "$fixed"
  fi
done
chmod -R a+x "$steam_root/steamrtarm64" "$steam_root/linuxarm64" 2>/dev/null || true
if [ -n "$sync" ]; then
  cp -f "$work/manifest" "$steam_root/package/$manifest.manifest"
else
  echo "$steam_channel" > "$steam_root/package/beta"
fi
ln -sfn "$steam_root/steamrtarm64" "$steam_root/steamrtarm32"
chmod +x "$steam_root/steamrtarm64/steam" 2>/dev/null || true
mkdir -p "$HOME/.steam"
ln -sfn "$steam_root" "$HOME/.steam/root"
ln -sfn "$steam_root" "$HOME/.steam/steam"
ln -sfn "$steam_root/steamrtarm64" "$HOME/.steam/bin64"
# sdk64 is where x86_64 Steamworks looks for steamclient.so; arm64 builds look in sdkarm64.
ln -sfn "$steam_root/linux64" "$HOME/.steam/sdk64"
ln -sfn "$steam_root/linuxarm64" "$HOME/.steam/sdkarm64"
ln -sfn "$steam_root/steamrtarm64" "$HOME/.steam/binarm64"
ln -sfn "$steam_root/linux32" "$HOME/.steam/sdk32"
echo "$version" > "$stamp"
if [ -n "$fallback" ]; then
  echo "$stable_channel" > "$channel_state"
  echo "== STEP $(date -u +%H:%M:%S) the Steam client now follows $stable_channel (beta in ~/.config/droiddeck/steam-channel returns to $beta_channel)"
fi
if [ -n "$repair" ]; then
  echo repaired > "$unconfirmed"
  rm -f "$repair_request"
fi
