#!/bin/bash
# Bridge a dedicated, throwaway Chrome profile on this Mac to an MCP gateway.
#
#   curl -fsSL https://get.tinker.dog/chrome | bash
#
# What it does, all inside your home directory, no sudo:
#   1. installs uv (Astral's Python manager) into ~/.local/bin if missing;
#   2. installs wss-bridge (a ~200-line WebSocket<->stdio relay) with uv;
#   3. installs chrome-cdp-mcp (a single static binary) into ~/.local/bin;
#   4. starts a SEPARATE Chrome with its own empty profile
#      (~/Library/Application Support/tinker-chrome/profile) and remote
#      debugging on 127.0.0.1 only. Your normal Chrome profile, its logins and
#      cookies are never touched and are not reachable through the bridge;
#   5. asks you to paste the gateway token (it is never written to disk,
#      never put on a command line, and never part of this script);
#   6. runs the bridge in this Terminal window. Leave it open for the demo;
#      Ctrl-C stops it. Quit the separate Chrome whenever you like.
#
# Run it again any time, or later just: ~/.local/bin/tinker-chrome
#
# Knobs (environment variables, all optional):
#   TINKER_WSS_URL   gateway device route  (default wss://shakil.mneme.bot/devices/chrome)
#   TINKER_TOKEN     token, skips the prompt (default: prompt on the terminal)
#   TINKER_CDP_PORT  local debugging port   (default 9339)
#   TINKER_GET_BASE  where to download from (default https://get.tinker.dog)
#   TINKER_CHROME    path to the Chrome binary (default: auto-detect)
#   TINKER_CHROME_ARGS  extra Chrome flags, e.g. "--headless=new"
#   TINKER_NO_BRIDGE=1  install and launch Chrome, but do not run the bridge

set -euo pipefail

SELF="chrome"   # this script's path under $BASE, for the relaunch copy
WSS_URL="${TINKER_WSS_URL:-wss://shakil.mneme.bot/devices/chrome}"
PORT="${TINKER_CDP_PORT:-9339}"
BASE="${TINKER_GET_BASE:-https://get.tinker.dog}"
BIN="$HOME/.local/bin"
WHEEL="wss_bridge-0.1.0-py3-none-any.whl"

say()  { printf '\033[1;34m==>\033[0m %s\n' "$*" >&2; }
ok()   { printf '\033[1;32m ok\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }

case "$(uname -s)" in
  Darwin) OS=darwin; DATA="$HOME/Library/Application Support/tinker-chrome" ;;
  Linux)  OS=linux;  DATA="${XDG_DATA_HOME:-$HOME/.local/share}/tinker-chrome" ;;
  *) die "unsupported OS $(uname -s); this is for macOS" ;;
esac
case "$(uname -m)" in
  arm64|aarch64) ARCH=arm64 ;;
  x86_64|amd64)  ARCH=amd64 ;;
  *) die "unsupported CPU $(uname -m)" ;;
esac
PROFILE="$DATA/profile"
mkdir -p "$BIN" "$PROFILE"
export PATH="$BIN:$PATH"

sha256() { if command -v shasum >/dev/null; then shasum -a 256 "$1"; else sha256sum "$1"; fi | cut -d' ' -f1; }

# ── 0. Chrome ──────────────────────────────────────────────────────────────
find_chrome() {
  if [ -n "${TINKER_CHROME:-}" ]; then echo "$TINKER_CHROME"; return; fi
  local c
  for c in "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
           "$HOME/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
           "/Applications/Chromium.app/Contents/MacOS/Chromium" \
           "$(command -v google-chrome-stable 2>/dev/null || true)" \
           "$(command -v google-chrome 2>/dev/null || true)" \
           "$(command -v chromium 2>/dev/null || true)"; do
    [ -n "$c" ] && [ -x "$c" ] && { echo "$c"; return; }
  done
  return 1
}
CHROME="$(find_chrome)" || die "Google Chrome not found. Install it from https://www.google.com/chrome/ and run this again."

# ── 1. uv ──────────────────────────────────────────────────────────────────
if [ -x "$BIN/uv" ]; then UV="$BIN/uv"
elif command -v uv >/dev/null; then UV="$(command -v uv)"
else
  say "installing uv into $BIN"
  curl -fsSL https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="$BIN" UV_NO_MODIFY_PATH=1 sh >/dev/null
  UV="$BIN/uv"
fi
ok "uv $("$UV" --version | cut -d' ' -f2)"

# ── 2 + 3. wss-bridge and chrome-cdp-mcp, checked against SHA256SUMS ───────
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
curl -fsSL "$BASE/SHA256SUMS" -o "$TMP/SHA256SUMS"
mkdir -p "$TMP/dl" "$TMP/pkg"
fetch() {  # fetch NAME DEST: download $BASE/NAME, verify, move to DEST
  local want got
  want="$(awk -v f="$1" '$2==f {print $1}' "$TMP/SHA256SUMS")"
  [ -n "$want" ] || die "$1 is not in $BASE/SHA256SUMS"
  curl -fsSL "$BASE/$1" -o "$TMP/dl/$1"
  got="$(sha256 "$TMP/dl/$1")"
  [ "$got" = "$want" ] || die "$1: checksum mismatch (got $got, want $want)"
  mv "$TMP/dl/$1" "$2"
}

