#!/bin/bash

# omarchy:summary=Send an Omarchy desktop notification
# omarchy:args=[--exec-arg <arg>]... [--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]
# omarchy:examples=omarchy notification send "Reminder" "5 minutes are up" -g 󰢌

set -euo pipefail

headline=""
description=""
glyph=
urgency="low"
app_name="omarchy-action"
image=
exec_command=
exec_args=()
args=()
parsed_option_args=0

parse_omarchy_option() {
  case $1 in
  -g | --glyph)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    glyph=$2
    parsed_option_args=2
    return 0
    ;;
  -u | --urgency)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    urgency="$2"
    parsed_option_args=2
    return 0
    ;;
  --app-name)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    app_name=$2
    parsed_option_args=2
    return 0
    ;;
  --image)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    image=$2
    parsed_option_args=2
    return 0
    ;;
  --exec)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    exec_command=$2
    parsed_option_args=2
    return 0
    ;;
  --exec-arg)
    if (($# < 2)); then
      echo "Missing value for $1" >&2
      exit 1
    fi
    # Each --exec-arg contributes one literal argument to the click command.
    # The shell runs the resulting argv vector directly (no shell), so callers
    # pass untrusted data as its own --exec-arg rather than quoting it into a
    # command string. Value is taken verbatim, even when it starts with "-".
    exec_args+=("$2")
    parsed_option_args=2
    return 0
    ;;
  esac

  return 1
}

while (($# > 0)); do
  if parse_omarchy_option "$@"; then
    shift "$parsed_option_args"
  else
    break
  fi
done

if (($# < 1)); then
  echo "Usage: omarchy-notification-send [--exec-arg <arg>]... [--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]"
  exit 1
fi

headline=$1
shift

if (($# > 0)) && [[ $1 != -* ]]; then
  description=$1
  shift
fi

while (($# > 0)); do
  if parse_omarchy_option "$@"; then
    shift "$parsed_option_args"
  else
    args+=("$1")
    shift
  fi
done

# Tag as a user-action toast so it pops through DND.
args+=("-a" "$app_name" "-u" "$urgency")

if [[ -n $glyph ]]; then
  args+=("--hint=string:omarchy-glyph:$glyph")
fi

if [[ -n $image ]]; then
  args+=("--hint=string:image-path:$image")
fi

# The shell runs the click command itself, from a copy it keeps alongside the
# on-screen popup. A libnotify action would instead keep this process blocked
# until the click, and die unanswered whenever the shell restarts underneath it.
#
# --exec-arg builds an argv vector the shell runs directly, so a value carrying
# untrusted data is only ever one argument and never reaches a shell. It wins
# over the legacy free-form --exec string, which is run through `bash -lc` and
# is only safe when the caller quoted every interpolated value itself.
if ((${#exec_args[@]} > 0)); then
  # NUL-delimit the args into jq so every byte survives as data — jq's own
  # --args would eat a bare "--", and a title with a newline must stay one
  # element, not split the vector.
  exec_argv_json=$(printf '%s\0' "${exec_args[@]}" | jq -Rsc 'split("\u0000")[:-1]')
  args+=("--hint=string:omarchy-exec-argv:$exec_argv_json")
elif [[ -n $exec_command ]]; then
  args+=("--hint=string:omarchy-exec:$exec_command")
fi

if [[ -n $description ]]; then
  notify-send "${args[@]}" "$headline" "$description"
else
  notify-send "${args[@]}" "$headline"
fi
