#!/usr/bin/env bash
# scripts/install/client.sh - install and setup all client related apps and environments
set -euo pipefail

ORIG_USER=${SUDO_USER:-$(id -un)}
REF=${LESAVKA_REF:-master}
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
SCRIPT_REPO_ROOT=$(cd -- "$SCRIPT_DIR/../.." && pwd)
DEFAULT_REPO_URL=ssh://git@scm.bstein.dev:2242/bstein/lesavka.git
REPO_URL=${LESAVKA_REPO_URL:-}
SRC=/var/src/lesavka
export TMPDIR=${TMPDIR:-/var/tmp}
USER_HOME=$(getent passwd "$ORIG_USER" | cut -d: -f6)

log() {
  printf '==> %s\n' "$*"
}

installed_kernel_module_trees() {
  local roots=(/usr/lib/modules /lib/modules)
  local seen=()
  local root entry
  for root in "${roots[@]}"; do
    [[ -d $root ]] || continue
    for entry in "$root"/*; do
      [[ -d $entry ]] || continue
      seen+=("$(basename "$entry")")
    done
  done
  if [[ ${#seen[@]} -eq 0 ]]; then
    return 0
  fi
  printf '%s\n' "${seen[@]}" | awk '!seen[$0]++'
}

require_command() {
  local cmd=$1
  local pkg_hint=$2
  if command -v "$cmd" >/dev/null 2>&1; then
    return 0
  fi
  echo "❌ required command '$cmd' is unavailable after install (expected via $pkg_hint)" >&2
  exit 1
}

require_linkable() {
  local path=$1
  local label=$2
  if ldd "$path" 2>/dev/null | grep -q 'not found'; then
    echo "❌ $label is present but has unresolved shared-library dependencies:" >&2
    ldd "$path" 2>/dev/null | grep 'not found' >&2 || true
    exit 1
  fi
}

require_gst_element() {
  local element=$1
  if gst-inspect-1.0 "$element" >/dev/null 2>&1; then
    return 0
  fi
  echo "❌ required GStreamer element '$element' is unavailable after install." >&2
  exit 1
}

require_kernel_module() {
  local module=$1
  local why=$2
  if modinfo "$module" >/dev/null 2>&1; then
    return 0
  fi
  local running_kernel
  running_kernel=$(uname -r)
  mapfile -t module_trees < <(installed_kernel_module_trees)
  echo "❌ required kernel module '$module' is unavailable for the running kernel $(uname -r)." >&2
  echo "   Lesavka needs it for $why." >&2
  if [[ ${#module_trees[@]} -eq 0 ]]; then
    echo "   No kernel module trees are currently installed under /usr/lib/modules or /lib/modules." >&2
  else
    echo "   Installed kernel module trees: ${module_trees[*]}" >&2
    if [[ ! " ${module_trees[*]} " =~ [[:space:]]${running_kernel}[[:space:]] ]]; then
      echo "   The machine is booted into an older kernel than the modules that are currently installed." >&2
      echo "   Reboot into one of the installed kernels above, then rerun the installer." >&2
    else
      echo "   The current kernel tree exists, but modinfo still cannot resolve '$module'." >&2
      echo "   Verify the kernel package and headers are healthy, then rerun the installer." >&2
    fi
  fi
  exit 1
}

run_as_user() {
  sudo -u "$ORIG_USER" env HOME="$USER_HOME" SSH_AUTH_SOCK="${SSH_AUTH_SOCK:-}" "$@"
}

mkdir -p "$TMPDIR"

if [[ -z $REPO_URL ]] && [[ -d $SCRIPT_REPO_ROOT/.git ]]; then
  REPO_URL=$(git -C "$SCRIPT_REPO_ROOT" config --get remote.origin.url || true)
fi
REPO_URL=${REPO_URL:-$DEFAULT_REPO_URL}

log "1. Installing base packages"
sudo pacman -Sq --needed --noconfirm \
  git rustup protobuf abseil-cpp gcc clang llvm-libs compiler-rt evtest base-devel libpulse \
  pipewire pipewire-pulse wireplumber alsa-utils gst-plugin-pipewire \
  gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav \
  wmctrl qt6-tools wl-clipboard xclip xsel desktop-file-utils

ensure_yay() {
  if command -v yay >/dev/null 2>&1; then
    if run_as_user yay --version >/dev/null 2>&1; then
      return
    fi
  fi
  run_as_user env TMPDIR="$TMPDIR" bash -c 'rm -rf "$TMPDIR/yay" &&
    cd "$TMPDIR" && git clone --depth 1 https://aur.archlinux.org/yay.git &&
    cd yay && makepkg -si --noconfirm'
}

log "1b. Installing grpcurl"
if sudo pacman -Si grpcurl >/dev/null 2>&1; then
  sudo pacman -Sq --needed --noconfirm grpcurl
else
  ensure_yay
  if ! run_as_user yay -S --needed --noconfirm grpcurl-bin; then
    log "grpcurl AUR install failed once, rebuilding yay and retrying"
    ensure_yay
    run_as_user yay -S --needed --noconfirm grpcurl-bin
  fi
fi

# 1c. input access
log "1c. Ensuring input group access for $ORIG_USER"
sudo usermod -aG input "$ORIG_USER"

log "1d. Verifying runtime tools"
require_command pactl "libpulse"
require_command gst-inspect-1.0 "gstreamer"
require_command arecord "alsa-utils"
require_command speaker-test "alsa-utils"
require_command wmctrl "wmctrl"
require_command qdbus6 "qt6-tools"
require_command protoc "protobuf"
if ! command -v wl-paste >/dev/null 2>&1 \
  && ! command -v xclip >/dev/null 2>&1 \
  && ! command -v xsel >/dev/null 2>&1; then
  echo "❌ no clipboard reader found after install (expected one of wl-clipboard/xclip/xsel)" >&2
  exit 1
fi
require_linkable "$(command -v protoc)" "protoc"
if [[ -e /usr/lib/libclang.so ]]; then
  require_linkable /usr/lib/libclang.so "libclang"
fi
require_kernel_module snd_usb_audio "USB microphones and USB headsets"
require_gst_element pulsesrc
require_gst_element pulsesink
require_gst_element pipewiresrc
protoc --version >/dev/null
if ! run_as_user pactl info >/dev/null 2>&1; then
  echo "⚠️  pactl is installed, but no PulseAudio/PipeWire Pulse server is reachable right now."
  echo "    Lesavka will still install, but local speaker/mic staging may stay empty until the host audio session is up."
fi

# 2. Rust tool-chain for both root & user
log "2. Ensuring Rust toolchain"
sudo rustup default stable
run_as_user rustup default stable

# 3. clone / update into a canonical workspace checkout
log "3. Syncing source checkout for ref ${REF}"
if [[ ! -d /var/src ]]; then
  sudo mkdir -p /var/src
fi
sudo chown "$ORIG_USER":"$ORIG_USER" /var/src
if [[ -d $SRC/.git ]]; then
  run_as_user git -C "$SRC" fetch --all --tags --prune
else
  run_as_user git clone "$REPO_URL" "$SRC"
fi
if run_as_user git -C "$SRC" rev-parse --verify --quiet "origin/$REF" >/dev/null; then
  run_as_user git -C "$SRC" checkout -B "$REF" "origin/$REF"
else
  run_as_user git -C "$SRC" checkout --force "$REF"
fi

# 4. build
log "4. Building client release binary"
run_as_user env TMPDIR="$TMPDIR" bash -c "cd '$SRC/client' && cargo clean && cargo build --release"

# 5. install binary
log "5. Installing launchable client binaries"
sudo install -Dm755 "$SRC/target/release/lesavka-client" /usr/local/bin/lesavka-client
sudo ln -sf /usr/local/bin/lesavka-client /usr/local/bin/lesavka

log "6. Registering desktop application"
sudo install -Dm644 "$SRC/client/assets/icons/hicolor/1024x1024/apps/lesavka.png" \
  /usr/share/icons/hicolor/1024x1024/apps/lesavka.png
sudo install -Dm644 "$SRC/client/assets/icons/hicolor/1024x1024/apps/lesavka.png" \
  /usr/share/pixmaps/lesavka.png
sudo install -Dm644 "$SRC/client/assets/linux/lesavka.desktop" \
  /usr/share/applications/lesavka.desktop
if command -v update-desktop-database >/dev/null 2>&1; then
  sudo update-desktop-database /usr/share/applications
fi
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
  sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true
fi

log "7. Removing legacy auto-start service"
sudo systemctl disable --now lesavka-client.service >/dev/null 2>&1 || true
sudo rm -f /etc/systemd/system/lesavka-client.service
sudo systemctl daemon-reload

echo
echo "✅ lesavka-client install complete"
echo "   Binary: /usr/local/bin/lesavka-client"
echo "   Launch alias: /usr/local/bin/lesavka"
echo "   Desktop entry: /usr/share/applications/lesavka.desktop"
echo "   Build source: $SRC/target/release/lesavka-client"
echo
echo "Quick start:"
echo "  KDE menu: search for Lesavka"
echo "  Terminal: /usr/local/bin/lesavka"
