#!/usr/bin/env bash
# SPV SETUP · login session · all-on · BGS BGF secure · standalone + API
# Law: BGS → BGF(+EZZIE PHI THERMO ADJOIN) → BGL → SDF · SPV free
# 127 only · free thrift · Always Hostess 7 · never ML · datacenter virus stays DOWN
set -u
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/out"
KATE="$ROOT/KateRTX"
EMP="${BGRTX_EMP:-$HOME/Projects/grok-employee/www/kate}"
STORE="${BGRTX_STORAGE:-$HOME/Desktop/BigGrinStorage}"
CFG="${XDG_CONFIG_HOME:-$HOME/.config}/biggrinrtx"
export SUDO_PASS="${SUDO_PASS:-mememe}"
export SUDO_ASKPASS="${SUDO_ASKPASS:-$ROOT/Build/sudo-askpass.sh}"
export DISPLAY="${DISPLAY:-:0}"
mkdir -p "$OUT" "$STORE/secrets" "$STORE/slots" "$STORE/out" "$CFG"

cmd="${1:-all}"
ts() { date -Iseconds; }
say() { echo "[$(ts)] $*"; }

# ── BGS / BGF / SPV free pure marks (no side engines) ──
bgf() { echo $(( ($1 - $2) | 1 )); }
bgs() { if (( ${1:-0} == 0 )); then echo $((7|1)); else echo $(( ${1} | 1 )); fi; }
bgl() { echo $(( ${1:-0} | 1 )); }
ezzie() { echo $(( ($1 ^ $2) | 1 )); }
phi() { echo $(( ($1 * $2) | 1 )); }
thermo() {
  local t=${1//[^0-9-]/}; t=${t:-0}
  if (( t <= 70 )); then echo $((0|1)); elif (( t <= 84 )); then echo $((1|1)); else echo $((2|1)); fi
}
spv() { echo $(( (${1:-0} ^ ${2:-0} ^ ${3:-0}) | 1 )); }

live_atoms() {
  local mf mc m tC at_ez at_phi at_th free_spv pub
  mf=$(awk '/^MemFree:/{print $2;exit}' /proc/meminfo)
  mc=$(awk '/^Cached:/{print $2;exit}' /proc/meminfo)
  m=$(bgf "$mf" "$mc")
  tC=30
  [[ -r /sys/class/thermal/thermal_zone0/temp ]] && tC=$(( $(cat /sys/class/thermal/thermal_zone0/temp)/1000 )) || true
  at_ez=$(ezzie "$mf" "$mc")
  at_phi=$(phi "$m" 1)
  at_th=$(thermo "$tC")
  free_spv=$(spv "$at_ez" "$at_phi" "$at_th")
  pub=$(ss -ltn 2>/dev/null | awk 'NR>1 && $4 !~ /127\.|::1/ {c++} END{print c+0}')
  cat <<JSON
{
  "ts": "$(ts)",
  "bgs": {"know_her": $(bgs 0), "field_one": $(bgs 1)},
  "bgf": $m,
  "bgl": $(bgl $((pub==0?1:0))),
  "atoms": {"EZZIE": $at_ez, "PHI": $at_phi, "THERMO": $at_th, "temp_C": $tC},
  "spv_free": $free_spv,
  "public_listen": $pub,
  "line": "BGS → BGF(+EZZIE PHI THERMO ADJOIN) → BGL → SDF · SPV free"
}
JSON
}

ensure_login() {
  say "LOGIN · identity + private storage (non-exec)"
  # identity from desk config (mail desk id) · never print secrets
  local idf="$CFG/identity.json"
  local sess="$OUT/spv_login_session.json"
  local email="biggrin@biggrinrtx.com"
  local name="Big Grin"
  if [[ -f "$idf" ]]; then
    email=$(python3 -c "import json;d=json.load(open('$idf'));print(d.get('user') or d.get('address') or 'biggrin@biggrinrtx.com')" 2>/dev/null || echo "$email")
    name=$(python3 -c "import json;d=json.load(open('$idf'));print(d.get('from_name') or 'Big Grin')" 2>/dev/null || echo "$name")
  fi
  # storage law + empty key placeholder only if missing (never invent API keys)
  [[ -f "$STORE/storage.spvdata" ]] || cat >"$STORE/storage.spvdata" <<'MAN'
{
  "format": "bgrtx.storage.spvdata.v1",
  "executable": false,
  "title": "Big Grin Storage",
  "brand": "Big Grin",
  "demo": "grokman",
  "stores": [
    {"id":"xai_api_key","path":"secrets/xai.key","kind":"secret_file","never_embed":true,"shared":false},
    {"id":"desk_notes","path":"slots/notes.txt","kind":"text","shared":false}
  ],
  "law": "NON-EXECUTABLE storage · secrets never execute · Desktop private"
}
MAN
  chmod 600 "$STORE/storage.spvdata" 2>/dev/null || true
  touch "$STORE/slots/notes.txt"
  chmod 600 "$STORE/slots/notes.txt" 2>/dev/null || true
  # key presence (do not create fake keys)
  local key_desk=0 key_cfg=0
  [[ -s "$STORE/secrets/xai.key" ]] && key_desk=1
  [[ -s "$CFG/xai.key" ]] && key_cfg=1
  if [[ $key_desk -eq 0 && $key_cfg -eq 0 && -n "${XAI_API_KEY:-}" ]]; then
    # only if env already holds key · write private desktop secret
    umask 077
    printf '%s\n' "$XAI_API_KEY" >"$STORE/secrets/xai.key"
    chmod 600 "$STORE/secrets/xai.key"
    key_desk=1
    say "LOGIN · wrote Desktop private xai.key from env (mode 600)"
  fi
  [[ -f "$STORE/secrets/xai.key" ]] && chmod 600 "$STORE/secrets/xai.key" 2>/dev/null || true
  # session stamp (no secret values)
  python3 - <<PY
import json
from pathlib import Path
from datetime import datetime
out = {
  "ts": datetime.now().astimezone().isoformat(timespec="seconds"),
  "word": "SPV_LOGIN",
  "logged_in": True,
  "user": ${email@Q},
  "name": ${name@Q},
  "identity": "desk",
  "storage": str(Path(${STORE@Q})),
  "storage_non_exec": True,
  "xai_key_desktop": bool($key_desk),
  "xai_key_config": bool($key_cfg),
  "grok_ready": bool($key_desk or $key_cfg),
  "contain": "Build/spv-curl-contain.sh",
  "spv_shell": "http://127.0.0.1/kate/?session=1&all=1",
  "home_api": "http://127.0.0.1:18773/",
  "desk_rest": "http://127.0.0.1:18772/",
  "law": "login = desk identity + private storage · Grok key optional private file · never embed",
}
Path(${sess@Q}).write_text(json.dumps(out, indent=2) + "\n")
print("login session →", ${sess@Q}, "grok_ready=", out["grok_ready"])
PY
}

sync_spv_tree() {
  say "SYNC · KateRTX SPVs → employee /kate + shell"
  mkdir -p "$EMP/spvs" "$EMP/icons/spv" "$KATE/out"
  # shell
  if [[ -f "$KATE/out/spv-shell.html" ]]; then
    cp -f "$KATE/out/spv-shell.html" "$EMP/index.html"
  fi
  # plugins + plugs
  if [[ -f "$KATE/spvs/plugins.json" ]]; then
    cp -f "$KATE/spvs/plugins.json" "$EMP/plugins.json"
  fi
  rsync -a --delete --exclude 'plugins.json' "$KATE/spvs/" "$EMP/spvs/" 2>/dev/null \
    || cp -f "$KATE/spvs/"*.js "$KATE/spvs/"*.dom.html "$EMP/spvs/" 2>/dev/null || true
  if [[ -d "$KATE/icons/spv" ]]; then
    rsync -a "$KATE/icons/spv/" "$EMP/icons/spv/" 2>/dev/null || cp -f "$KATE/icons/spv/"* "$EMP/icons/spv/" 2>/dev/null || true
  fi
  # ensure readable
  chmod -R a+rX "$EMP" 2>/dev/null || true
  say "SYNC · plugs js=$(ls "$EMP/spvs"/*.js 2>/dev/null | wc -l)"
}

all_on_session() {
  say "ALL-ON · write SPV session catalog"
  python3 - <<'PY'
import json
from pathlib import Path
from datetime import datetime

root = Path("/home/default/Projects/x")
kate = root / "KateRTX"
emp = Path.home() / "Projects/grok-employee/www/kate"
plugins_path = kate / "spvs" / "plugins.json"
if not plugins_path.is_file():
    plugins_path = emp / "plugins.json"
plugs = []
priority = []
if plugins_path.is_file():
    d = json.loads(plugins_path.read_text())
    plugs = d.get("plugs") or []
    priority = d.get("priority") or []

# heavy plugs stay off by default (user can ON manually) · thrash / long media
HEAVY = {
    "mp4", "nv_mp4", "rtmp", "mqtt", "santa", "serial",
    "zero2d_front", "zero2d_side", "zero2d_over_shoulder",
}
SYSTEM = {
    "antivirus", "curl_contain", "grok_spv", "biggrin_storage",
    "measure", "term", "os_desktop", "scar",
}
# always prefer these first · no BlueAV · Grok SPV antivirus on demand
FORCE = [
    "iron_pins", "curl_contain", "grok_spv", "biggrin_storage",
    "antivirus", "ezzie", "phi", "thermo", "zero2d", "grin", "kate",
    "dns", "term", "measure", "css_all", "html5_all", "js_all",
]

ids = []
seen = set()
for p in plugs:
    i = p.get("id")
    if not i or i in seen:
        continue
    seen.add(i)
    ids.append(i)
# add js stems missing from catalog
for p in sorted((kate / "spvs").glob("*.js")):
    if p.stem not in seen:
        ids.append(p.stem)
        seen.add(p.stem)

on = []
off_heavy = []
for i in ids:
    if i in HEAVY:
        off_heavy.append(i)
    else:
        on.append(i)

# stable order: FORCE then priority then rest
ordered = []
for i in FORCE + priority + on:
    if i in on and i not in ordered:
        ordered.append(i)

session = {
    "ts": datetime.now().astimezone().isoformat(timespec="seconds"),
    "word": "SPV_SESSION",
    "mode": "all_on",
    "logged_in": True,
    "on": ordered,
    "off_heavy": off_heavy,
    "system": sorted(SYSTEM & set(ordered)),
    "core": [i for i in ordered if i not in SYSTEM],
    "counts": {"on": len(ordered), "heavy_off": len(off_heavy), "total": len(ids)},
    "shell": "http://127.0.0.1/kate/?session=1&all=1",
    "law": "ON all light+system SPVs · heavy media left OFF · BGS→BGF→BGL→SDF · SPV free",
}
out = root / "out" / "spv_session.json"
out.write_text(json.dumps(session, indent=2) + "\n")
# also mirror for kate home api
(kate / "out" / "spv_session.json").write_text(json.dumps(session, indent=2) + "\n")
# update plugins default_on flags for shell pretick
if plugins_path.is_file():
    d = json.loads(plugins_path.read_text())
    on_set = set(ordered)
    for p in d.get("plugs") or []:
        p["default_on"] = p.get("id") in on_set
    d["session"] = {
        "mode": "all_on",
        "on_n": len(ordered),
        "shell_query": "?session=1&all=1",
    }
    d["priority"] = [i for i in FORCE if i in on_set] + [i for i in (d.get("priority") or []) if i in on_set and i not in FORCE]
    text = json.dumps(d, indent=2) + "\n"
    plugins_path.write_text(text)
    emp_p = emp / "plugins.json"
    emp_p.parent.mkdir(parents=True, exist_ok=True)
    emp_p.write_text(text)
print(f"session on={len(ordered)} heavy_off={len(off_heavy)} → {out}")
PY
}

start_home_api() {
  say "HOME-API · standalone KateRTX :18773"
  if curl -fsS --max-time 1 http://127.0.0.1:18773/status >/dev/null 2>&1; then
    say "HOME-API already up"
    return 0
  fi
  nohup python3 "$KATE/bin/krtx-home-api" >>"$KATE/out/home-api.log" 2>&1 &
  echo $! >"$KATE/out/home-api.pid"
  for i in 1 2 3 4 5 6 7 8 9 10; do
    curl -fsS --max-time 1 http://127.0.0.1:18773/status >/dev/null 2>&1 && break
    sleep 0.15
  done
  say "HOME-API http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 2 http://127.0.0.1:18773/status 2>/dev/null || echo 000)"
}

ensure_desk_rest() {
  if ! curl -fsS --max-time 1 http://127.0.0.1:18772/status >/dev/null 2>&1; then
    [[ -x "$ROOT/Build/desk-rest.sh" ]] && bash "$ROOT/Build/desk-rest.sh" start || true
  fi
  say "DESK-REST http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 2 http://127.0.0.1:18772/status 2>/dev/null || echo 000)"
}

run_secure_stack() {
  say "SECURE · BGL + secure-all + hunter once · datacenter virus DOWN"
  systemctl stop bgrtx-datacenter.service 2>/dev/null || true
  systemctl mask bgrtx-datacenter.service 2>/dev/null || true
  systemctl stop bgs-bgf-always.service 2>/dev/null || true
  # BGS BGF cover measure (fast path · not full always thrash)
  if [[ -x "$ROOT/Build/cover.sh" ]]; then
    bash "$ROOT/Build/cover.sh" measure 2>&1 | tail -20 || true
  fi
  if [[ -x "$ROOT/Build/bgl-secure.sh" ]]; then
    BGL_SKIP_SCAN=1 bash "$ROOT/Build/bgl-secure.sh" 2>&1 | tail -25 || true
  fi
  if [[ -x "$ROOT/Build/secure-all.sh" ]]; then
    bash "$ROOT/Build/secure-all.sh" 2>&1 | tail -30 || true
  fi
  if [[ -x "$ROOT/Build/scar-cook.sh" ]]; then
    bash "$ROOT/Build/scar-cook.sh" check 2>&1 | tail -15 || true
  fi
  # linear · Grok AV on demand · no stamp · no forever · no hunter
  live_atoms >"$OUT/bgs_bgf_live.json"
  cp -f "$OUT/bgs_bgf_live.json" "$KATE/out/bgs_bgf_live.json" 2>/dev/null || true
  say "BGS/BGF live → out/bgs_bgf_live.json"
}

write_bundle() {
  python3 - <<'PY'
import json
from pathlib import Path
from datetime import datetime
root = Path("/home/default/Projects/x")
out = root / "out"
def load(n):
    p = out / n
    if p.is_file():
        try:
            return json.loads(p.read_text())
        except Exception:
            return {"raw": p.read_text()[:200]}
    return None
bundle = {
    "ts": datetime.now().astimezone().isoformat(timespec="seconds"),
    "word": "SPV_SETUP",
    "login": load("spv_login_session.json"),
    "session": load("spv_session.json"),
    "bgs_bgf": load("bgs_bgf_live.json"),
    "secure_all": load("secure_all_latest.json") or load("secure_all.json"),
    "scar": load("scar_check_latest.json"),
    "ports": {
        "desk_rest": "http://127.0.0.1:18772/",
        "home_api": "http://127.0.0.1:18773/",
        "spv_shell": "http://127.0.0.1/kate/?session=1&all=1",
        "mail": "http://127.0.0.1:18770/",
    },
    "law": "BGS→BGF→BGL→SDF · SPV free · desk AV active · datacenter virus DOWN",
}
(out / "spv_setup_latest.json").write_text(json.dumps(bundle, indent=2) + "\n")
print(json.dumps({"ok": True, "on": (bundle.get("session") or {}).get("counts"), "grok_ready": (bundle.get("login") or {}).get("grok_ready"), "shell": bundle["ports"]["spv_shell"]}, indent=2))
PY
}

case "$cmd" in
  login) ensure_login ;;
  sync) sync_spv_tree ;;
  all-on|allon) all_on_session ;;
  secure) run_secure_stack ;;
  api|home-api) start_home_api; ensure_desk_rest ;;
  atoms|bgs-bgf) live_atoms | tee "$OUT/bgs_bgf_live.json" ;;
  status)
    cat "$OUT/spv_setup_latest.json" 2>/dev/null || echo '{"ok":false,"error":"run once first"}'
    ;;
  all|once|setup|"")
    ensure_login
    sync_spv_tree
    all_on_session
    ensure_desk_rest
    start_home_api
    run_secure_stack
    write_bundle
    say "DONE · open http://127.0.0.1/kate/?session=1&all=1"
    ;;
  *)
    echo "usage: $0 all|login|sync|all-on|secure|api|bgs-bgf|status" >&2
    exit 2
    ;;
esac
