#!/usr/bin/env bash
# Monitors D-Bus for org.freedesktop.Notifications.Notify method calls.
# For each notification, captures the sender process PID and outputs:
#   <notification-id>:<sender-pid>
# Quickshell reads this to know which process originated each notification,
# allowing it to walk the /proc tree and focus the exact window that sent it.

get_pid() {
    busctl call org.freedesktop.DBus /org/freedesktop/DBus \
        org.freedesktop.DBus GetConnectionUnixProcessID s "$1" 2>/dev/null \
        | awk '{print $2}'
}

# Maps serial → pid so concurrent notifications don't clobber each other.
declare -A pending_pids

awaiting_nid=false
pending_pid=""

dbus-monitor --session "dest='org.freedesktop.Notifications'" 2>/dev/null | \
while IFS= read -r line; do
    line="${line#"${line%%[![:space:]]*}"}"  # trim leading whitespace

    if [[ "$line" == *"method call"* && "$line" == *"member=Notify"* ]]; then
        if [[ "$line" =~ sender=([^[:space:],;]+) ]]; then sender="${BASH_REMATCH[1]}"; fi
        if [[ "$line" =~ serial=([0-9]+) ]];         then serial="${BASH_REMATCH[1]}"; fi
        if [[ "$sender" == :* && -n "$serial" ]]; then
            pid=$(get_pid "$sender")
            if [[ -n "$pid" && "$pid" != "0" ]]; then
                pending_pids["$serial"]="$pid"
            fi
        fi

    elif [[ "$line" == *"method return"* ]]; then
        if [[ "$line" =~ reply_serial=([0-9]+) ]]; then
            reply="${BASH_REMATCH[1]}"
            if [[ -n "${pending_pids[$reply]}" ]]; then
                awaiting_nid=true
                pending_pid="${pending_pids[$reply]}"
                unset "pending_pids[$reply]"
            fi
        fi

    elif [[ "$awaiting_nid" == true ]]; then
        if [[ "$line" =~ ^uint32[[:space:]]+([0-9]+) ]]; then
            echo "${BASH_REMATCH[1]}:${pending_pid}"
            awaiting_nid=false
            pending_pid=""
        elif [[ -n "$line" ]]; then
            awaiting_nid=false
        fi
    fi
done
