#!/usr/bin/env bash
#
# RELAY-PHASE1 · staging bootstrap (mode B — self-signed TLS, no Let's Encrypt yet).
#
# Idempotent one-shot that prepares EVERYTHING the two services need to boot, EXCEPT starting them:
#   1. strong random POSTGRES_PASSWORD + OPERATOR_PASSWORD  (persisted 0600, reused on re-run)
#   2. P5 capability keypair            (deploy/scripts/gen-capability-key.sh)
#   3. private agent-enrollment CA      (deploy/scripts/gen-agent-ca.sh)
#   4. self-signed browser :443 cert    (mode B stand-in for issue-tls-cert.sh)
#   5. /etc/relay/control-plane.env + /etc/relay/relay.env  — the REAL env contract read by the code
#      (control-plane/src/env.ts + relay-run/src/main-phase1.ts), which is a SUPERSET of .env.example:
#        · relay needs AGENT_SERVER_CERT_PATH / AGENT_SERVER_KEY_PATH / ALLOWED_ORIGINS (template omits)
#        · relay hosts the STAGING /auth/mint, so it needs CAPABILITY_SIGN_PRIVKEY (base64 PKCS#8 DER)
#          + MINT_RATE_SALT. In Phase 1 the relay IS a token minter (staging shortcut); Phase 2 = WebAuthn.
#   6. deploy/.env for docker-compose, then `docker compose up -d` Postgres + Redis (loopback-only).
#
# Secrets are generated in place (0600); NOTHING secret is printed except OPERATOR_PASSWORD (once).
# Private keys are NEVER printed. Config via ENV (staging defaults for THIS deploy):
#     BASE_DOMAIN (yaojia.wang)  SUBDOMAIN (kai)  SERVER_IP (8.138.1.192)
#     RELAY_TRUST_DOMAIN (relay.yaojia.wang)  RELAY_NODE_ID (relay-1)  REPO (repo root)
#
# Verify (syntax): bash -n deploy/scripts/bootstrap-staging.sh
set -euo pipefail

BASE_DOMAIN="${BASE_DOMAIN:-yaojia.wang}"
SUBDOMAIN="${SUBDOMAIN:-kai}"
SERVER_IP="${SERVER_IP:-8.138.1.192}"
RELAY_TRUST_DOMAIN="${RELAY_TRUST_DOMAIN:-relay.${BASE_DOMAIN}}"
RELAY_NODE_ID="${RELAY_NODE_ID:-relay-1}"
FQDN="${SUBDOMAIN}.${BASE_DOMAIN}"

# Repo root = two levels up from this script, unless overridden.
SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
REPO="${REPO:-$SELF}"

ETC=/etc/relay
CAP_DIR="${ETC}/capability"
CA_DIR="${ETC}/ca"
TLS_DIR="${ETC}/tls"
SECRETS="${ETC}/secrets.env"

command -v openssl >/dev/null 2>&1 || { echo "FATAL: openssl not on PATH" >&2; exit 3; }
command -v docker  >/dev/null 2>&1 || { echo "FATAL: docker not on PATH"  >&2; exit 3; }

umask 077
mkdir -p "${ETC}" "${TLS_DIR}"

echo "== [1/6] passwords (persisted, reused on re-run) =="
# shellcheck disable=SC1090
[[ -f "${SECRETS}" ]] && source "${SECRETS}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 32)}"
OPERATOR_PASSWORD="${OPERATOR_PASSWORD:-$(openssl rand -base64 18 | tr -dc 'A-Za-z0-9' | head -c 24)}"
MINT_RATE_SALT="${MINT_RATE_SALT:-$(openssl rand -hex 16)}"
{
  echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}"
  echo "OPERATOR_PASSWORD=${OPERATOR_PASSWORD}"
  echo "MINT_RATE_SALT=${MINT_RATE_SALT}"
} > "${SECRETS}"
chmod 600 "${SECRETS}"

echo "== [2/6] P5 capability keypair =="
KEY_DIR="${CAP_DIR}" bash "${REPO}/deploy/scripts/gen-capability-key.sh" > "${ETC}/capability-summary.txt" 2>&1 \
  || { echo "FATAL: gen-capability-key.sh failed:" >&2; cat "${ETC}/capability-summary.txt" >&2; exit 1; }
CAP_B64="$(grep -oE 'CAPABILITY_SIGN_PUBKEY_B64=[^ ]+' "${ETC}/capability-summary.txt" | head -1 | cut -d= -f2-)"
CAP_B64URL="$(grep -oE 'RELAY_AUTH_VERIFY_PUBKEY=[^ ]+' "${ETC}/capability-summary.txt" | head -1 | cut -d= -f2-)"
[[ -n "${CAP_B64}" && -n "${CAP_B64URL}" ]] || { echo "FATAL: could not parse capability pubkeys" >&2; exit 1; }
# The relay ALSO mints operator tokens (staging /auth/mint) → it needs the private key as base64 PKCS#8 DER.
CAP_PRIV_B64="$(openssl pkey -in "${CAP_DIR}/capability-sign.key.pem" -outform DER | base64 | tr -d '\n')"

