#!/usr/bin/env bash

# One stable command boundary for launcher actions. Vicinae scripts stay tiny,
# while the actual mapping to Quickshell IPC remains testable in one place.

set -euo pipefail

script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
action="${1:-}"
helper_dir="${PANAMA_ACTION_HELPER_DIR:-$script_dir}"
confirm_attempts="${PANAMA_ACTION_CONFIRM_ATTEMPTS:-20}"
confirm_delay="${PANAMA_ACTION_CONFIRM_DELAY:-0.1}"
kill_command="${PANAMA_ACTION_KILL_COMMAND:-/usr/bin/kill}"

osd_command=("$helper_dir/panama-osd")
gallery_command=("$helper_dir/panama-prism-gallery")

report_failure() {
    local status=$?
    trap - EXIT
    if (( status != 0 )) && command -v notify-send >/dev/null 2>&1; then
        notify-send -a Panama -i dialog-error-symbolic \
            "Panama action failed" \
            "The “${action//-/ }” action could not be completed." || true
    fi
    exit "$status"
}
trap report_failure EXIT

show_state() {
    local state="$1" on_icon="$2" off_icon="$3" label="$4"
    case "$state" in
        true) PANAMA_OSD_STRICT=1 "${osd_command[@]}" message "$on_icon" "$label On" ;;
        false) PANAMA_OSD_STRICT=1 "${osd_command[@]}" message "$off_icon" "$label Off" ;;
        *)
            printf 'Panama action returned an invalid state: %s\n' "$state" >&2
            return 1
            ;;
    esac
}

state_is_active() {
    local target="$1"
    case "$target" in
        caffeine)
            systemd-inhibit --list --no-pager --no-legend 2>/dev/null \
                | awk '$1 == "Panama" && $(NF - 1) == "Caffeine" && $NF == "block" { found = 1 } END { exit !found }'
            ;;
        night-light)
            pgrep -u "$(id -u)" -x hyprsunset >/dev/null 2>&1
            ;;
        *) return 2 ;;
    esac
}

release_caffeine_inhibitors() {
    local inhibitors pid uid
    uid="$(id -u)"
    inhibitors="$(systemd-inhibit --list --no-pager --no-legend 2>/dev/null \
        | awk -v uid="$uid" '$1 == "Panama" && $2 == uid && $(NF - 1) == "Caffeine" && $NF == "block" { print $4 }')"
    while IFS= read -r pid; do
        [[ $pid =~ ^[0-9]+$ ]] || continue
        "$kill_command" "$pid" 2>/dev/null || true
    done <<<"$inhibitors"
}

wait_for_confirmed_state() {
    local target="$1" expected="$2" attempt
    for ((attempt = 0; attempt < confirm_attempts; attempt++)); do
        if [[ $expected == true ]] && state_is_active "$target"; then
            return 0
        fi
        if [[ $expected == false ]] && ! state_is_active "$target"; then
            return 0
        fi
        sleep "$confirm_delay"
    done
    printf 'Panama action could not confirm %s reached state %s\n' "$target" "$expected" >&2
    return 1
}

toggle_state() {
    local target="$1" on_icon="$2" off_icon="$3" label="$4" state
    state="$(qs ipc call "$target" toggle)"
    case "$state" in true|false) ;; *) show_state "$state" "$on_icon" "$off_icon" "$label"; return ;; esac
    if [[ $target == caffeine && $state == false ]]; then
        release_caffeine_inhibitors
    fi
    wait_for_confirmed_state "$target" "$state"
    show_state "$state" "$on_icon" "$off_icon" "$label"
}

wait_for_shell() {
    local attempt
    for ((attempt = 0; attempt < confirm_attempts; attempt++)); do
        if qs ipc show >/dev/null 2>&1; then
            return 0
        fi
        sleep "$confirm_delay"
    done
    printf 'Panama shell did not become ready after restart\n' >&2
    return 1
}

case "$action" in
    control-center) qs ipc call quicksettings open ;;
    notifications) qs ipc call notifications open ;;
    calendar) qs ipc call calendar-agenda open ;;
    clipboard) qs ipc call clipboard open ;;
    overview) qs ipc call overview open ;;
    settings) qs ipc call settings open ;;

    # Jump straight to one settings page. The launcher's per-page commands are
    # the only caller, and they are generated from the page list itself, so the
    # pattern below is a boundary check rather than a whitelist: an unknown page
    # would leave the settings window showing nothing at all.
    settings-page)
        page="${2:-}"
        if [[ ! "$page" =~ ^[a-z][a-z-]*$ ]]; then
            printf 'Usage: panama-action settings-page PAGE\n' >&2
            exit 2
        fi
        qs ipc call settings page "$page"
        ;;
    dock-pin) qs ipc call dock pickApp ;;
    health) qs ipc call health open ;;

    dnd)
        state="$(qs ipc call notifications dnd)"
        show_state "$state" notifications-disabled-symbolic notifications-symbolic "Do Not Disturb"
        ;;
    caffeine)
        toggle_state caffeine weather-clear-symbolic weather-clear-night-symbolic Caffeine
        ;;
    night-light)
        toggle_state night-light night-light-symbolic night-light-disabled-symbolic "Night Light"
        ;;
    focus-start)
        state="$(qs ipc call focus start)"
        [[ $state == true ]]
        PANAMA_OSD_STRICT=1 "${osd_command[@]}" message preferences-system-time-symbolic "Focus Session Started"
        ;;
    focus-end)
        state="$(qs ipc call focus end)"
        if [[ $state == true ]]; then
            PANAMA_OSD_STRICT=1 "${osd_command[@]}" message media-playback-stop-symbolic "Focus Session Ended"
        else
            PANAMA_OSD_STRICT=1 "${osd_command[@]}" message dialog-information-symbolic "No Focus Session Running"
        fi
        ;;

    capture) qs ipc call capture open ;;
    intelligence) qs ipc call screen-intelligence open ;;
    screenshot) qs ipc call capture screenNow ;;
    microphone) PANAMA_OSD_STRICT=1 "${osd_command[@]}" microphone toggle ;;

    gallery) "${gallery_command[@]}" ;;
    restart-shell)
        qs kill >/dev/null 2>&1 || true
        quickshell --daemonize
        wait_for_shell
        PANAMA_OSD_STRICT=1 "${osd_command[@]}" message view-refresh-symbolic "Panama Restarted"
        ;;
    *)
        printf 'Usage: panama-action {%s}\n' \
            'control-center|notifications|calendar|clipboard|overview|settings|settings-page PAGE|dock-pin|health|dnd|caffeine|night-light|focus-start|focus-end|capture|intelligence|screenshot|microphone|gallery|restart-shell' >&2
        exit 2
        ;;
esac
