#!/usr/bin/env bash
set -euo pipefail

readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
readonly SOURCE_FILE="$SCRIPT_DIR/clipboard-screenshot-hotkey.c"
readonly PROGRAM_NAME="clipboard-screenshot-hotkey"
readonly BINARY_FILE="/usr/local/libexec/$PROGRAM_NAME"
readonly SERVICE_NAME="$PROGRAM_NAME.service"
readonly SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME"
readonly SCHEMA="org.cinnamon.desktop.keybindings.media-keys"
readonly CONFIG_DIR="$HOME/.config/$PROGRAM_NAME"
readonly BACKUP_FILE="$CONFIG_DIR/cinnamon-bindings.backup"

readonly -a SCREENSHOT_KEYS=(
  screenshot
  screenshot-clip
  window-screenshot
  window-screenshot-clip
)

usage() {
  cat <<EOF
Usage: $(basename "$0") install|uninstall|status

  install    Build and install the listener, enable its service, and disable
             conflicting Cinnamon screenshot shortcuts.
  uninstall  Remove the listener and restore the previous Cinnamon shortcuts.
  status     Show the service state, resource use, and Cinnamon shortcuts.

Run this script as the Cinnamon desktop user, without sudo. The script invokes
sudo only for system-wide operations.
EOF
}

die() {
  printf 'Error: %s\n' "$*" >&2
  exit 1
}

require_desktop_user() {
  (( EUID != 0 )) || die "do not run this script with sudo; run it as the desktop user"
  [[ -f "$SOURCE_FILE" ]] || die "missing source file: $SOURCE_FILE"
  command -v sudo >/dev/null || die "sudo is required"
  command -v gsettings >/dev/null || die "gsettings is required"
  [[ "$(uname -m)" == "x86_64" ]] || die "this minimal source supports x86-64 only"
}

check_supported_session() {
  local desktop="${XDG_CURRENT_DESKTOP:-}"
  local session="${XDG_SESSION_TYPE:-}"

  [[ "${desktop,,}" == *cinnamon* ]] ||
    die "Cinnamon is required (XDG_CURRENT_DESKTOP is '${desktop:-unset}')"
  [[ "${session,,}" == "x11" ]] ||
    die "an X11 session is required (XDG_SESSION_TYPE is '${session:-unset}'); Wayland is not supported"
  [[ -n "${DISPLAY:-}" ]] ||
    die "DISPLAY is not set; run this installer from a terminal inside Cinnamon"
}

desktop_env() {
  env \
    DISPLAY="${DISPLAY:-:0}" \
    XAUTHORITY="${XAUTHORITY:-$HOME/.Xauthority}" \
    DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/$(id -u)/bus}" \
    "$@"
}

desktop_gsettings() {
  desktop_env gsettings "$@"
}

