#!/usr/bin/env bash

# System power profile, via the PowerProfiles D-Bus API.
#
# GNOME's Power panel offers Balanced / Performance / Power Saver; this is the
# same daemon behind it. On Fedora 44 the implementation is tuned-ppd rather
# than power-profiles-daemon, but it serves the same net.hadess.PowerProfiles
# interface, which is why this talks to the interface rather than to either
# binary -- powerprofilesctl is not even installed here.
#
# Setting a profile needs no privileges: the daemon accepts a property write
# from the active session user.
#
# Usage:
#   panama-power-profile list        -> {"profiles":[...],"active":"...","degraded":"..."}
#   panama-power-profile set <name>
#
# PerformanceDegraded is reported because it is the one thing that makes the
# choice a lie: a thermally throttled laptop reports "performance" while
# behaving otherwise, and GNOME surfaces exactly this. It is an empty string
# when nothing is wrong.

set -uo pipefail

readonly BUS_NAME=net.hadess.PowerProfiles
readonly OBJECT=/net/hadess/PowerProfiles

emit_error() {
    printf '{"profiles":[],"active":"","degraded":"","error":%s}\n' "$(jq -Rn --arg e "$1" '$e')"
    exit 0
}

command -v busctl >/dev/null 2>&1 || emit_error 'busctl is not available'

property() {
    busctl get-property "$BUS_NAME" "$OBJECT" "$BUS_NAME" "$1" 2>/dev/null
}

cmd_list() {
    # A machine with no power-profiles daemon is a normal state -- plenty of
    # desktops have none -- so it is reported rather than treated as a failure.
    busctl status "$BUS_NAME" >/dev/null 2>&1 \
        || emit_error 'No power profile service is running. GNOME uses power-profiles-daemon; Fedora ships tuned-ppd.'

    local active degraded profiles
    active="$(property ActiveProfile | sed 's/^s //; s/"//g')"
    degraded="$(property PerformanceDegraded | sed 's/^s //; s/"//g')"

    # Profiles is an array of dicts, which busctl renders flat:
    #   v aa{sv} 3 2 "Profile" s "power-saver" "Driver" s "tuned" 2 "Profile" ...
    # so each profile is the string following its own "Profile" marker. Matching
    # the marker matters: "Driver" values sit in the same stream, and on this
    # machine the driver is called "tuned", which a looser pattern happily
    # reports as a fourth profile that does not exist.
    profiles="$(property Profiles \
        | grep -oE '"Profile" s "[a-z-]+"' \
        | sed 's/.*s "//; s/"$//' \
        | awk '!seen[$0]++')"

    [[ -n "$profiles" ]] || emit_error 'The power profile service reported no profiles.'

    jq -cn \
        --arg active "$active" \
        --arg degraded "$degraded" \
        --argjson profiles "$(printf '%s\n' "$profiles" | jq -Rn '[inputs | select(length > 0)]')" \
        '{profiles: $profiles, active: $active, degraded: $degraded, error: ""}'
}

cmd_set() {
    local profile="${1:-}" status
    # Constrained rather than passed through: this reaches a system service.
    [[ "$profile" =~ ^[a-z-]+$ ]] || {
        printf 'panama-power-profile: refusing a profile name with unexpected characters\n' >&2
        return 2
    }
    # pipefail is set above, so $? here is busctl's real exit status, not
    # head's -- a failed write (daemon stopped, profile rejected) must be
    # reported rather than always claimed as a success.
    busctl set-property "$BUS_NAME" "$OBJECT" "$BUS_NAME" ActiveProfile s "$profile" 2>&1 >/dev/null \
        | head -2 >&2
    status=$?
    return "$status"
}

case "${1:-list}" in
    list) cmd_list ;;
    set)  shift; cmd_set "${1:-}" ;;
    *)    printf 'usage: panama-power-profile [list|set <profile>]\n' >&2; exit 2 ;;
esac
