#!/bin/bash
# motel-layout — switch the desktop layout.
#
# Layouts are Plasma shell scripts. Applying one means handing it to the
# running plasmashell over D-Bus; there is no restart and no logout.
#
#   motel-layout list
#   motel-layout current
#   motel-layout apply windows
set -euo pipefail

LAYOUT_DIR="${MOTEL_LAYOUT_DIR:-/usr/share/motel/layouts}"
STATE_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/motel/layout"

die() { printf 'motel-layout: %s\n' "$*" >&2; exit 1; }

# Qt 6 renamed the tool and distributions disagree about which name they ship.
find_qdbus() {
    local candidate
    for candidate in qdbus6 qdbus-qt6 qdbus; do
        if command -v "$candidate" >/dev/null 2>&1; then
            printf '%s' "$candidate"
            return 0
        fi
    done
    return 1
}

list_layouts() {
    local f name
    for f in "$LAYOUT_DIR"/*.js; do
        [ -e "$f" ] || continue
        name="$(basename "$f" .js)"
        printf '%s\n' "$name"
    done
}

describe() {
    case "$1" in
        windows) printf 'Taskbar at the bottom, launcher at the left.' ;;
        macos)   printf 'Menu bar at the top, dock at the bottom.' ;;
        classic) printf 'Compact panel with a cascading menu and pager.' ;;
        touch)   printf 'Large targets and a full-screen launcher.' ;;
        *)       printf 'Custom layout.' ;;
    esac
}

cmd_list() {
    local name
    while read -r name; do
        printf '  %-10s %s\n' "$name" "$(describe "$name")"
    done < <(list_layouts)
}

cmd_current() {
    if [ -r "$STATE_FILE" ]; then
        cat "$STATE_FILE"
    else
        printf 'unknown\n'
    fi
}

cmd_apply() {
    local name="${1:-}"
    [ -n "$name" ] || die "apply needs a layout name (try: motel-layout list)"

    local script="$LAYOUT_DIR/$name.js"
    [ -r "$script" ] || die "no such layout: $name"

    [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ] || die "no graphical session"

    local qdbus
    qdbus="$(find_qdbus)" || die "qdbus not found; cannot talk to plasmashell"

    # evaluateScript returns plasmashell's own error text on failure rather than
    # a non-zero exit, so the output has to be inspected.
    local output
    if ! output="$("$qdbus" org.kde.plasmashell /PlasmaShell \
            org.kde.PlasmaShell.evaluateScript "$(cat "$script")" 2>&1)"; then
        die "plasmashell rejected the layout: $output"
    fi
    if [ -n "$output" ]; then
        die "plasmashell reported: $output"
    fi

    mkdir -p "$(dirname "$STATE_FILE")"
    printf '%s\n' "$name" > "$STATE_FILE"
    printf 'Applied layout: %s\n' "$name"
}

case "${1:-}" in
    list)    cmd_list ;;
    current) cmd_current ;;
    apply)   shift; cmd_apply "$@" ;;
    ""|-h|--help)
        cat <<EOF
Usage: motel-layout <command>

  list             Show available layouts
  current          Show the layout currently applied
  apply <name>     Switch to a layout

Layouts live in $LAYOUT_DIR
EOF
        ;;
    *) die "unknown command: $1" ;;
esac
