#!/usr/bin/env bash
#
# NerdZap: install Steam on a Chromebook (Linux development environment)
# Guide:   https://nerdzap.com/guides/steam-on-chromebook/
# Version: 1.2
#
# What this script does, in order:
#   1. Checks you are on an Intel/AMD (x86_64) Chromebook with Linux set up
#   2. Checks the GPU flag was on when Linux was set up (looks for /dev/dri)
#   3. Turns on 32-bit support, installs Valve's official Steam package, and
#      installs Steam's extra libraries up front (so Steam's first launch
#      doesn't ask for a Linux password, which Chromebook Linux doesn't set)
#   4. Adds your account to the "render" group so Linux can use the GPU
#   5. Asks you to shut Linux down, then run the same command again
#   6. On the second run: checks the GPU works and starts Steam
#
# It is safe to run more than once. It never touches ChromeOS itself.
# Read it before you run it: it is plain text and short.
#
# MIT License
# Copyright (c) 2026 NerdZap
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# Everything runs inside main(), called on the last line. When this script is
# piped into bash, bash has to read the whole file before anything runs, so a
# download that gets cut off part-way can never run half a script.

set -u

GUIDE_URL="https://nerdzap.com/guides/steam-on-chromebook/"
STEAM_DEB_URL="https://repo.steampowered.com/steam/archive/stable/steam_latest.deb"

# --- COLOURS ---
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m'

say()  { printf '\n%b==> %s%b\n' "$BOLD" "$*" "$NC"; }
note() { printf '    %s\n' "$*"; }
warn() { printf '\n%b%s%b\n' "$YELLOW" "$*" "$NC"; }
die()  { printf '\n%bStopped:%b %s\n    Guide: %s\n\n' "$RED" "$NC" "$*" "$GUIDE_URL" >&2; exit 1; }

# Prompts must read from the keyboard even when the script is piped into bash.
ask_yes_no() {
  local reply
  printf '    %s [y/N] ' "$1"
  read -r reply < /dev/tty || return 1
  [[ "$reply" =~ ^[Yy] ]]
}

# Stop politely when someone answers "no" to a prompt.
stop_by_choice() {
  printf '\n    OK, stopping here. Nothing else was changed.\n'
  note "When you've fixed it, run the same command again. Guide: $GUIDE_URL"
  printf '\n'
  exit 1
}

# True only if the package is fully installed (not just leftover config files).
pkg_installed() {
  dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q "install ok installed"
}

