#!/usr/bin/env bash
# install-ibus-rime.sh — Install IBus + Rime and add it
# to GNOME's Input Sources. Tuned for Ubuntu 26.04 (GNOME 50 / Wayland) but
# works on any modern Ubuntu/Debian GNOME desktop.
#
# Hardened: distro-detect, runs as the desktop user (not root) for gsettings,
# uses sudo only for apt steps, idempotent re-runs, ERR trap, --dry-run.

set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT_NAME="${0##*/}"
DRY_RUN=0
SKIP_GSETTINGS=0

usage() {
  cat <<EOF
Usage: $SCRIPT_NAME [--dry-run] [--skip-gsettings] [--help]

Purges old ibus-libpinyin, installs ibus-rime (plus Chinese language packs), 
configures Rime to default to Simplified Pinyin, and registers 'Rime' 
as a GNOME input source. Idempotent.

Do NOT run with sudo: gsettings is per-user and must run as the desktop user.
The script invokes sudo internally only for apt-get steps.

Options:
  --skip-gsettings  Install packages but don't touch GNOME input sources
                    (useful on non-GNOME desktops; configure manually afterwards).
  --dry-run         Print actions without executing.
  --help, -h        Show this help.

Switch input methods at runtime with: Super + Space
EOF
}

log()  { printf '\033[1;34m[%s]\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*"; }
warn() { printf '\033[1;33m[%s] WARN:\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*" >&2; }
die()  { printf '\033[1;31m[%s] ERROR:\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*" >&2; exit 1; }
run()  { if (( DRY_RUN )); then printf '  DRY-RUN: %s\n' "$*"; else eval "$@"; fi; }
trap 'rc=$?; (( rc )) && printf "\033[1;31m[%s] failed at line %s (exit %d)\033[0m\n" "${SCRIPT_NAME%.sh}" "$LINENO" "$rc" >&2' ERR

while (( $# )); do
  case "$1" in
    --dry-run)         DRY_RUN=1 ;;
    --skip-gsettings)  SKIP_GSETTINGS=1 ;;
    -h|--help)         usage; exit 0 ;;
    *) die "Unknown argument: $1 (try --help)" ;;
  esac
  shift
done

# Resolve the desktop user. If invoked via sudo, gsettings must target SUDO_USER.
if (( EUID == 0 )); then
  DESKTOP_USER="${SUDO_USER:-}"
  [[ -n "$DESKTOP_USER" && "$DESKTOP_USER" != "root" ]] \
    || die "Run as a normal user (the script will call sudo itself for apt). gsettings can't run as root."
else
  DESKTOP_USER="$USER"
fi

# Look up the user's UID and Home Directory for configs and DBus.
USER_ENTRY="$(getent passwd "$DESKTOP_USER")" || die "User '$DESKTOP_USER' not found in passwd."
USER_ID="$(awk -F: '{print $3}' <<<"$USER_ENTRY")"
USER_HOME="$(awk -F: '{print $6}' <<<"$USER_ENTRY")"

[[ -r /etc/os-release ]] || die "/etc/os-release not found."
# shellcheck disable=SC1091
. /etc/os-release
case "${ID:-}:${ID_LIKE:-}" in
  *ubuntu*|*debian*) : ;;
  *) die "Unsupported distro: ${PRETTY_NAME:-unknown}. Requires Debian/Ubuntu." ;;
esac
log "Detected: ${PRETTY_NAME:-unknown}, desktop user: $DESKTOP_USER"

# Helper: invoke a command as $DESKTOP_USER with a working DBus address.
run_as_user() {
  local cmd=("$@")
  if (( DRY_RUN )); then
    printf '  DRY-RUN (as %s): %s\n' "$DESKTOP_USER" "${cmd[*]}"
    return 0
  fi
  if (( EUID == 0 )); then
    sudo -u "$DESKTOP_USER" \
      DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$USER_ID/bus" \
      XDG_RUNTIME_DIR="/run/user/$USER_ID" \
      "${cmd[@]}"
  else
    "${cmd[@]}"
  fi
}

# Helper: invoke a command with sudo when the caller is non-root.
sudo_run() {
  if (( DRY_RUN )); then
    printf '  DRY-RUN (sudo): %s\n' "$*"
    return 0
  fi
  if (( EUID == 0 )); then "$@"; else sudo "$@"; fi
}

