#!/usr/bin/env bash
# Install an AgentVox daemon as a macOS LaunchAgent, so it starts at login and
# is restarted if it dies. Run on the machine you are adding.
#
#   ./install-launchd.sh            # the host daemon (default)
#   ./install-launchd.sh vox        # the Vox assistant daemon
#
# Idempotent: re-running replaces the existing agent with a fresh one.
#
# LaunchAgent, not LaunchDaemon: these daemons own tmux sessions belonging to a
# logged-in user and need that user's environment and keychain. An agent keeps
# running while the screen is locked and stops at logout — right for a laptop.
set -euo pipefail

COMPONENT="${1:-host}"
case "$COMPONENT" in
  host|vox) ;;
  *) echo "usage: $0 [host|vox]" >&2; exit 2 ;;
esac

LABEL="io.percip.agentvox.$COMPONENT"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
LOG="$HOME/.agentvox/$COMPONENT.log"
CONFIG="$HOME/.agentvox/$COMPONENT.json"

# launchd starts jobs with a minimal PATH containing none of the usual install
# locations, so every path in the plist must be absolute and resolved now, at
# install time. The same class of mistake produces status=203/EXEC under
# systemd.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

TARGET="$(command -v "agentvox-$COMPONENT" 2>/dev/null || true)"
if [[ -z "$TARGET" && "$COMPONENT" == "vox" ]]; then
  # Vox is not published to npm, so it normally runs straight from the repo.
  TARGET="$REPO_ROOT/vox/dist/cli.js"
  [[ -f "$TARGET" ]] || { echo "ERROR: $TARGET not found — run 'npm run build -w vox' first." >&2; exit 1; }
fi
if [[ -z "$TARGET" ]]; then
  echo "ERROR: agentvox-$COMPONENT is not on PATH. Install it first:" >&2
  echo "       npm install -g @agentvox/$COMPONENT" >&2
  exit 1
fi

# Resolve the wrapper symlink to the real script, and use the node that is
# actually on PATH rather than assuming a location.
SCRIPT_PATH="$(python3 -c 'import os,sys;print(os.path.realpath(sys.argv[1]))' "$TARGET")"
NODE_BIN="$(command -v node)"

echo "→ component : $COMPONENT"
echo "→ node      : $NODE_BIN ($("$NODE_BIN" --version))"
echo "→ script    : $SCRIPT_PATH"
echo "→ plist     : $PLIST"

if [[ ! -f "$CONFIG" ]]; then
  echo
  echo "WARNING: no $CONFIG — this machine is not enrolled yet." >&2
  if [[ "$COMPONENT" == "host" ]]; then
    echo "         Run 'agentvox-host pair' and claim the code in the iOS app," >&2
  else
    echo "         Run 'agentvox-vox enroll --proxy <url> --token <device-token>'," >&2
  fi
  echo "         then re-run this script." >&2
  echo
fi

mkdir -p "$HOME/Library/LaunchAgents" "$HOME/.agentvox"

# Unload any previous incarnation before rewriting, or launchd keeps running
# the old ProgramArguments.
launchctl bootout "gui/$(id -u)/$LABEL" 2>/dev/null || true

cat > "$PLIST" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>$LABEL</string>
    <key>ProgramArguments</key>
    <array>
        <string>$NODE_BIN</string>
        <string>$SCRIPT_PATH</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>ThrottleInterval</key>
    <integer>10</integer>
    <!-- launchd would otherwise start the job in "/", and the host daemon
         reports its cwd to the proxy as the host's workingDir — which Vox
         uses as the fallback path when creating an agent with no explicit
         directory. Landing new agents in "/" is not what anyone wants. -->
    <key>WorkingDirectory</key>
    <string>$HOME</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>$(dirname "$NODE_BIN"):/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
        <key>HOME</key>
        <string>$HOME</string>
    </dict>
    <key>StandardOutPath</key>
    <string>$LOG</string>
    <key>StandardErrorPath</key>
    <string>$LOG</string>
</dict>
</plist>
PLISTEOF

launchctl bootstrap "gui/$(id -u)" "$PLIST"
launchctl kickstart -k "gui/$(id -u)/$LABEL"

sleep 3
echo
if launchctl list | grep -q "$LABEL"; then
  echo "✓ $LABEL is loaded"
  launchctl list | grep "$LABEL" | awk '{print "  pid="$1"  last-exit="$2}'
else
  echo "✗ $LABEL failed to load — check $LOG" >&2
  exit 1
fi

echo
echo "Logs:    tail -f $LOG"
echo "Stop:    launchctl bootout gui/$(id -u)/$LABEL"
echo "Restart: launchctl kickstart -k gui/$(id -u)/$LABEL"
