#!/bin/sh
# ════════════════════════════════════════════════════════════════════════════
# ShellJolt installer (POSIX sh).   curl -fsSL https://shelljolt.com/install | sh
#   • DEFAULT = FREE lite — semantic colors + live `memlive` dashboard + warn-and-ask
#     watchdog. No payment, no login, no account. Just works.
#   • Pro ($39/yr): re-run with  TSP_ACTIVATE=1  (opens the browser to subscribe).
#   • 2-day Pro trial: re-run with  TSP_CODE=<16-digit-code>
# Makes ZERO calls to any AI provider's API/auth (ToS-safe). Idempotent.
#   Local test:   TSP_API=http://localhost:3000 sh install.sh
# ════════════════════════════════════════════════════════════════════════════
set -eu
API="${TSP_API:-https://shelljolt.com}"
HOME_DIR="${HOME:?HOME not set}"
TSP="$HOME_DIR/.terminal-superpowers"
LIC="$TSP/license.jwt"
ZSHRC="$HOME_DIR/.zshrc"
SRC_LINE="[ -f \"\$HOME/.terminal-superpowers/init.zsh\" ] && source \"\$HOME/.terminal-superpowers/init.zsh\""
say()  { printf '\033[36m▸\033[0m %s\n' "$1"; }
ok()   { printf '\033[32m✓\033[0m %s\n' "$1"; }
warn() { printf '\033[33m!\033[0m %s\n' "$1" >&2; }
die()  { printf '\033[31m✗ %s\033[0m\n' "$1" >&2; exit 1; }

[ "$(uname -s)" = "Darwin" ] || die "ShellJolt v1 is macOS-only (Windows/WSL2 coming in v2)."
command -v curl >/dev/null 2>&1 || die "curl is required."
mkdir -p "$TSP"

# ── 1. FREE lite (ALWAYS — no payment, no login): shell colors + live dashboard + warn-and-ask watchdog ──
say "Installing ShellJolt free lite (colors + live dashboards + warnings)…"
for f in init.zsh claude-memory-watchdog.sh claude-mem-live.sh sj-statusline.py cc-live.py sj_predict.py; do
  curl -fsS "$API/assets/$f" -o "$TSP/$f" || die "Failed to download $f"
done
chmod +x "$TSP/claude-memory-watchdog.sh" "$TSP/claude-mem-live.sh" "$TSP/sj-statusline.py" "$TSP/cc-live.py"
mkdir -p "$TSP/sessions"

# ── wire Claude Code's status line (the live context · cost · limits bar) — agnostic + non-destructive ──
# Only for Claude Code users; never clobbers an existing custom status line; backs up settings.json first.
CC_SETTINGS="$HOME_DIR/.claude/settings.json"
if command -v python3 >/dev/null 2>&1 && [ -d "$HOME_DIR/.claude" ]; then
  python3 - "$CC_SETTINGS" "$TSP/sj-statusline.py" <<'PY' || true
import json, os, sys, shutil
path, cmd = sys.argv[1], sys.argv[2]
try: d = json.load(open(path)) if os.path.exists(path) else {}
except Exception: d = {}
sl = d.get("statusLine")
if isinstance(sl, dict) and str(sl.get("command", "")).endswith("sj-statusline.py"):
    pass
elif sl:
    print("   (kept your existing Claude status line — run `cclive` for the full dashboard)")
else:
    if os.path.exists(path): shutil.copy(path, path + ".sj-bak")
    d["statusLine"] = {"type": "command", "command": cmd}
    os.makedirs(os.path.dirname(path), exist_ok=True)
    json.dump(d, open(path, "w"), indent=2)
    print("   ✓ Claude Code status line wired (context · cost · limits).")
PY
fi

# Best-effort fetch of the compiled engine binary (it's the Pro gate; absent/unlicensed → degrades to free).
if curl -fsS "$API/assets/shelljolt" -o "$TSP/shelljolt" 2>/dev/null && [ -s "$TSP/shelljolt" ]; then
  chmod +x "$TSP/shelljolt"
  # Rely on notarization (don't strip quarantine). If Gatekeeper/arch blocks it, drop to the free shell tier.
  "$TSP/shelljolt" version >/dev/null 2>&1 || rm -f "$TSP/shelljolt"
fi

# ── 2. wire into zsh (idempotent + backup) ──
if [ -f "$ZSHRC" ] && ! grep -qF '.terminal-superpowers/init.zsh' "$ZSHRC"; then
  cp "$ZSHRC" "$ZSHRC.shelljolt-bak-$(date +%Y%m%d%H%M%S)"
  printf '\n# ShellJolt\n%s\n' "$SRC_LINE" >> "$ZSHRC"
elif [ ! -f "$ZSHRC" ]; then
  printf '# ShellJolt\n%s\n' "$SRC_LINE" > "$ZSHRC"
fi
ok "Shell layer wired into ~/.zshrc"