main() {
  local user arch gpu_node deb renderer n

  user="${USER:-$(id -un)}"

  # 1. Sanity checks ---------------------------------------------------------
  [ "$(id -u)" -ne 0 ] || die "Run this as your normal Linux user, not root (no sudo in front)."
  command -v apt >/dev/null 2>&1 || die "This needs a Debian-based Linux (the Chromebook default). apt was not found."
  command -v sudo >/dev/null 2>&1 || die "sudo was not found."
  { : < /dev/tty; } 2>/dev/null || die "No keyboard (tty) available. Open the Terminal app and run it there."

  arch="$(uname -m)"
  if [ "$arch" != "x86_64" ]; then
    die "Your Chromebook reports '$arch'. Valve's Steam package only supports x86_64 (Intel/AMD), so Steam can't be installed this way."
  fi

  say "NerdZap Steam setup for Chromebook"
  note "Running as: $user"

  # 2. GPU device check --------------------------------------------------------
  gpu_node=""
  for n in /dev/dri/renderD*; do
    if [ -e "$n" ]; then gpu_node="$n"; break; fi
  done

  if [ -z "$gpu_node" ]; then
    warn "No GPU device found in Linux."
    note "The flag chrome://flags/#crostini-gpu-support must be Enabled, and ChromeOS restarted,"
    note "BEFORE Linux is set up. Without it, games run on the CPU and crawl."
    note "If the flag isn't listed at all, your ChromeOS version may not offer it."
    note "Fix: turn the flag on, restart, remove Linux (Settings > About ChromeOS > Developers),"
    note "set it up again, then run this command again."
    ask_yes_no "Carry on anyway (Steam will work, but games will be very slow)?" || stop_by_choice
  fi

  # 3. 32-bit support and Steam ------------------------------------------------
  if pkg_installed steam-launcher; then
    say "Steam is already installed, skipping download"
  else
    say "Adding 32-bit support"
    sudo dpkg --add-architecture i386 || die "Could not add 32-bit support."
    sudo apt update || die "apt update failed. Check your internet connection and try again."

    say "Installing curl"
    sudo apt install -y curl || die "Could not install curl."

    say "Downloading Valve's official Steam package"
    deb="$(mktemp --suffix=.deb)" || die "Could not create a temporary file."
    # shellcheck disable=SC2064  # expand $deb now, on purpose
    trap "rm -f '$deb'" EXIT
    chmod 644 "$deb"
    curl -fsSL --retry 3 -o "$deb" "$STEAM_DEB_URL" \
      || die "Could not download Steam from repo.steampowered.com. Check your internet connection and try again."

    say "Installing Steam (this takes a minute or two)"
    sudo apt install -y "$deb" || die "Steam failed to install."
  fi

  # Steam's package adds Valve's own software source. Refresh, then install the
  # libraries Steam would otherwise try to install on first launch. Doing it here
  # means no password prompt and no "install extra packages" window.
  if pkg_installed steam-libs-amd64 && pkg_installed steam-libs-i386:i386; then
    note "Steam's extra libraries are already installed."
  else
    say "Installing Steam's extra libraries"
    sudo apt update || die "apt update failed. Check your internet connection and try again."
    sudo apt install -y steam-libs-amd64 steam-libs-i386 || die "Could not install Steam's extra libraries."
  fi

  # 4. GPU access: the render group --------------------------------------------
  # Skipped when there is no GPU device: the group would do nothing.
  if [ -n "$gpu_node" ]; then
    say "Checking GPU access"
    # id -nG NAME = the account's groups on disk.
    if ! id -nG "$user" | tr ' ' '\n' | grep -qx render; then
      sudo usermod -aG render "$user" || die "Could not add you to the render group."
      note "Added you to the render group."
    fi

    # id -nG with no name = the groups this Terminal session actually has.
    if ! id -nG | tr ' ' '\n' | grep -qx render; then
      warn "One more thing: shut Linux down completely."
      note "1. Right-click the Terminal icon on your shelf (bottom of the screen)."
      note "2. Choose \"Shut down Linux\"."
      note "3. Open Terminal again: select the circle Launcher button at the bottom left of the"
      note "   screen, type Terminal and press Enter."
      note "4. Run the same command again (press the Up arrow key to bring it back, or paste it again)."
      note "Closing the Terminal window is not enough."
      printf '\n'
      exit 0
    fi
    note "Your account can use the GPU."
  fi

  # 5. Check the GPU is actually being used ------------------------------------
  say "Checking the GPU is working"
  if ! command -v glxinfo >/dev/null 2>&1; then
    note "Installing a small graphics tool (mesa-utils) to check..."
    sudo apt install -y mesa-utils >/dev/null 2>&1 || note "(Could not install mesa-utils, skipping the check.)"
  fi
  if command -v glxinfo >/dev/null 2>&1; then
    renderer="$(glxinfo -B 2>/dev/null | grep -i 'OpenGL renderer' | sed 's/^[^:]*: *//')"
    note "OpenGL renderer: ${renderer:-unknown}"
    if printf '%s' "$renderer" | grep -qi llvmpipe; then
      warn "Linux is still using the CPU (llvmpipe), not the GPU."
      note "If you haven't yet, shut Linux down completely and run this again."
      note "If you have, the GPU flag probably wasn't on when Linux was set up (see the guide)."
      ask_yes_no "Carry on anyway?" || stop_by_choice
    elif printf '%s' "$renderer" | grep -qi virgl; then
      printf '    %bGPU is working.%b\n' "$GREEN" "$NC"
    fi
  fi

  # 6. Start Steam -------------------------------------------------------------
  say "Starting Steam"
  note "The first time, Steam downloads about 470MB of updates before it shows the sign-in screen."
  nohup steam >/dev/null 2>&1 &
  disown 2>/dev/null || true

  printf '\n%bDone.%b Steam is starting.\n' "$GREEN" "$NC"
  note "If a game won't run, see \"Fix Games That Won't Run\" in the guide:"
  note "$GUIDE_URL"
  printf '\n'
}

main "$@"
