#!/usr/bin/env bash
# cc-remote installer — Claude Code on the shared worker, no Tailscale needed.
#
# Usage:
#   curl -fsSL https://cc.quake0day.com/install.sh | bash
#
# Does:
#   1. Verifies ssh/rsync, installs cloudflared if missing
#   2. Generates a dedicated SSH key (~/.ssh/id_cc_remote) if missing
#   3. Registers your public key with the worker (invite code required)
#   4. Writes a managed Host block to ~/.ssh/config (tunnel ProxyCommand)
#   5. Installs cc-remote to /usr/local/bin (or ~/.local/bin)
#
# Env overrides:
#   CC_INVITE=xxxx     skip the interactive invite-code prompt
#   CC_IDENTITY=name   skip the interactive identity prompt

set -e
set -o pipefail

API_URL="${CC_API_URL:-https://cc-api.quake0day.com}"
SSH_HOSTNAME="${CC_SSH_HOSTNAME:-cc-ssh.quake0day.com}"
WORKER_USER="claude"
SSH_ALIAS="cc-worker"
SCRIPT_URL="https://cc.quake0day.com/cc-remote"
KEY_PATH="$HOME/.ssh/id_cc_remote"

C_DIM='\033[2m'; C_BLU='\033[36m'; C_YEL='\033[33m'; C_GRN='\033[32m'; C_RED='\033[31m'; C_RST='\033[0m'
[[ -t 1 ]] || { C_DIM=''; C_BLU=''; C_YEL=''; C_GRN=''; C_RED=''; C_RST=''; }
say()   { printf "${C_BLU}▸${C_RST} %s\n" "$*"; }
warn()  { printf "${C_YEL}!${C_RST} %s\n" "$*"; }
err()   { printf "${C_RED}✗${C_RST} %s\n" "$*" >&2; }
ok()    { printf "${C_GRN}✓${C_RST} %s\n" "$*"; }

cat <<'BANNER'

  ╔══════════════════════════════════════════════╗
  ║   cc-remote installer  ·  no VPN required    ║
  ╚══════════════════════════════════════════════╝

BANNER

# ─── step 1: base tools + cloudflared ────────────────────────────
say "1/5  Checking tools…"
command -v ssh   >/dev/null || { err "ssh not found — install OpenSSH first"; exit 1; }
command -v rsync >/dev/null || { err "rsync not found. Install: brew install rsync (macOS) / apt install rsync (Linux)"; exit 1; }

if command -v cloudflared >/dev/null; then
  ok "cloudflared found: $(command -v cloudflared)"
else
  say "installing cloudflared (tunnels SSH through Cloudflare)…"
  os="$(uname -s)"; arch="$(uname -m)"
  if [[ "$os" == "Darwin" ]] && command -v brew >/dev/null; then
    brew install cloudflared
  elif [[ "$os" == "Linux" ]]; then
    case "$arch" in
      x86_64)          cf_arch="amd64" ;;
      aarch64|arm64)   cf_arch="arm64" ;;
      armv7l)          cf_arch="arm"   ;;
      *) err "unsupported arch: $arch — install cloudflared manually: https://developers.cloudflare.com/cloudflared/"; exit 1 ;;
    esac
    cf_url="https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cf_arch}"
    if [[ -w /usr/local/bin ]]; then cf_target=/usr/local/bin/cloudflared
    else mkdir -p "$HOME/.local/bin"; cf_target="$HOME/.local/bin/cloudflared"; fi
    curl -fsSL "$cf_url" -o "$cf_target"
    chmod +x "$cf_target"
    ok "installed cloudflared → $cf_target"
  else
    err "cannot auto-install cloudflared on $os. Install it, then re-run:"
    err "  https://developers.cloudflare.com/cloudflared/"
    exit 1
  fi
  command -v cloudflared >/dev/null || export PATH="$HOME/.local/bin:$PATH"
  command -v cloudflared >/dev/null || { err "cloudflared still not on PATH — open a new shell and re-run"; exit 1; }
fi

# Verify the worker API is reachable through the tunnel
if ! curl -fsS --max-time 10 "$API_URL/healthz" >/dev/null; then
  err "Cannot reach $API_URL/healthz — the worker tunnel may be down."
  err "Ask the admin to check:  systemctl status cloudflared cc-registrar"
  exit 1
fi
ok "worker API reachable at $API_URL"

# ─── step 2: ssh key ─────────────────────────────────────────────
say "2/5  Setting up SSH key…"
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
if [[ -f "$KEY_PATH" ]]; then
  ok "existing key found at $KEY_PATH"
  # regenerate a missing .pub from the private key (otherwise the cat below
  # fails with a confusing error)
  if [[ ! -f "${KEY_PATH}.pub" ]]; then
    ssh-keygen -y -f "$KEY_PATH" > "${KEY_PATH}.pub"
    ok "recreated missing public key: ${KEY_PATH}.pub"
  fi
else
  label="$(whoami)@$(hostname -s 2>/dev/null || hostname)-$(date +%Y%m%d)"
  ssh-keygen -t ed25519 -f "$KEY_PATH" -N "" -C "$label" -q
  ok "generated new key: $KEY_PATH"
fi
PUBKEY="$(cat "${KEY_PATH}.pub")"

# ─── step 3: register key (invite code) ──────────────────────────
say "3/5  Registering with the worker…"
# curl|bash leaves stdin holding the script — prompt via /dev/tty
INVITE="${CC_INVITE:-}"
if [[ -z "$INVITE" ]]; then
  if [[ -r /dev/tty ]]; then
    printf "${C_BLU}▸${C_RST} invite code: " > /dev/tty
    read -r INVITE < /dev/tty
  else
    err "no TTY to prompt for the invite code — re-run with CC_INVITE=xxxx"
    exit 1
  fi