install_dependencies() {
  local -a packages=()
  command -v cc >/dev/null || packages+=(gcc)
  command -v gnome-screenshot >/dev/null || packages+=(gnome-screenshot)

  if (( ${#packages[@]} )); then
    command -v pacman >/dev/null || die "pacman is required to install: ${packages[*]}"
    printf 'Installing required packages: %s\n' "${packages[*]}"
    sudo pacman -S --needed --noconfirm "${packages[@]}"
  fi
}

escape_sed_replacement() {
  printf '%s' "$1" | sed 's/[&|\\]/\\&/g'
}

backup_cinnamon_bindings() {
  [[ -e "$BACKUP_FILE" ]] && return
  mkdir -p "$CONFIG_DIR"
  : > "$BACKUP_FILE"
  local key
  for key in "${SCREENSHOT_KEYS[@]}"; do
    printf '%s\t%s\n' "$key" "$(desktop_gsettings get "$SCHEMA" "$key")" \
      >> "$BACKUP_FILE"
  done
}

disable_cinnamon_bindings() {
  local key
  for key in "${SCREENSHOT_KEYS[@]}"; do
    desktop_gsettings set "$SCHEMA" "$key" "[]"
  done
}

restore_cinnamon_bindings() {
  local key value
  if [[ -f "$BACKUP_FILE" ]]; then
    while IFS=$'\t' read -r key value; do
      [[ -n "$key" ]] || continue
      desktop_gsettings set "$SCHEMA" "$key" "$value"
    done < "$BACKUP_FILE"
    rm -f "$BACKUP_FILE"
    rmdir "$CONFIG_DIR" 2>/dev/null || true
  else
    for key in "${SCREENSHOT_KEYS[@]}"; do
      desktop_gsettings reset "$SCHEMA" "$key"
    done
  fi
}

install_listener() {
  require_desktop_user
  check_supported_session
  install_dependencies

  local temporary_directory customized_source compiled_binary service_template
  temporary_directory="$(mktemp -d)"
  trap 'rm -rf -- "$temporary_directory"' EXIT
  customized_source="$temporary_directory/$PROGRAM_NAME.c"
  compiled_binary="$temporary_directory/$PROGRAM_NAME"
  service_template="$temporary_directory/$SERVICE_NAME"

  local user_name user_home user_uid display xauthority session_bus
  user_name="$(escape_sed_replacement "$USER")"
  user_home="$(escape_sed_replacement "$HOME")"
  user_uid="$(id -u)"
  display="$(escape_sed_replacement "${DISPLAY:-:0}")"
  xauthority="$(escape_sed_replacement "${XAUTHORITY:-$HOME/.Xauthority}")"
  session_bus="$(escape_sed_replacement "${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/$user_uid/bus}")"

  sed \
    -e "s|\"cachyos\"|\"$user_name\"|g" \
    -e "s|/home/cachyos/.Xauthority|$xauthority|g" \
    -e "s|/home/cachyos|$user_home|g" \
    -e "s|unix:path=/run/user/1000/bus|$session_bus|g" \
    -e "s|DISPLAY=:0|DISPLAY=$display|g" \
    "$SOURCE_FILE" > "$customized_source"

  printf 'Compiling the minimal listener...\n'
  cc -std=c17 -Os \
    -Wall -Wextra -Wpedantic -Werror \
    -ffreestanding -fno-stack-protector -fno-pie \
    -fno-asynchronous-unwind-tables -fno-unwind-tables \
    -nostdlib -static -no-pie \
    -Wl,--build-id=none -Wl,-z,noseparate-code -Wl,-N -s \
    "$customized_source" -o "$compiled_binary"

  cat > "$service_template" <<EOF
[Unit]
Description=Copy Print Screen screenshots to the clipboard despite X11 menu grabs
After=graphical.target

[Service]
Type=simple
ExecStart=$BINARY_FILE
Restart=always
RestartSec=2

[Install]
WantedBy=graphical.target
EOF

  backup_cinnamon_bindings

  sudo install -Dm755 "$compiled_binary" "$BINARY_FILE"
  # Remove an older linked unit before installing the standalone unit file.
  sudo rm -f "$SERVICE_FILE"
  sudo install -Dm644 "$service_template" "$SERVICE_FILE"
  sudo systemctl daemon-reload
  sudo systemctl enable "$SERVICE_NAME"
  sudo systemctl restart "$SERVICE_NAME"
  disable_cinnamon_bindings

  printf '\nInstallation complete.\n'
  printf '  Print Screen: copy the entire screen\n'
  printf '  Alt+Print Screen: copy the active window\n'
  printf '  Service: %s\n' "$(sudo systemctl is-active "$SERVICE_NAME")"
}

uninstall_listener() {
  require_desktop_user

  sudo systemctl disable --now "$SERVICE_NAME" 2>/dev/null || true
  sudo rm -f "$SERVICE_FILE" "$BINARY_FILE"
  sudo systemctl daemon-reload
  restore_cinnamon_bindings

  printf 'Uninstallation complete. Previous Cinnamon shortcuts were restored.\n'
}

show_status() {
  require_desktop_user

  printf '%s\n' '--- Service ---'
  sudo systemctl --no-pager --full status "$SERVICE_NAME" || true

  local pid
  pid="$(sudo systemctl show -p MainPID --value "$SERVICE_NAME" 2>/dev/null || true)"
  if [[ "$pid" =~ ^[1-9][0-9]*$ ]] && [[ -r "/proc/$pid/status" ]]; then
    printf '\n%s\n' '--- Process ---'
    ps -p "$pid" -o pid,state,wchan,%cpu,rss,vsz,cmd
  fi

  printf '\n%s\n' '--- Cinnamon screenshot shortcuts ---'
  local key
  for key in "${SCREENSHOT_KEYS[@]}"; do
    printf '%-26s %s\n' "$key" "$(desktop_gsettings get "$SCHEMA" "$key")"
  done
}

case "${1:-}" in
  install)
    install_listener
    ;;
  uninstall)
    uninstall_listener
    ;;
  status)
    show_status
    ;;
  *)
    usage
    exit 2
    ;;
esac