say "installing wss-bridge"
fetch "$WHEEL" "$TMP/pkg/$WHEEL"
"$UV" tool install --quiet --force --python 3.12 "$TMP/pkg/$WHEEL" 2>&1 | grep -v -E '^(Installed|Resolved|Prepared|Audited)' >&2 || true
[ -x "$BIN/wss-bridge" ] || die "wss-bridge did not install into $BIN"
ok "wss-bridge"

say "installing chrome-cdp-mcp"
fetch "chrome-cdp-mcp-$OS-$ARCH.tar.xz" "$TMP/pkg/cdp.tar.xz"
tar -xJf "$TMP/pkg/cdp.tar.xz" -C "$TMP/pkg" chrome-cdp-mcp
mv "$TMP/pkg/chrome-cdp-mcp" "$BIN/chrome-cdp-mcp.new"
chmod 755 "$BIN/chrome-cdp-mcp.new"
[ "$OS" = darwin ] && xattr -c "$BIN/chrome-cdp-mcp.new" 2>/dev/null || true
mv -f "$BIN/chrome-cdp-mcp.new" "$BIN/chrome-cdp-mcp"
ok "chrome-cdp-mcp"

# Keep a copy of this script as the relaunch command.
if curl -fsSL "$BASE/$SELF" -o "$TMP/tinker-chrome" 2>/dev/null; then
  install -m 755 "$TMP/tinker-chrome" "$BIN/tinker-chrome"
fi

# ── 4. the separate Chrome ─────────────────────────────────────────────────
cdp_up() { curl -fs --max-time 2 "http://127.0.0.1:$PORT/json/version" >/dev/null 2>&1; }

if cdp_up; then
  if pgrep -f -- "--user-data-dir=$PROFILE" >/dev/null 2>&1; then
    ok "demo Chrome already running on port $PORT"
  else
    die "something else is already listening on 127.0.0.1:$PORT. Re-run with TINKER_CDP_PORT=<another port>."
  fi
else
  say "starting a separate Chrome (own profile, debugging on 127.0.0.1:$PORT)"
  # shellcheck disable=SC2206
  FLAGS=(--user-data-dir="$PROFILE" --remote-debugging-port="$PORT"
         --no-first-run --no-default-browser-check ${TINKER_CHROME_ARGS:-}
         "https://www.google.com/")
  APP="${CHROME%/Contents/MacOS/*}"
  if [ "$OS" = darwin ] && [ "$APP" != "$CHROME" ]; then
    # LaunchServices: a new, fully detached instance beside your own Chrome.
    open -n -a "$APP" --args "${FLAGS[@]}"
  else
    nohup "$CHROME" "${FLAGS[@]}" >"$DATA/chrome.log" 2>&1 &
    disown || true
  fi
  for _ in $(seq 1 40); do cdp_up && break; sleep 0.5; done
  cdp_up || die "Chrome did not open its debugging port; see $DATA/chrome.log"
  ok "demo Chrome is up (a second Chrome icon in the Dock; your own Chrome is untouched)"
fi

[ "${TINKER_NO_BRIDGE:-}" = 1 ] && { ok "TINKER_NO_BRIDGE=1: not starting the bridge"; exit 0; }

# ── 5. token ───────────────────────────────────────────────────────────────
TOKEN="${TINKER_TOKEN:-}"
if [ -z "$TOKEN" ]; then
  [ -r /dev/tty ] || die "no terminal to prompt on; set TINKER_TOKEN"
  printf '\n\033[1mPaste the gateway token\033[0m (input is hidden), then press Return: ' >/dev/tty
  IFS= read -rs TOKEN </dev/tty
  printf '\n' >/dev/tty
fi
TOKEN="$(printf '%s' "$TOKEN" | tr -d '[:space:]')"
[ -n "$TOKEN" ] || die "empty token"
unset TINKER_TOKEN

# ── 6. bridge ──────────────────────────────────────────────────────────────
say "bridging Chrome -> $WSS_URL"
cat >&2 <<EOF

  Leave this window open during the demo.
  Working when the log says "connected" and stays quiet.
  "403" or "invalid bearer token" means the token is wrong: Ctrl-C and run
      ~/.local/bin/tinker-chrome
  Ctrl-C stops the bridge. Quit the separate Chrome when you are done.

EOF
export WSS_BRIDGE_TOKEN="$TOKEN"; unset TOKEN
exec "$BIN/wss-bridge" --wss-url "$WSS_URL" --log-level INFO \
  --cmd "$BIN/chrome-cdp-mcp" --stdio --browser-url="http://127.0.0.1:$PORT"
