#!/bin/sh -eu

usage() {
	echo "Usage: makoctl <command> [options...]"
	echo ""
	echo "Commands:"
	echo "  dismiss [-n id]                Dismiss the notification with the"
	echo "                                 given id, or the last notification"
	echo "                                 if none is given"
	echo "          [-a|--all]             Dismiss all notifications"
	echo "          [-g|--group]           Dismiss all the notifications"
	echo "                                 in the last notification's group"
	echo "  restore                        Restore the most recently expired"
	echo "                                 notification from the history buffer"
	echo "  invoke [-n id] [action]        Invoke an action on the notification"
	echo "                                 with the given id, or the last"
	echo "                                 notification if none is given"
	echo "  menu [-n id] <prog> [arg ...]  Use <prog> [args ...] to select one"
	echo "                                 action to be invoked on the notification"
	echo "                                 with the given id, or the last"
	echo "                                 notification if none is given"
	echo "  list                           List notifications"
	echo "  history                        List history"
	echo "  reload                         Reload the configuration file"
	echo "  mode                           List modes"
	echo "  mode [-a mode]... [-r mode]... Add/remove modes"
	echo "  mode -s mode...                Set modes"
	echo "  help                           Show this help"
}

BUSCTL=busctl
if ! type $BUSCTL >/dev/null 2>&1; then
	BUSCTL=basuctl
fi
if ! type $BUSCTL >/dev/null 2>&1; then
	echo >&2 "$0: busctl or basuctl is required"
	exit 1
fi

call() {
	$BUSCTL -j --user call org.freedesktop.Notifications /fr/emersion/Mako \
		fr.emersion.Mako -- "$@"
}

require_jq() {
	if ! type jq >/dev/null 2>&1; then
		echo >&2 "$0: jq is required to use this command"
		exit 1
	fi
}

if [ $# -eq 0 ]; then
	usage
	exit 1
fi

case "$1" in
"dismiss")
	all=0
	group=0
	id=0
	while [ $# -gt 1 ]; do
		case "$2" in
		"-a"|"--all")
			all=1
			;;
		"-g"|"--group")
			group=1
			;;
		"-n")
			if [ $# -lt 3 ]; then
				echo >&2 "$0: Expected <id> after '-n'"
				exit 1
			fi
			id=$3
			shift
			;;
		*)
			echo >&2 "$0: Unrecognized option: $2"
			exit 1
			;;
		esac
		shift
	done

	if [ $all -eq 1 ]; then
		call DismissAllNotifications
	else
		call DismissNotification "ub" "$id" "$group"
	fi
	;;
"invoke")
	id=0
	if [ $# -gt 1 ] && [ "$2" = "-n" ]; then
		id="$3"
		shift 2
	fi

	action="default"
	if [ $# -gt 1 ]; then
		action="$2"
	fi

	call InvokeAction "us" "$id" "$action"
	;;
"restore")
	call RestoreNotification
	;;
"menu")
	shift 1
	require_jq
	if [ $# -gt 1 ] && [ "$1" = "-n" ]; then
		id="$2"
		actions="$(call ListNotifications | jq --arg id "$id" -re '.data[0][] | select(.id.data==($id | tonumber)) | .actions.data')"
		shift 2
	else
		actions="$(call ListNotifications | jq -re '.data[0][0].actions.data')"
		id="0"
	fi
	if [ "$(jq -rn "$actions | length")" -eq "0" ]; then
		echo >&2 "$0: No actions found"
		exit 1
	fi

	sel="$(jq -rn "$actions|values[]" | "$@")"
	sel="$(jq -rn --arg sel "$sel" "$actions|to_entries[]|select(.value == \$sel).key")"
	if [ -z "$sel" ]; then
		echo >&2 "$0: No action selected"
		exit 1
	else
		call InvokeAction "us" "$id" "$sel"
	fi
	;;
"list")
	call ListNotifications
	;;
"history")
	call ListHistory
	;;
"reload")
	call Reload
	;;
"set-mode") # deprecated
	call SetMode "s" "$2"
	;;
"mode")
	shift 1
	require_jq
	modes="$(call ListModes | jq '.data[0]')"
	add_remove_flag=0
	set_flag=0
	while getopts a:r:s name; do
		case "$name" in
		a)
			add_remove_flag=1
			modes="$(echo "$modes" | jq --arg mode "$OPTARG" '. += [$mode]')"
			;;
		r)
			add_remove_flag=1
			modes="$(echo "$modes" | jq --arg mode "$OPTARG" 'del(.[] | select(. == $mode))')"
			;;
		s)
			set_flag=1
			;;
		?)
			exit 1
		esac
	done
	if [ "$add_remove_flag" = 1 ] && [ "$set_flag" = 1 ]; then
		echo >&2 "makoctl: -a/-r and -s cannot be used together"
		exit 1
	fi
	if [ "$set_flag" = 1 ]; then
		shift $(($OPTIND - 1))
		modes="$(jq -n '$ARGS.positional' --args "$@")"
	fi
	if [ "$add_remove_flag" = 1 ] || [ "$set_flag" = 1 ]; then
		modes="$(echo "$modes" | jq '. | unique')"
		modes_len="$(echo "$modes" | jq '. | length')"
		modes_args=$(echo "$modes" | jq -r '@sh')
		# Required to behave properly when mode names contain spaces
		eval set -- $modes_args
		call SetModes "as" "$modes_len" "$@"
	fi
	echo "$modes" | jq -r '.[]'
	;;
"help"|"--help"|"-h")
	usage
	;;
*)
	echo "makoctl: unrecognized command '$1'"
	exit 1
	;;
esac
