#!/usr/bin/env bash
# workmux-palette — workmux as a tmux-palette source (the "workmux" palette,
# ~/.config/tmux-palette/palettes/workmux.json).
#
#   workmux-palette              print palette items (JSON): every agent
#                                workmux tracks in this tmux server (waiting,
#                                then done, then working), the worktrees of the
#                                active pane's repo with Close/Merge/Remove
#                                items, New from a prompt, and the dashboard,
#                                sidebar and last-done tools
#   workmux-palette --add BRANCH the palette's query item (what was typed):
#                                `workmux add BRANCH` in the active pane's repo
#   workmux-palette --prompt     the New item's popup body: `gum write` the
#                                task (enter submits, ctrl+j newline, esc
#                                cancels), then `workmux add -A -p TASK`
#   workmux-palette --popup DIR CMD…
#                                run CMD… in DIR in a popup that closes when it
#                                succeeds and waits for a key when it fails
#   workmux-palette --do DIR CMD…
#                                run CMD… in DIR; a failure shows its last
#                                output line as a tmux message
#
# Lifecycle commands (add, merge, remove) run in a popup: they print hook
# output and may ask y/n (remove with unmerged commits). Open and close are
# quick, so they run in place.

set -uo pipefail
self=$(readlink -f "$0")

case ${1-} in
--exec) # the popup's command (see --popup)
    shift
    "$@"
    status=$?
    [ "$status" -eq 0 ] && exit 0
    printf '\n\033[2m[exit %s] any key to close\033[0m' "$status"
    read -rsn1
    exit 0
    ;;
--popup)
    dir=$2
    shift 2
    # argv form: tmux runs it without a shell and expands no formats in it.
    title=${*/#"$self"/${self##*/}}
    exec tmux display-popup -E -w 80% -h 60% -d "$dir" -T " ${title//#/##} " "$self" --exec "$@"
    ;;
--do)
    cd "$2" || exit 1
    shift 2
    if ! out=$("$@" 2>&1); then
        msg=$(tail -n1 <<<"$out")
        tmux display-message -d 5000 "workmux: ${msg//#/##}"
    fi
    exit 0
    ;;
--add)
    cwd=$(tmux display -p '#{pane_current_path}')
    exec "$self" --popup "$cwd" workmux add "$2"
    ;;
--prompt)
    # The branch name comes from omp under auto_name in workmux's config.yaml.
    task=$(gum write --width 0 --height 8 \
        --header "New worktree in ${PWD##*/}: describe the task (enter submits, ctrl+j newline, esc cancels)" \
        --placeholder "What should the agent do?") || exit 0
    [ -n "${task//[[:space:]]/}" ] || exit 0
    printf '→ naming the branch…\n'
    exec workmux add -A -p "$task"
    ;;
esac

cwd=$(tmux display -p '#{pane_current_path}' 2>/dev/null) || cwd=$PWD
root=$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null) || root=
worktrees='[]'
[ -n "$root" ] && worktrees=$(cd "$root" && workmux list --json 2>/dev/null) || worktrees='[]'

workmux status --all --json 2>/dev/null | jq --arg self "$self" --arg home "$HOME" --arg root "$root" \
    --argjson worktrees "${worktrees:-[]}" '
    def tilde: if startswith($home) then "~" + .[($home | length):] else . end;
    def ago: if . < 60 then "\(.)s" elif . < 3600 then "\(. / 60 | floor)m"
             else "\(. / 3600 | floor)h\(. % 3600 / 60 | floor)m" end;
    def run($mode; $argv): {shell: ([$self, $mode, $root] + $argv | map(@sh) | join(" "))};
    # An agent that registered but reported nothing yet has status "-".
    {working: {icon: "\uf110", color: "#5ea1ff", rank: 2, label: "working"},
     waiting: {icon: "\uf075", color: "#f1ff5e", rank: 0, label: "waiting"},
     done:    {icon: "\uf00c", color: "#5eff6c", rank: 1, label: "done"}} as $look
    | {icon: "\uf544", color: "#7b8496", rank: 3, label: "idle"} as $idle
    | ($worktrees | map(select(.is_main | not))) as $trees
    | (if $root == "" then "" else $root | split("/") | last end) as $repo
    | [
      ((.agents // []) | map(. + {look: ($look[.status // ""] // $idle)})
       | sort_by([.look.rank, (.elapsed_secs // 0)])[]
       | {category: "Agents", icon: .look.icon, iconColor: .look.color,
          title: (if .worktree == .project then .project else "\(.project)/\(.worktree)" end),
          description: ([.look.label + (if .elapsed_secs == null then "" else " \(.elapsed_secs | ago)" end),
                         (if (.title // "") == "" then .session else .title end)] | join(" · ")),
          action: {tmux: "switch-client -t \(.pane_id | @sh)"}}),
      ($trees[]
       | {category: "Worktrees: \($repo)", icon: "\uf126",
          title: .handle,
          description: ([.branch, (if .is_open then "open" else "closed" end)]
                        + (if .has_uncommitted_changes then ["dirty"] else [] end)
                        + [.path | tilde] | join(" · ")),
          action: run("--do"; ["workmux", "open", .handle])}
         + (if .is_open then {iconColor: "#5eff6c"} else {} end)),
      (if $root == "" then empty else
        {category: "New", icon: "\uf067", title: "New worktree from a prompt",
         description: "type the task (gum write); omp names the branch · \($repo)",
         aliases: ["add", "prompt"], action: run("--popup"; [$self, "--prompt"])}
       end),
      {category: "Workmux", icon: "\uf0e4", title: "Dashboard", description: "agents and worktrees TUI in a popup",
       aliases: ["dash"], action: {tmux: "display-popup -E -w 90% -h 90% workmux dashboard"}},
      {category: "Workmux", icon: "\uf0db", title: "Sidebar", description: "toggle the agent status sidebar",
       shortcut: "Ctrl+Shift+S", aliases: ["side"], action: {tmux: "run-shell -b \("workmux sidebar" | @sh)"}},
      {category: "Workmux", icon: "\uf0e2", title: "Last done", description: "jump to the agent that last finished or is waiting",
       aliases: ["ld"], action: {tmux: "run-shell -b \("workmux last-done" | @sh)"}},
      ($trees[] | select(.is_open)
       | {category: "Close", icon: "\uf00d", title: "Close \(.handle)", description: "close the session, keep the worktree and branch",
          action: run("--do"; ["workmux", "close", .handle])}),
      ($trees[]
       | {category: "Merge", icon: "\uf419", title: "Merge \(.handle)", description: "merge \(.branch) into the main branch, then remove it",
          action: run("--popup"; ["workmux", "merge", .handle])}),
      ($trees[]
       | {category: "Remove", icon: "\uf1f8", title: "Remove \(.handle)", description: "remove the worktree, session and branch without merging",
          action: run("--popup"; ["workmux", "remove", .handle])})
    ]'