export DEBIAN_FRONTEND=noninteractive

log "Removing old ibus-libpinyin if present..."
sudo_run apt-get remove --purge -y ibus-libpinyin || true

log "Installing IBus Rime + Chinese language packs..."
sudo_run apt-get update -qq
sudo_run apt-get install -y \
  ibus \
  ibus-rime \
  language-pack-zh-hans \
  language-pack-gnome-zh-hans

log "Configuring Rime to permanently default to Simplified Pinyin..."
RIME_DIR="$USER_HOME/.config/ibus/rime"
if (( DRY_RUN )); then
  printf '  DRY-RUN (as %s): Create %s/default.custom.yaml\n' "$DESKTOP_USER" "$RIME_DIR"
else
  if (( EUID == 0 )); then
    sudo -u "$DESKTOP_USER" mkdir -p "$RIME_DIR"
    sudo -u "$DESKTOP_USER" tee "$RIME_DIR/default.custom.yaml" > /dev/null <<'EOF'
patch:
  schema_list:
    - schema: luna_pinyin_simp
EOF
  else
    mkdir -p "$RIME_DIR"
    tee "$RIME_DIR/default.custom.yaml" > /dev/null <<'EOF'
patch:
  schema_list:
    - schema: luna_pinyin_simp
EOF
  fi
fi

# Make sure ibus-daemon picks up the new engines and config for the user.
if command -v ibus >/dev/null 2>&1; then
  log "Restarting ibus-daemon for $DESKTOP_USER..."
  # `ibus exit` will fail if no daemon is running — treat as non-fatal.
  run_as_user ibus exit >/dev/null 2>&1 || true
  # Start fresh in the background; -drx replaces a running daemon.
  if (( ! DRY_RUN )); then
    sudo -u "$DESKTOP_USER" \
      DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$USER_ID/bus" \
      XDG_RUNTIME_DIR="/run/user/$USER_ID" \
      sh -c 'nohup ibus-daemon -drx >/dev/null 2>&1 &' || \
      warn "ibus-daemon restart returned non-zero (non-fatal)."
    sleep 1
  fi
fi

if (( SKIP_GSETTINGS )); then
  log "Skipping GNOME input-sources update (--skip-gsettings)."
  log "Done. Add 'Chinese (Rime)' manually under Settings → Keyboard → Input Sources."
  exit 0
fi

# Only manage gsettings if GNOME schemas are present.
if ! run_as_user gsettings list-schemas 2>/dev/null | grep -q '^org.gnome.desktop.input-sources$'; then
  warn "GNOME schema org.gnome.desktop.input-sources not found; skipping gsettings update."
  log "Done. Add 'Chinese (Rime)' manually in your DE's input settings."
  exit 0
fi

log "Adding 'Rime' to GNOME Input Sources (idempotent)..."

CURRENT_SOURCES="$(run_as_user gsettings get org.gnome.desktop.input-sources sources 2>/dev/null || echo '[]')"
# Strip the optional "@as " type annotation gvariant sometimes prepends.
CLEAN_SOURCES="${CURRENT_SOURCES#@as }"

if [[ "$CLEAN_SOURCES" == *"'ibus', 'rime'"* ]]; then
  log "Rime already present in input sources — nothing to do."
else
  if [[ "$CLEAN_SOURCES" == *"'ibus', 'libpinyin'"* ]]; then
    # Dynamically replace libpinyin with rime
    NEW_SOURCES="${CLEAN_SOURCES//\'libpinyin\'/\'rime\'}"
  elif [[ -z "$CLEAN_SOURCES" || "$CLEAN_SOURCES" == "[]" || "$CLEAN_SOURCES" == "@as []" ]]; then
    NEW_SOURCES="[('xkb', 'us'), ('ibus', 'rime')]"
  else
    # Insert the rime tuple before the closing bracket of the existing list.
    NEW_SOURCES="${CLEAN_SOURCES%]*}, ('ibus', 'rime')]"
  fi
  run_as_user gsettings set org.gnome.desktop.input-sources sources "$NEW_SOURCES"
  log "Input sources updated to include: ('ibus', 'rime')"
fi

log "---"
log "Done! Rime is installed and configured for Simplified Pinyin."
log "Switch input methods with: Super + Space"
log "If 'Chinese (Rime)' doesn't appear in the top bar right away, log out and back in."