#!/bin/sh
# claude-rc — central manager for always-on `claude rc` (Remote Control) servers,
# supervised by systemd --user on this host. Runs ON the host (apricot); drive it
# from elsewhere over ssh (plum's `rc` function forwards here).
#
# Single source of truth is the registry:
#     ~/.config/claude-rc/projects        # lines: name=dir  ('#' comments)
# `dir` is relative to $HOME (or absolute, or ~/...). Each entry maps to a
# systemd template instance `claude-rc@<name>.service` running `claude rc --name
# <name>` in <dir>. systemd + Linger give boot-persistence and Restart=always.
#
# Commands:
#   list                       registry + unit state + dir
#   status [name]              state + claude.ai/code URL (all, or one)
#   url <name>                 print the environment URL
#   add <name> <dir>           register + enable --now
#   rm  <name>                 disable + unregister
#   sync                       reconcile units to the registry (boot/after edits)
#   logs <name> [journalctl-args…]
#   restart|stop|start <name>
#   _run <name>                internal: exec'd by the template unit
set -eu

REG=${CLAUDE_RC_REGISTRY:-$HOME/.config/claude-rc/projects}
TPL=claude-rc@          # systemd template prefix

uc() { systemctl --user "$@"; }

# name -> absolute dir (resolves rel-to-HOME, ~/ and absolute). Empty if absent.
reg_dir() {
    [ -f "$REG" ] || return 0
    while IFS= read -r line || [ -n "$line" ]; do
        case "$line" in ''|\#*) continue ;; esac
        [ "${line%%=*}" = "$1" ] || continue
        d=${line#*=}
        case "$d" in
            /*)    printf %s "$d" ;;
            '~/'*) printf %s "$HOME/${d#\~/}" ;;
            *)     printf %s "$HOME/$d" ;;
        esac
        return 0
    done < "$REG"
}

reg_names() {
    [ -f "$REG" ] || return 0
    while IFS= read -r line || [ -n "$line" ]; do
        case "$line" in ''|\#*) continue ;; esac
        printf '%s\n' "${line%%=*}"
    done < "$REG"
}

url_of() {
    journalctl --user -u "$TPL$1" -o cat -n 120 2>/dev/null \
        | grep -oE 'env_[A-Za-z0-9]+' | tail -1
}

require() { [ -n "${1:-}" ] || { echo "claude-rc: missing <name>" >&2; exit 2; }; }

cmd=${1:-list}; [ $# -gt 0 ] && shift || true
case "$cmd" in
    _run)
        name=${1:-}; require "$name"
        dir=$(reg_dir "$name")
        [ -n "$dir" ] || { echo "claude-rc: '$name' not in $REG" >&2; exit 1; }
        cd "$dir" || { echo "claude-rc: dir missing: $dir" >&2; exit 1; }
        # --spawn is mandatory for headless operation: without it `claude rc`
        # prompts "Choose [1/2]" for spawn mode and blocks forever. Default to
        # worktree (isolated session per spawn — safe for concurrent agents);
        # override per-instance with CLAUDE_RC_SPAWN=same-dir|session.
        # --permission-mode sets the mode for spawned sessions; bypassPermissions
        # so phone/web sessions run without permission prompts (override with
        # CLAUDE_RC_PERM=default|acceptEdits|plan|...).
        exec claude rc --name "$name" \
            --spawn "${CLAUDE_RC_SPAWN:-worktree}" \
            --permission-mode "${CLAUDE_RC_PERM:-bypassPermissions}"
        ;;
    list|ls)
        printf '%-16s %-10s %s\n' NAME STATE DIR
        reg_names | while read -r n; do
            printf '%-16s %-10s %s\n' "$n" "$(uc is-active "$TPL$n" 2>/dev/null || echo -)" "$(reg_dir "$n")"
        done
        ;;
    status|st)
        show() {
            env=$(url_of "$1")
            printf '%-16s %-10s %s\n' "$1" "$(uc is-active "$TPL$1" 2>/dev/null || echo -)" \
                "${env:+https://claude.ai/code?environment=$env}"
        }
        if [ -n "${1:-}" ]; then show "$1"; else reg_names | while read -r n; do show "$n"; done; fi
        ;;
    url)
        name=${1:-}; require "$name"
        env=$(url_of "$name")
        [ -n "$env" ] && echo "https://claude.ai/code?environment=$env" || { echo "claude-rc: no URL for $name" >&2; exit 1; }
        ;;
    add)
        name=${1:-}; dir=${2:-}
        [ -n "$name" ] && [ -n "$dir" ] || { echo "usage: claude-rc add <name> <dir>" >&2; exit 2; }
        mkdir -p "$(dirname "$REG")"; touch "$REG"
        if reg_names | grep -qx "$name"; then
            echo "claude-rc: '$name' already registered ($(reg_dir "$name"))"
        else
            printf '%s=%s\n' "$name" "$dir" >> "$REG"
            echo "registered $name=$dir"
        fi
        uc enable --now "$TPL$name" && echo "enabled+started $TPL$name"
        ;;
    rm|remove)
        name=${1:-}; require "$name"
        uc disable --now "$TPL$name" 2>/dev/null && echo "disabled $TPL$name" || true
        if [ -f "$REG" ]; then
            tmp=$(mktemp); grep -v "^$name=" "$REG" > "$tmp" 2>/dev/null || true; mv "$tmp" "$REG"
        fi
        echo "unregistered $name"
        ;;
    sync)
        # Bring every registered project up…
        reg_names | while read -r n; do
            uc enable --now "$TPL$n" >/dev/null 2>&1 && echo "up:   $n" || echo "FAIL: $n"
        done
        # …and tear down any enabled instance no longer in the registry.
        uc list-unit-files "${TPL}*.service" --no-legend 2>/dev/null | awk '{print $1}' | while read -r uf; do
            inst=${uf#"$TPL"}; inst=${inst%.service}
            [ -n "$inst" ] || continue
            if ! reg_names | grep -qx "$inst"; then
                uc disable --now "$TPL$inst" >/dev/null 2>&1 && echo "down: $inst (orphan)"
            fi
        done
        ;;
    logs)
        name=${1:-}; require "$name"; shift || true
        set -- "$@"
        [ $# -gt 0 ] || set -- -n 40 --no-pager
        exec journalctl --user -u "$TPL$name" "$@"
        ;;
    restart|stop|start)
        name=${1:-}; require "$name"
        uc "$cmd" "$TPL$name" && uc is-active "$TPL$name" 2>/dev/null || true
        ;;
    -h|--help|help)
        sed -n '2,33p' "$0" | sed 's/^# \{0,1\}//'
        ;;
    *)
        echo "claude-rc: unknown command '$cmd' (try: claude-rc help)" >&2; exit 2
        ;;
esac
