#!/usr/bin/env bash
# Bluetooth state — adapter power, connected device and the paired/trusted
# device list — from one ObjectManager call on the system bus.  Refreshes on
# every org.bluez signal (property changes, devices added/removed) and every
# 60 s.

fallback='{"powered":false,"connected":false,"device":"","devices":[]}'

query() {
  busctl --system --json=short call org.bluez / org.freedesktop.DBus.ObjectManager GetManagedObjects 2>/dev/null \
    | jq -c '
      .data[0] as $o
      | ($o | to_entries | map(.value["org.bluez.Adapter1"] | select(.) | .Powered.data) | any) as $powered
      | ($o | to_entries
          | map(.value["org.bluez.Device1"] | select(.))
          | map(select(.Paired.data or .Trusted.data or .Connected.data))
          | map({ mac: .Address.data,
                  name: (.Alias.data // .Name.data // .Address.data),
                  connected: (.Connected.data // false),
                  paired: (.Paired.data // false) })
          | sort_by((.connected | not), (.paired | not), .name)) as $devices
      | { powered: $powered,
          connected: ($devices | any(.connected)),
          device: ($devices | map(select(.connected)) | .[0].name // ""),
          devices: $devices }' 2>/dev/null
}

refresh() {
  local out
  out=$(query)
  emit "${out:-$fallback}"
}

_bt_events() { exec gdbus monitor --system --dest org.bluez; }

refresh
mux_init
mux_add _bt_events
mux_tick 60
mux_loop refresh
