#!/usr/bin/env bash
# seat-launcher — runs inside agent-seat-*.scope + seat netns as per-seat implementer (ods-<seat-id>).
set -euo pipefail

state_dir=""
seat_id=""
seat_host=""
model=""

if [ -n "${OVERDECK_SEAT_ID:-}" ] && [ -n "${OVERDECK_SEAT_HOST:-}" ] && [ -n "${OVERDECK_SEAT_MODEL:-}" ]; then
  seat_id="$OVERDECK_SEAT_ID"
  seat_host="$OVERDECK_SEAT_HOST"
  model="$OVERDECK_SEAT_MODEL"
  state_dir="${OVERDECK_SEAT_STATE_DIR:-$HOME/.local/state/overdeck/seats/${seat_id}}"
fi

env_json="${state_dir}/trusted-config/seat-env.json"
if [ -f "$env_json" ]; then
  while IFS= read -r -d '' kv; do
    key=${kv%%=*}
    val=${kv#*=}
    export "$key=$val"
  done < <(python3 -c '
import json, sys
CONTROL = set(range(0, 9)) | {11, 12} | set(range(14, 32)) | {127}
ALLOW = {
  "PATH", "HOME", "USER", "LOGNAME", "SHELL", "LANG", "LC_ALL", "LC_CTYPE", "LC_MESSAGES", "TERM",
  "CLAUDE_CONFIG_DIR", "CLAUDE_SECURESTORAGE_CONFIG_DIR", "SYSTRAY_CLAUDE_ACCOUNT_HOME",
  "SYSTRAY_CLAUDE_ACCOUNT_SLUG", "OVERDECK_SEAT_HOST", "OVERDECK_SEAT_ID", "OVERDECK_SEAT_MODEL",
  "ANTHROPIC_BASE_URL", "OVERDECK_CLAUDE_BIN", "OVERDECK_SEAT_GUARD_BIN", "OVERDECK_SEAT_CHECKOUT",
  "OVERDECK_SEAT_STATE_DIR",
}
DENY = {
  "ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "OPENAI_API_KEY", "CCP_CONFIG_DIR", "CCP_BIND_ADDRESS",
  "CCP_CODEX_MODEL", "CCP_CODEX_SERVICE_TIER", "ANTHROPIC_MODEL", "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY",
  "DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR",
}
path = sys.argv[1]
with open(path, encoding="utf-8") as fh:
    data = json.load(fh)
if not isinstance(data, dict):
    raise SystemExit("seat-env-not-object")
seen = set()
for key, value in data.items():
    if key in seen:
        raise SystemExit(f"seat-env-duplicate:{key}")
    seen.add(key)
    if key not in ALLOW or key in DENY:
        raise SystemExit(f"seat-env-reject:{key}")
    if not isinstance(value, str):
        raise SystemExit(f"seat-env-type:{key}")
    if any(ord(ch) in CONTROL for ch in value):
        raise SystemExit(f"seat-env-control:{key}")
    sys.stdout.write(key)
    sys.stdout.write("=")
    sys.stdout.write(value)
    sys.stdout.write("\0")
' "$env_json")
fi

if [ -z "$seat_id" ] && [ -n "${OVERDECK_SEAT_ID:-}" ]; then seat_id="$OVERDECK_SEAT_ID"; fi
if [ -z "$seat_host" ] && [ -n "${OVERDECK_SEAT_HOST:-}" ]; then seat_host="$OVERDECK_SEAT_HOST"; fi
if [ -z "$model" ] && [ -n "${OVERDECK_SEAT_MODEL:-}" ]; then model="$OVERDECK_SEAT_MODEL"; fi
if [ -z "$state_dir" ] && [ -n "${OVERDECK_SEAT_STATE_DIR:-}" ]; then state_dir="$OVERDECK_SEAT_STATE_DIR"; fi
if [ -z "$state_dir" ] && [ -n "$seat_id" ]; then state_dir="$HOME/.local/state/overdeck/seats/${seat_id}"; fi

if [ -z "$seat_id" ] || [ -z "$seat_host" ] || [ -z "$model" ]; then
  echo "seat-launcher: missing OVERDECK_SEAT_ID/HOST/MODEL" >&2
  exit 2
fi

netns_name="overdeck-seat-${seat_id}"
netns_path="/var/run/netns/${netns_name}"

if [ ! -e "$netns_path" ]; then
  echo "seat-launcher: seat netns missing ($netns_path)" >&2
  exit 2
fi

identified=$(ip netns identify 2>/dev/null || true)
if [ "$identified" != "$netns_name" ]; then
  echo "seat-launcher: not in seat netns (got ${identified:-none}, want $netns_name)" >&2
  exit 2
fi

guard_bin="${OVERDECK_SEAT_GUARD_BIN:-}"
trusted_dir="$state_dir/trusted-config"
settings="$trusted_dir/seat-settings.json"
mcp_config="$trusted_dir/empty-mcp.json"
forwarded_json="$trusted_dir/claude-forwarded.json"
claude_bin="${OVERDECK_CLAUDE_BIN:-}"
checkout="${OVERDECK_SEAT_CHECKOUT:-}"

if [ -z "$claude_bin" ] || [ ! -x "$claude_bin" ]; then
  echo "seat-launcher: claude binary missing (OVERDECK_CLAUDE_BIN)" >&2
  exit 127
fi
if [ -z "$guard_bin" ] || [ ! -d "$guard_bin" ]; then
  echo "seat-launcher: seat guard missing (OVERDECK_SEAT_GUARD_BIN)" >&2
  exit 2
fi
if [ -z "$checkout" ] || [ ! -d "$checkout" ]; then
  echo "seat-launcher: checkout missing (OVERDECK_SEAT_CHECKOUT)" >&2
  exit 2
fi

if [ ! -f "$settings" ] || [ ! -f "$mcp_config" ] || [ ! -f "$forwarded_json" ] || [ ! -f "$env_json" ]; then
  echo "seat-launcher: seat artifacts missing under $trusted_dir" >&2
  exit 2
fi

unset DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR \
  ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN OPENAI_API_KEY \
  CCP_CONFIG_DIR CCP_BIND_ADDRESS CCP_CODEX_MODEL CCP_CODEX_SERVICE_TIER \
  ANTHROPIC_MODEL CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY

export PATH="${guard_bin}:${PATH:-/usr/bin:/bin}"
export OVERDECK_SEAT_ID="$seat_id"
export OVERDECK_SEAT_HOST="$seat_host"
export OVERDECK_SEAT_MODEL="$model"
export OVERDECK_SEAT_STATE_DIR="$state_dir"

cd "$checkout"

mapfile -t forwarded < <(python3 -c '
import json, sys
CONTROL = set(range(0, 9)) | {11, 12} | set(range(14, 32)) | {127}
DENY_EXACT = {
  "--model", "--fallback-model", "--settings", "--setting-sources", "--disallowedTools", "--allowedTools",
  "--disallowed-tools", "--allowed-tools", "--tools",
  "--agents", "--strict-mcp-config", "--mcp-config", "--plugin", "--plugins", "--plugin-dir", "--plugin-url",
  "--marketplace",
  "--enable-workflows", "--enable-workflow", "--agent", "--workflow", "Agent", "Workflow",
}
DENY_PREFIX = (
  "--model=", "--fallback-model=", "--settings=", "--setting-sources=", "--disallowedTools=",
  "--allowedTools=", "--disallowed-tools=", "--allowed-tools=", "--tools=",
  "--agents=", "--strict-mcp-config=", "--mcp-config=", "--plugin=", "--plugins=", "--plugin-dir=", "--plugin-url=",
  "--marketplace=",
  "--enable-workflows=", "--enable-workflow=", "--agent=", "--workflow=",
)
path = sys.argv[1]
with open(path, encoding="utf-8") as fh:
    data = json.load(fh)
if not isinstance(data, list):
    raise SystemExit("forwarded-not-array")
for idx, item in enumerate(data):
    if not isinstance(item, str):
        raise SystemExit(f"forwarded-not-string:{idx}")
    if any(ord(ch) in CONTROL for ch in item):
        raise SystemExit(f"forwarded-control:{idx}")
    if item in DENY_EXACT:
        raise SystemExit(f"forwarded-deny:{item}")
    for prefix in DENY_PREFIX:
        if item.startswith(prefix):
            raise SystemExit(f"forwarded-deny:{item}")
    print(item)
' "$forwarded_json")

claude_argv=(
  "$claude_bin"
  --model "$model"
  --settings "$settings"
  --setting-sources ""
  --disallowedTools Agent Workflow
  --agents '{}'
  --strict-mcp-config
  --mcp-config "$mcp_config"
)

for arg in "${forwarded[@]}"; do
  claude_argv+=("$arg")
done

model_count=0
for arg in "${claude_argv[@]}"; do
  if [ "$arg" = "--model" ] || [[ "$arg" == --model=* ]]; then model_count=$((model_count + 1)); fi
done
if [ "$model_count" -ne 1 ]; then
  echo "seat-launcher: expected exactly one --model" >&2
  exit 2
fi

exec "${claude_argv[@]}"