fi
[[ -n "$INVITE" ]] || { err "empty invite code"; exit 1; }

IDENTITY="${CC_IDENTITY:-}"
if [[ -z "$IDENTITY" ]]; then
  default_id="$(whoami)-$(hostname -s 2>/dev/null || hostname)"
  if [[ -r /dev/tty ]]; then
    printf "${C_BLU}▸${C_RST} your identity (name/email, shown to admin) [%s]: " "$default_id" > /dev/tty
    read -r IDENTITY < /dev/tty
  fi
  IDENTITY="${IDENTITY:-$default_id}"
fi

# JSON-encode safely with python (handles quotes/spaces)
payload="$(python3 -c "import json,sys; print(json.dumps({'invite_code': sys.argv[1], 'public_key': sys.argv[2], 'identity': sys.argv[3]}))" "$INVITE" "$PUBKEY" "$IDENTITY" 2>/dev/null || \
          python -c "import json,sys; print(json.dumps({'invite_code': sys.argv[1], 'public_key': sys.argv[2], 'identity': sys.argv[3]}))" "$INVITE" "$PUBKEY" "$IDENTITY")"
http_code=$(curl -sS -o /tmp/cc-register-resp.$$ -w "%{http_code}" --max-time 15 \
  -X POST "$API_URL/register" \
  -H "content-type: application/json" \
  -d "$payload") || { err "registration request failed (network)"; exit 1; }
response="$(cat /tmp/cc-register-resp.$$ 2>/dev/null || true)"; rm -f /tmp/cc-register-resp.$$
if [[ "$http_code" == "403" ]]; then
  err "registration rejected: invalid invite code"
  exit 1
elif [[ "$http_code" != "200" ]]; then
  err "registration failed (HTTP $http_code): $response"
  exit 1
fi
echo "$response" | python3 -c "
import json, sys
d = json.load(sys.stdin)
status = 'added' if d.get('added') else 'already registered (identity refreshed)'
print(f'   fingerprint: {d.get(\"fingerprint\")}')
print(f'   identity:    {d.get(\"identity\")}')
print(f'   status:      {status}')
" 2>/dev/null || echo "$response"
ok "key registered"

# ─── step 4: managed ssh config block ────────────────────────────
say "4/5  Writing ssh config…"
cfg="$HOME/.ssh/config"
begin="# >>> cc-remote managed >>>"; end="# <<< cc-remote managed <<<"
block="$(cat <<EOF
$begin
Host $SSH_ALIAS
  HostName $SSH_HOSTNAME
  User $WORKER_USER
  IdentityFile $KEY_PATH
  IdentitiesOnly yes
  ProxyCommand cloudflared access ssh --hostname $SSH_HOSTNAME
  StrictHostKeyChecking accept-new
  ServerAliveInterval 30
  ConnectTimeout 15
$end
EOF
)"
touch "$cfg"; chmod 600 "$cfg"
if grep -qF "$begin" "$cfg"; then
  tmp="$(mktemp)"
  sed "/^$begin\$/,/^$end\$/d" "$cfg" > "$tmp"
  printf '%s\n' "$block" >> "$tmp"
  cat "$tmp" > "$cfg"; rm -f "$tmp"
  ok "refreshed managed block in $cfg"
else
  printf '\n%s\n' "$block" >> "$cfg"
  ok "added managed block to $cfg"
fi

# ─── step 5: install cc-remote ───────────────────────────────────
say "5/5  Installing cc-remote command…"
if [[ -w /usr/local/bin ]]; then
  target=/usr/local/bin/cc-remote
elif sudo -n true 2>/dev/null; then
  target=/usr/local/bin/cc-remote
  use_sudo=1
else
  mkdir -p "$HOME/.local/bin"
  target="$HOME/.local/bin/cc-remote"
fi

tmpfile=$(mktemp)
curl -fsSL "$SCRIPT_URL" -o "$tmpfile"
chmod +x "$tmpfile"

if [[ ${use_sudo:-0} -eq 1 ]]; then
  sudo mv "$tmpfile" "$target"
else
  mv "$tmpfile" "$target"
fi
ok "installed: $target"

# ─── smoke test ──────────────────────────────────────────────────
say "smoke test: connecting through the tunnel…"
if out="$(ssh -o BatchMode=yes "$SSH_ALIAS" whoami 2>/dev/null)" && [[ "$out" == "$WORKER_USER" ]]; then
  ok "tunnel + key + identity all working"
else
  warn "could not complete an SSH round-trip yet."
  warn "try manually:  ssh $SSH_ALIAS whoami     (should print '$WORKER_USER')"
  warn "if it fails, send the output to the admin."
fi

# ─── done ────────────────────────────────────────────────────────
echo
ok "All set. Try it:"
echo
echo -e "   ${C_GRN}cd /path/to/your/project${C_RST}"
echo -e "   ${C_GRN}cc-remote${C_RST}              # interactive (like local \`claude\`)"
echo -e "   ${C_GRN}cc-remote -p \"hi\"${C_RST}     # one-shot"
echo
echo "Your local cwd is auto-synced to the worker before each session"
echo "and synced back when you exit. Standard .git / node_modules etc. are excluded."
echo "Add patterns to .claudeignore in your project to skip more."
echo

if [[ "$target" == "$HOME/.local/bin/cc-remote" ]]; then
  if ! echo ":$PATH:" | grep -q ":$HOME/.local/bin:"; then
    warn "Note: $HOME/.local/bin is not in your PATH."
    warn "Add this to your shell rc:    export PATH=\"\$HOME/.local/bin:\$PATH\""
  fi
fi
