#!/usr/bin/env bash
# BigGrinRTX business · Spectrum circuit · public IP may churn · free thrift
# Keeps desk mesh healthy without assuming a fixed public A record.
# Public brand stays on WordPress.com + Titan · desk private on WG/Tailscale.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/out"
VPN="$HOME/.config/bgrtx-vpn"
mkdir -p "$OUT" "$VPN"
TS() { date -Iseconds; }

# --- public IPv4 (best effort · may fail offline) ---
ip4=""
for u in https://ifconfig.me https://icanhazip.com https://api.ipify.org; do
  ip4=$(curl -4 -fsS -m 5 "$u" 2>/dev/null | tr -d '[:space:]' || true)
  [[ "$ip4" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && break
  ip4=""
done
prev=""
[[ -f "$OUT/PUBLIC_IP.txt" ]] && prev=$(cat "$OUT/PUBLIC_IP.txt" | tr -d '[:space:]')

if [[ -n "$ip4" ]]; then
  echo "$ip4" >"$OUT/PUBLIC_IP.txt"
  changed=0
  [[ "$ip4" != "$prev" ]] && changed=1
else
  ip4="${prev:-unknown}"
  changed=0
  echo "$(TS) warn: could not fetch public IP · kept $ip4" >>"$OUT/dyndns.log"
fi

# --- regenerate WireGuard client Endpoint with current IP (if known) ---
if [[ -f "$VPN/server_public.key" && -f "$VPN/client_private.key" && "$ip4" != "unknown" ]]; then
  SERVER_PUB=$(cat "$VPN/server_public.key")
  CLIENT_PRIV=$(cat "$VPN/client_private.key")
  cat >"$VPN/client-phone-laptop.conf" <<WGEOF
# BigGrinRTX WireGuard · business mesh · IP churn OK · free thrift
# Import into WireGuard app. Re-import after big IP change, or run:
#   bash ~/Projects/x/Build/bgrtx-dyndns.sh
# Then pull this file again (or sync via Tailscale).
#
# After connect, open:
#   http://10.66.66.1/          (Host: email / grok / h7)
#   http://email.biggrinrtx.com  (if phone hosts/DNS → 10.66.66.1)
#   http://grok.biggrinrtx.com
#   http://h7.biggrinrtx.com
#
# Endpoint uses current public IP at generation time: $ip4
# Router: UDP 51820 → desk (optional; LAN works without it)

[Interface]
Address = 10.66.66.2/32
PrivateKey = $CLIENT_PRIV
DNS = 1.1.1.1

[Peer]
PublicKey = $SERVER_PUB
Endpoint = ${ip4}:51820
AllowedIPs = 10.66.66.0/24
PersistentKeepalive = 25
WGEOF
  chmod 600 "$VPN/client-phone-laptop.conf"
fi

# --- status JSON for health / humans ---
python3 - "$OUT" "$ip4" "$changed" <<'PY'
import json, sys, time
from pathlib import Path
out, ip4, changed = Path(sys.argv[1]), sys.argv[2], sys.argv[3] == "1"
status = {
  "ts": time.strftime("%Y-%m-%dT%H:%M:%S"),
  "public_ip": ip4,
  "ip_changed": changed,
  "law": "BigGrinRTX business · Spectrum circuit · free thrift legal · WG me",
  "public_brand": {
    "magazine": "https://biggrinrtx.com/",
    "email_entry": "https://biggrinrtx.com/email/",
    "mailbox_transport": "Titan IMAP/SMTP",
  },
  "desk_private": {
    "wireguard": "10.66.66.1/24 · bgrtx0",
    "email": "http://email.biggrinrtx.com/ (via hosts or mesh DNS)",
    "office": "http://grok.biggrinrtx.com/",
    "hostess7": "http://h7.biggrinrtx.com/",
    "client_conf": "~/.config/bgrtx-vpn/client-phone-laptop.conf",
  },
  "do_not": [
    "A-record email/grok/h7 to home IP as primary public host (ToS + IP churn)",
    "depend on fixed 71.x A records",
  ],
  "prefer": [
    "WordPress.com for public magazine",
    "Titan webmail for public send/receive anywhere",
    "WireGuard or Tailscale for Grok's Claws + office on the desk",
    "optional Cloudflare Tunnel later if Claws must be on public hostname without port-forward",
  ],
}
(out / "cohost_status.json").write_text(json.dumps(status, indent=2) + "\n")
print(json.dumps({"ts": status["ts"], "public_ip": ip4, "ip_changed": changed}, indent=2))
PY

echo "$(TS) ip=$ip4 changed=$changed" >>"$OUT/dyndns.log"
# keep log short
tail -n 200 "$OUT/dyndns.log" >"$OUT/dyndns.log.tmp" 2>/dev/null && mv "$OUT/dyndns.log.tmp" "$OUT/dyndns.log" || true
