#!/usr/bin/env bash

# Inspired by <https://github.com/cdown/btmenu>

function show_usage() {
    echo "A simple bluetoothctl from bluez-utilies interface for dmenu(1)"
    echo ""
    echo "Usage:"
    echo -e "\tbtmenu [OPTION] [DEVICE]"
    echo -e "\t\tWithout any options, defaults to connecting to device"
    echo "Options:"
    echo -e "\t-h, --help\n\t\tshow this message and quit"
    echo -e "\t-d, --disconnect\n\t\tDisconnect the device"
    exit 0
}

function _bluetoothctl() {
    LC_ALL=C timeout 30 bluetoothctl
}

# Connects by default
mode=connect

# Name -> MAC
declare -A DEVICES
while read -r _ mac name; do
    DEVICES["$name"]=$mac
done < <(echo "devices" | _bluetoothctl | awk '$1 == "Device"')

# Notify the user about the operation
function notify() {
    local msg
    local is_error

    msg=${1?BUG: no message}
    is_error=${2:-0}

    if command -v notify-send >/dev/null 2>&1; then
        notify-send "btmenu" "$msg"  # TODO: escaping
    fi

    if (( is_error )); then
        printf 'ERROR: %s\n' "$msg" >&2
    else
        printf '%s\n' "$msg"
    fi
}

function execute_mode() {
    local mode
    local name
    local mac
    local preposition
    local expected_to_connect
    local retries

    mode=${1?BUG: missing mode}
    retries=15

    case $mode in
        connect)
            preposition=to
            expected_to_connect=yes
        ;;
        disconnect)
            preposition=from
            expected_to_connect=no
        ;;
    esac

    if ! (( ${#DEVICES[@]} )); then
        notify "No devices found. Are they registered with D-Bus?" 1
        return 2
    fi

    name=$(printf '%s\n' "${!DEVICES[@]}" | dmenu -l 10 -p "btmenu" "${dmenu_args[@]}")
    [[ $name ]] || return
    mac=${DEVICES["$name"]}

    notify "Attempting to $mode $preposition $name"

    while (( retries-- )); do
        printf 'power on\n%s %s\n' "$mode" "$mac" | _bluetoothctl
        if printf 'info %s\n' "$mac" |
            _bluetoothctl |
            grep -Pq '^[\t ]+Connected: '"$expected_to_connect"; then
            notify "${mode^}ed $preposition $name"
            return 0
        fi
        sleep 1
    done

    ret="$?"
    notify "Failed to $mode $preposition $name" 1
    return "$ret"
}

i=2

# FIXME: I want to have a list of devices with their connection status instead
# of having to launch the script with the correct argument to connect/disconnect
for arg do
    if [[ $arg == -- ]]; then
        dmenu_args=( "${@:$i}" )
        break
    fi

    case "$arg" in
        -d|--disconnect) mode=disconnect ;;
        -h|--help) show_usage ;;
    esac

    (( i++ ))
done

execute_mode "$mode"