#!/usr/bin/env bash
# naga-dpi-cycle.sh [up|down]  — step the Razer Naga V2 HyperSpeed through DPI stages.
#
# Why this exists: in OpenRazer "driver mode" (which we need so the 12 side
# buttons emit unique keycodes) the on-mouse DPI button no longer cycles DPI,
# AND reading the dpi back is unreliable (it returns 0:0). Writing DPI still
# works, though — so we track the current stage in a state file and write the
# new value directly to the openrazer `dpi` sysfs (binary big-endian, 4 bytes).
# Requires membership of the `openrazer` group (no sudo).
#
# The Naga's profile buttons emit F13 (top) / F14 (bottom); bind those here.
set -eu

STAGES=(400 800 1000 1200 1600 3200)
DEFAULT_IDX=3                       # 1200 (stage 4)
dir="${1:-apply}"                   # up | down | apply (apply = just (re)set current stage)
state="${XDG_STATE_HOME:-$HOME/.local/state}/naga-dpi-stage"   # persists across logout/reboot
mkdir -p "${state%/*}"

dpi=$(ls /sys/bus/hid/devices/*1532*00B4*/dpi 2>/dev/null | head -1)
[ -n "${dpi:-}" ] || { command -v notify-send >/dev/null && notify-send -t 1500 "Naga DPI" "device not found"; exit 1; }

last=$(( ${#STAGES[@]} - 1 ))

idx=$(cat "$state" 2>/dev/null || true)
case "${idx:-}" in ''|*[!0-9]*) idx=$DEFAULT_IDX ;; esac
[ "$idx" -le "$last" ] || idx=$DEFAULT_IDX

case "$dir" in
    up)   idx=$(( idx < last ? idx + 1 : last )) ;;
    down) idx=$(( idx > 0    ? idx - 1 : 0 )) ;;
    *)    : ;;                      # apply: leave idx as-is
esac

printf '%s' "$idx" > "$state"

val=${STAGES[idx]}
hi=$(( (val >> 8) & 0xff )); lo=$(( val & 0xff ))
printf "$(printf '\\x%02x\\x%02x\\x%02x\\x%02x' "$hi" "$lo" "$hi" "$lo")" > "$dpi"

command -v notify-send >/dev/null && \
    notify-send -t 1200 -h string:x-canonical-private-synchronous:naga-dpi \
        "Naga DPI" "${val} dpi  (stage $((idx + 1))/${#STAGES[@]})"