echo "== [3/6] private agent-enrollment CA (NOT Let's Encrypt) =="
CA_DIR="${CA_DIR}" AGENT_FACING_HOST="${FQDN}" AGENT_FACING_IP="${SERVER_IP}" \
  RELAY_TRUST_DOMAIN="${RELAY_TRUST_DOMAIN}" \
  bash "${REPO}/deploy/scripts/gen-agent-ca.sh" > "${ETC}/ca-summary.txt" 2>&1 \
  || { echo "FATAL: gen-agent-ca.sh failed:" >&2; cat "${ETC}/ca-summary.txt" >&2; exit 1; }

echo "== [4/6] self-signed browser :443 cert for ${FQDN} (mode B) =="
if [[ ! -f "${TLS_DIR}/privkey.pem" ]]; then
  openssl req -x509 -newkey rsa:2048 -nodes -days 825 \
    -keyout "${TLS_DIR}/privkey.pem" -out "${TLS_DIR}/fullchain.pem" \
    -subj "/CN=${FQDN}" -addext "subjectAltName=DNS:${FQDN},IP:${SERVER_IP}"
fi
chmod 600 "${TLS_DIR}/privkey.pem"; chmod 644 "${TLS_DIR}/fullchain.pem"

echo "== [5/6] env files (REAL contract from env.ts + main-phase1.ts) =="
cat > "${ETC}/control-plane.env" <<EOF
PG_URL=postgres://relay:${POSTGRES_PASSWORD}@127.0.0.1:5432/relay
REDIS_URL=redis://127.0.0.1:6379
CAPABILITY_SIGN_PUBKEY_B64=${CAP_B64}
CA_INTERMEDIATE_KMS_KEY_REF=dev-local
CA_INTERMEDIATE_CERT_PATH=${CA_DIR}/intermediate.cert.pem
NODE_MTLS_TRUST_BUNDLE_PATH=${CA_DIR}/agent-ca.bundle.pem
BASE_DOMAIN=${BASE_DOMAIN}
CP_BIND_HOST=127.0.0.1
CP_BIND_PORT=8080
EOF
chmod 600 "${ETC}/control-plane.env"

cat > "${ETC}/relay.env" <<EOF
BIND_HOST=0.0.0.0
BIND_PORT=443
AGENT_BIND_PORT=8444
TLS_CERT_PATH=${TLS_DIR}/fullchain.pem
TLS_KEY_PATH=${TLS_DIR}/privkey.pem
AGENT_SERVER_CERT_PATH=${CA_DIR}/relay-agent-server.cert.pem
AGENT_SERVER_KEY_PATH=${CA_DIR}/relay-agent-server.key.pem
AGENT_CA_CERT_PATH=${CA_DIR}/agent-ca.cert.pem
AGENT_CA_CHAIN_PATH=${CA_DIR}/agent-ca.bundle.pem
BASE_DOMAIN=${BASE_DOMAIN}
RELAY_NODE_ID=${RELAY_NODE_ID}
RELAY_TRUST_DOMAIN=${RELAY_TRUST_DOMAIN}
ALLOWED_ORIGINS=https://${FQDN}
PG_URL=postgres://relay:${POSTGRES_PASSWORD}@127.0.0.1:5432/relay
REDIS_URL=redis://127.0.0.1:6379
RELAY_AUTH_VERIFY_PUBKEY=${CAP_B64URL}
OPERATOR_PASSWORD=${OPERATOR_PASSWORD}
CAPABILITY_SIGN_PRIVKEY=${CAP_PRIV_B64}
MINT_RATE_SALT=${MINT_RATE_SALT}
EOF
chmod 600 "${ETC}/relay.env"

echo "== [6/6] docker compose up -d (Postgres + Redis, loopback-only) =="
cat > "${REPO}/deploy/.env" <<EOF
POSTGRES_DB=relay
POSTGRES_USER=relay
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
EOF
chmod 600 "${REPO}/deploy/.env"
docker compose --env-file "${REPO}/deploy/.env" -f "${REPO}/deploy/docker-compose.yml" up -d

cat <<SUMMARY

=== bootstrap OK ===
FQDN                : ${FQDN}
capability pubkey   : b64 ${#CAP_B64} chars / b64url ${#CAP_B64URL} chars (same 32 bytes)
env files (0600)    : ${ETC}/control-plane.env  ${ETC}/relay.env
OPERATOR_PASSWORD   : ${OPERATOR_PASSWORD}    <-- browser login; shown once, also in ${SECRETS} (0600)

Next: start control-plane + relay, then mint a manage token to create an account + pairing code.
SUMMARY