# ── 3. warn-and-ask watchdog (user LaunchAgent, no sudo): shell watchdog (free) or `shelljolt watch` (Pro) ──
PLIST="$HOME_DIR/Library/LaunchAgents/com.shelljolt.watchdog.plist"
mkdir -p "$HOME_DIR/Library/LaunchAgents"
if [ -x "$TSP/shelljolt" ]; then
  PROGARGS="<string>$TSP/shelljolt</string><string>watch</string>"
  RUNMODE="<key>KeepAlive</key><true/><key>ThrottleInterval</key><integer>10</integer>"
else
  PROGARGS="<string>/bin/zsh</string><string>$TSP/claude-memory-watchdog.sh</string>"
  RUNMODE="<key>StartInterval</key><integer>30</integer>"
fi
cat > "$PLIST" <<PLIST
<?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>com.shelljolt.watchdog</string>
  <key>ProgramArguments</key><array>$PROGARGS</array>
  $RUNMODE<key>RunAtLoad</key><true/>
  <key>ProcessType</key><string>Background</string><key>LowPriorityIO</key><true/>
  <key>EnvironmentVariables</key><dict><key>HOME</key><string>$HOME_DIR</string><key>PATH</key><string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string></dict>
</dict></plist>
PLIST
launchctl bootout "gui/$(id -u)/com.shelljolt.watchdog" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" "$PLIST" 2>/dev/null && ok "Watchdog active (warn-and-ask; never auto-closes your terminals)." || warn "Watchdog will start on next login."

# ── 4. OPTIONAL Pro activation — ONLY when you ask for it (free users never see a paywall) ──
license=""
if [ -n "${TSP_CODE:-}" ] || [ -n "${TSP_ACTIVATE:-}" ]; then
  device_token="$( (uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || od -xN16 /dev/urandom | head -1 | tr -d ' \n') | tr 'A-Z' 'a-z')"
  curl -fsS -X POST "$API/api/device/start" -H 'content-type: application/json' \
    -d "{\"device_token\":\"$device_token\",\"host\":\"$(hostname 2>/dev/null || echo mac)\",\"os\":\"macos\"}" >/dev/null \
    || die "Could not reach the activation server ($API)."
  if [ -n "${TSP_CODE:-}" ]; then
    say "Redeeming your Pro-trial code…"
    resp="$(curl -fsS -X POST "$API/api/license/redeem" -H 'content-type: application/json' -d "{\"code\":\"$TSP_CODE\",\"device_token\":\"$device_token\"}" 2>/dev/null || echo '')"
    license="$(printf '%s' "$resp" | sed -n 's/.*"license":"\([^"]*\)".*/\1/p')"
    [ -n "$license" ] || die "That code is invalid, used up, or expired (trial codes last ~2 days)."
  else
    activate_url="$API/activate?token=$device_token"
    say "Opening your browser to subscribe (Pro \$39/yr)…"
    command -v open >/dev/null 2>&1 && open "$activate_url" >/dev/null 2>&1 || true
    printf '\n   If the browser did not open, paste this URL:\n   \033[4m%s\033[0m\n\n' "$activate_url"
    say "Waiting for payment to complete…"
    i=0
    while [ "$i" -lt 100 ]; do
      resp="$(curl -fsS "$API/api/license/activate?token=$device_token" 2>/dev/null || echo '')"
      case "$resp" in *'"status":"active"'*) license="$(printf '%s' "$resp" | sed -n 's/.*"license":"\([^"]*\)".*/\1/p')"; [ -n "$license" ] && break ;; esac
      i=$((i+1)); sleep 3
    done
    [ -n "$license" ] || die "Activation timed out. Re-run: TSP_ACTIVATE=1 curl -fsSL $API/install | sh"
  fi
  printf '%s' "$license" > "$LIC"; chmod 600 "$LIC"
fi

# ── 5. honest status + what-to-do-next (assume the user is brand new to this — teach in a few short lines) ──
printf '\n\033[1;32m✓ ShellJolt installed.\033[0m  '
if [ -s "$LIC" ]; then printf 'Pro is active on this Mac.\n'; else printf "You're on the free tier.\n"; fi
printf '\n  \033[1mIt is already working.\033[0m  ShellJolt now runs quietly in the background and warns you\n'
printf '  \033[1mbefore\033[0m a busy AI agent (Claude Code, Codex, Gemini, Grok) freezes your Mac.\n'
printf '  Keep coding — it taps your shoulder only when memory runs low. Nothing to watch.\n'
printf '\n  Optional — to load the colors into THIS window now, type:  \033[1mexec zsh\033[0m\n'
printf '  To peek at memory any time, type:  \033[1mmemlive --once\033[0m   (a one-look snapshot)\n'
printf '  (Or \033[1mmemlive\033[0m for a live monitor — open it in a spare tab; press Ctrl-C to close it.)\n'
if [ ! -s "$LIC" ]; then
  printf '\n  \033[1mUpgrade to Pro\033[0m (\033[1m$39/yr\033[0m) for automatic memory budgeting: %s/activate\n' "$API"
fi
printf '\n'
