#!/usr/bin/env bash
# Battery state from sysfs; refreshes on power_supply udev events and every
# 30 s.  Emits a `state` (charging / discharging / low / full / idle) that the
# CSS maps to a colour, instead of hard-coding one here.

bat=""
for d in /sys/class/power_supply/*; do
  [[ -r $d/type && $(<"$d/type") == Battery ]] && { bat=$d; break; }
done
if [[ -z $bat ]]; then
  echo '{"visible":false,"percentage":0,"wattage":"","status":"","state":"none"}'
  exit 0
fi

attr() { # first readable, non-empty attribute of the list, else 0
  local a v
  for a in "$@"; do
    v=$(cat "$bat/$a" 2>/dev/null) && [[ -n $v ]] && { echo "$v"; return; }
  done
  echo 0
}

hours_to_clock() { awk -v h="$1" 'BEGIN { printf "%d:%02d", int(h), int((h - int(h)) * 60 + 0.5) }'; }

state() {
  local cap status rate now full power time="" wattage state
  cap=$(attr capacity)
  status=$(attr status)
  rate=$(attr power_now current_now) # µW or µA
  now=$(attr energy_now charge_now)  # µWh or µAh — same unit as rate, so now/rate = hours
  full=$(attr energy_full charge_full)
  if [[ -r $bat/power_now ]]; then power=$rate; else power=$((rate * $(attr voltage_now) / 1000000)); fi
  wattage=$(awk -v p="$power" 'BEGIN { printf "%.1f W", p / 1000000 }')
  if ((rate > 0)); then
    case $status in
      Discharging) time=$(hours_to_clock "$(awk -v n="$now" -v r="$rate" 'BEGIN { print n / r }')") ;;
      Charging) time=$(hours_to_clock "$(awk -v n="$now" -v f="$full" -v r="$rate" 'BEGIN { print (f - n) / r }')") ;;
    esac
  fi
  case $status in
    Charging)
      state=charging
      status="Charging${time:+, $time left}"
      ;;
    Discharging)
      state=discharging
      ((cap <= 20)) && state=low
      status=${time:+$time left}
      ;;
    Full)
      state=full
      status="Fully charged"
      ;;
    *) state=idle ;;
  esac
  printf '{"visible":true,"percentage":%s,"wattage":"%s","status":"%s","state":"%s"}' \
    "$cap" "$wattage" "$(jstr "$status")" "$state"
}

refresh() { emit "$(state)"; }
_ps_events() { exec udevadm monitor --udev --subsystem-match=power_supply; }

refresh
mux_init
mux_add _ps_events
mux_tick 30
mux_loop refresh
