#!/bin/sh
#!/usr/bin/env nix-shell
#!nix-shell -i bash

usage() {
  echo "usage: battery_estimate [options...]"
  echo
  echo "pretty-prints a battery estimate (icon to indicate state, and a duration estimate)"
  echo
  echo "options:"
  echo "  --debug: output additional information, to stderr"
  echo "  --minute-suffix <string>:  use the provided string as a minutes suffix"
  echo "  --hour-suffix <string>:  use the provided string as an hours suffix"
  echo "  --icon-suffix <string>:  use the provided string as an icon suffix"
  echo "  --percent-suffix <string>:  use the provided string when displaying percents"
}

# these icons come from sxmo; they only render in nerdfonts
icon_bat_chg=("󰢟" "󱊤" "󱊥" "󰂅")
icon_bat_dis=("󰂎" "󱊡" "󱊢" "󱊣")
suffix_icon=" "  # thin space
suffix_percent="%"
# suffix_icon=" "

# render time like: 2ʰ08ᵐ
# unicode sub/super-scripts: <https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts>
# symbol_hr="ʰ"
# symbol_min="ᵐ"

# render time like: 2ₕ08ₘ
# symbol_hr="ₕ"
# symbol_min="ₘ"

# render time like: 2h08m
# symbol_hr="h"
# symbol_min="m"

# render time like: 2:08
# symbol_hr=":"
# symbol_min=

# render time like: 2꞉08⧗
symbol_hr="꞉"
symbol_min="⧗"
# variants:
# symbol_hr=":"
# symbol_min="⧖"
# symbol_min="⌛"

# render time like: 2'08"
# symbol_hr="'"
# symbol_min='"'

log() {
  if [ "$BATTERY_ESTIMATE_DEBUG" = "1" ]; then
    printf "$@" >&2
    echo >&2
  fi
}

render_icon() {
  # args:
  # 1: "chg" or "dis"
  # 2: current battery percentage
  level=$(($2 / 25))
  level=$(($level > 3 ? 3 : $level))
  level=$(($level < 0 ? 0 : $level))
  log "icon: %s %d" "$1" "$level"
  if [ "$1" = "dis" ]; then
    printf "%s" "${icon_bat_dis[$level]}"
  elif [ "$1" = "chg" ]; then
    printf "%s" "${icon_bat_chg[$level]}"
  fi
}

try_path() {
  # assigns output variables:
  # - perc, perc_from_full  (0-100)
  # - full, rate (pos means charging)
  if [ -f "$1/capacity" ]; then
    log "perc, perc_from_full from %s" "$1/capacity"
    perc=$(cat "$1/capacity")
    perc_from_full=$((100 - $perc))
  fi

  if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then
    log "full, rate from %s and %s" "$1/charge_full_design" "$1/current_now"
    # current is positive when charging
    full=$(cat "$1/charge_full_design")
    rate=$(cat "$1/current_now")
  elif [ -f "$1/energy_full" ] && [ -f "$1/power_now" ]; then
    log "full, rate from %s and %s" "$1/energy_full" "$1/power_now"
    # power_now is positive when discharging
    full=$(cat "$1/energy_full")
    rate=-$(cat "$1/power_now")
  elif [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then
    log "full, rate from %s and %s" "$1/energy_full" "$1/energy_now"
    log "  this is a compatibility path for legacy Thinkpad batteries which do not populate the 'power_now' field, and incorrectly populate 'energy_now' with power info"
    # energy_now is positive when discharging
    full=$(cat "$1/energy_full")
    rate=-$(cat "$1/energy_now")
  fi
}

try_all_paths() {
  try_path "/sys/class/power_supply/axp20x-battery"  # Pinephone
  try_path "/sys/class/power_supply/BAT0"  # Thinkpad
  log "perc: %d, perc_from_full: %d" "$perc" "$perc_from_full"
  log "full: %f, rate: %f" "$full" "$rate"
  log "  rate > 0 means charging, else discharging"
}

fmt_minutes() {
  # args:
  # 1: icon to render
  # 2: string to show if charge/discharge time is indefinite
  # 3: minutes to stable state (i.e. to full charge or full discharge)
  #    - we work in minutes instead of hours for precision: bash math is integer-only
  log "charge/discharge time: %f min" "$3"
  # args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty>
  if [ -n "$3" ] && [ "$3" -lt 1440 ]; then
    hr=$(($3 / 60))
    hr_in_min=$(($hr * 60))
    min=$(($3 - $hr_in_min))
    printf "%s%s%d%s%02d%s" "$1" "$suffix_icon" "$hr" "$symbol_hr" "$min" "$symbol_min"
  else
    log "charge/discharge duration > 1d"
    printf "%s%s%s" "$1" "$suffix_icon" "$2"  # more than 1d
  fi
}

pretty_output() {
  if [ -n "$perc" ]; then
    duration=""
    if [ "$rate" -gt 0 ]; then
      log "charging"
      icon="$(render_icon chg $perc)"
      duration="$(($full * 60 * $perc_from_full / (100 * $rate)))"
    else
      log "discharging"
      icon="$(render_icon dis $perc)"
      if [ "$rate" -lt 0 ]; then
        duration="$(($full * 60 * $perc / (-100 * $rate)))"
      fi
    fi
    fmt_minutes "$icon" "$perc$suffix_percent" "$duration"
  fi
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    "--debug")
      shift
      BATTERY_ESTIMATE_DEBUG=1
      ;;
    "--icon-suffix")
      shift
      suffix_icon="$1"
      shift
      ;;
    "--hour-suffix")
      shift
      symbol_hr="$1"
      shift
      ;;
    "--minute-suffix")
      shift
      symbol_min="$1"
      shift
      ;;
    "--percent-suffix")
      shift
      suffix_percent="$1"
      shift
      ;;
    *)
      usage
      exit 1
      ;;
  esac
done

try_all_paths
pretty_output
