#!/usr/bin/env bash
# blender-mcp — the agent side of fv-ml1's Blender (stacks/blender). Prime, 2026-09-27.
#
#   scripts/blender-mcp            serve MCP over stdio (what an MCP client launches)
#   scripts/blender-mcp up|down    start / stop the Blender container (GPU 3 is borrowed: on demand)
#   scripts/blender-mcp status     is the container up, and does the add-on answer a ping?
#   scripts/blender-mcp setup      (re)build the in-container MCP venv from the pinned requirements
#
# Shape: the MCP server (mcp-for-blender 2.1.1, pinned in stacks/blender/conf/mcp-requirements.txt)
# runs INSIDE the Blender container, and this script carries its stdio over
# `ssh … docker exec -i`. Why it runs there rather than here:
#   - The add-on socket executes arbitrary Python with NO auth. Beside the server it stays on the
#     container's localhost, with no port published anywhere. Access = ssh to fv-ml1 + docker.
#   - get_viewport_screenshot has Blender write a file that the MCP server then reads, so the two
#     must share a filesystem. With the server on nh3-dev it failed: "Screenshot file was not created".
# Telemetry is off. SAFE MODE is on: model-written code must clear upstream's AST allowlist before it
# reaches Blender. It guards against prompt injection from third-party asset text; it is not a sandbox.
#
# ⚠ `serve` does NOT start Blender. An MCP client launches this at session start, and auto-starting
#   would put Blender on the reserve card for every session. If Blender is down, `serve` exits with
#   a message: run `up`, wait for `status` to answer, then reconnect the MCP server.
set -euo pipefail

HOST=${BLENDER_SSH_HOST:-infra-ops@10.251.50.54}
COMPOSE_DIR=/opt/docker/compose/blender
VENV=/work/.mcp-venv
REQS=/opt/docker/conf/blender/mcp-requirements.txt
SSH=(ssh -o BatchMode=yes -o ConnectTimeout=10 "$HOST")

# ⚠ -n on every ssh except the serving one: without it, this pre-flight ssh swallows the MCP
#   client's `initialize` from stdin, and the session hangs at init (found 2026-09-27).
running() { [ "$(ssh -n -o BatchMode=yes -o ConnectTimeout=10 "$HOST" "docker inspect -f '{{.State.Running}}' blender 2>/dev/null")" = true ]; }

case "${1:-serve}" in
  up)
    "${SSH[@]}" "cd $COMPOSE_DIR && docker compose up -d" >&2
    echo "blender: starting; the add-on answers once the desktop has loaded (~20-40 s). Check: $0 status" >&2 ;;
  down)
    "${SSH[@]}" "cd $COMPOSE_DIR && docker compose down" >&2 ;;
  status)
    # ⚠ Not a TCP probe: a port can accept while Blender is still loading. Ask the add-on to ping.
    "${SSH[@]}" "docker ps -a --filter name=^blender\$ --format 'container: {{.Status}}'; \
      docker exec -u abc blender python3 -c '
import json, socket
try:
    s = socket.create_connection((\"localhost\", 9876), 3); s.settimeout(5)
    s.sendall(json.dumps({\"type\": \"ping\"}).encode())
    ok = json.loads(s.recv(4096)).get(\"status\") == \"success\"
except Exception:
    ok = False
print(\"mcp add-on: answering\" if ok else \"mcp add-on: not answering\")
' 2>/dev/null || echo 'mcp add-on: container not running'" ;;
  setup)
    running || { echo "blender-mcp: container is down; run '$0 up' first" >&2; exit 1; }
    "${SSH[@]}" "docker exec -u abc blender sh -c 'rm -rf $VENV.new && python3 -m venv $VENV.new \
      && $VENV.new/bin/pip install -q -r $REQS && rm -rf $VENV && mv $VENV.new $VENV && echo setup: ok'" ;;
  serve)
    if ! running; then
      echo "blender-mcp: Blender is not running on fv-ml1 (GPU 3 is on-demand). Run '$0 up', wait for '$0 status', then reconnect this MCP server." >&2
      exit 1
    fi
    exec "${SSH[@]}" docker exec -i -u abc \
      -e DISABLE_TELEMETRY=true -e BLENDER_MCP_SAFE_MODE=1 \
      -e BLENDER_HOST=localhost -e BLENDER_PORT=9876 \
      blender "$VENV/bin/mcp-for-blender" ;;
  *)
    echo "usage: $0 [serve|up|down|status|setup]" >&2; exit 2 ;;
esac
