#!/bin/bash
# svcboot — Hardened node bootstrap with tmpfs and WireGuard
set -euo pipefail
shopt -s inherit_errexit 2>/dev/null || true
IFS=$'\n\t'

readonly NODE_ID="${NODE_ID:-}"
readonly ENGINE_IP="${ENGINE_IP:-10.69.69.6}"
readonly VAULT_KEY_FILE="${VAULT_KEY_FILE:-/dev/shm/vault.key}"
readonly BOOT_STATE="/run/se/state/boot"
readonly LOG_DIR="/run/se/logs"
readonly CONF="/run/se/.nodeconf"
readonly SE_DIR="/run/se"
readonly WG_IFACE="wg0"
readonly LOCK_FILE="/run/se/.svcboot.lock"

# ── Validate node_id ───────────────────────────────────────────────────────
if [[ -z "${NODE_ID}" ]]; then
    printf 'ERR: NODE_ID not set\n' >&2
    exit 1
fi

# ── Lock ───────────────────────────────────────────────────────────────────
exec 300>"${LOCK_FILE}"
if ! flock -n 300; then
    printf 'ERR: svcboot already running\n' >&2
    exit 1
fi

t006_log() {
    local m="${1:-}"
    logger -t "boot-${NODE_ID}" "${m}" 2>/dev/null || true
    mkdir -p "${LOG_DIR}"
    printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${m}" >> "${LOG_DIR}/boot.log"
}

t006_hmac() {
    local p="${1:-}" k="${2:-}"
    printf '%s' "${p}" | openssl dgst -sha256 -hmac "${k}" -hex | awk '{print $NF}'
}

t006_sign() {
    local method="${1:-POST}" path="${2:-}" body="${3:-}"
    local ts n sig_input s
    ts="$(date +%s)"
    n="$(openssl rand -hex 16)"
    sig_input="${ts}.${n}.${method}.${path}.${body}"
    if [[ -f "${VAULT_KEY_FILE}" ]]; then
        s="$(t006_hmac "${sig_input}" "$(cat "${VAULT_KEY_FILE}")")"
    else
        s='none'
    fi
    printf '%s\n%s\n%s\n' "${ts}" "${n}" "${s}"
}

t006_report() {
    local ev="${1:-}"
    local ts n s body
    body="{\"node\":\"${NODE_ID}\",\"event\":\"${ev}\"}"
    read -r ts n s < <(t006_sign "POST" "/a/security/event" "${body}") || true
    curl -sf --connect-timeout 3 --max-time 10 \
        -X POST "http://${ENGINE_IP}:8301/a/security/event" \
        -H 'Content-Type: application/json' \
        -H "x-engine-ts: ${ts}" \
        -H "x-engine-nonce: ${n}" \
        -H "x-engine-sig: ${s}" \
        -H "x-engine-node: ${NODE_ID}" \
        -d "${body}" \
        2>/dev/null || true
}

# ── Tmpfs mount ────────────────────────────────────────────────────────────
t006_tmpfs() {
    if ! mountpoint -q "${SE_DIR}" 2>/dev/null; then
        mount -t tmpfs -o "size=100m,mode=700,noexec,nosuid,nodev" tmpfs "${SE_DIR}" 2>/dev/null || {
            t006_log 'tmpfs mount failed'
            exit 1
        }
    fi
    mkdir -p "${SE_DIR}/state" "${SE_DIR}/logs"
    chmod 700 "${SE_DIR}" "${SE_DIR}/state" "${SE_DIR}/logs"
    t006_log 'tmpfs mounted'
}

# ── WireGuard init ─────────────────────────────────────────────────────────
t006_wginit() {
    local pk pub pfile cfg
    pfile="${SE_DIR}/wg.${WG_IFACE}.conf"

    if ip link show "${WG_IFACE}" &>/dev/null; then
        t006_log "wg ${WG_IFACE} already up"
        return 0
    fi

    if [[ -f "${pfile}" ]]; then
        cfg="$(cat "${pfile}")"
    else
        pk="$(wg genkey)"
        pub="$(printf '%s' "${pk}" | wg pubkey)"
        # Use proper node-to-IP mapping instead of NODE_ID suffix
        local WG_IP
        case "${NODE_ID}" in
            199335) WG_IP="10.69.69.5" ;;
            244939) WG_IP="10.69.69.3" ;;
            333941) WG_IP="10.69.69.4" ;;
            414342) WG_IP="10.69.69.1" ;;
            558201) WG_IP="10.69.69.2" ;;
            669427) WG_IP="10.69.69.6" ;;
            *)      WG_IP="10.69.69.99"; t006_log "WARN: unknown NODE_ID ${NODE_ID}, using fallback IP" ;;
        esac
        cfg="[Interface]
PrivateKey=${pk}
Address=${WG_IP}/32
ListenPort=51820
"
        printf '%s' "${cfg}" > "${pfile}"
        chmod 600 "${pfile}"
    fi

    ip link add "${WG_IFACE}" type wireguard 2>/dev/null || true
    if ! wg setconf "${WG_IFACE}" "${pfile}" 2>/dev/null; then
        local pkf
        pkf="$(grep 'PrivateKey' "${pfile}" | cut -d= -f2 | tr -d ' ')"
        wg set "${WG_IFACE}" private-key <(printf '%s' "${pkf}")
    fi
    ip link set "${WG_IFACE}" up

    # Set peer with engine pubkey
    local engine_pub
    engine_pub="${ENGINE_PUBKEY:-$(cat "${SE_DIR}/engine.pub" 2>/dev/null || printf '%s' '')}"
    if [[ -n "${engine_pub}" ]]; then
        wg set "${WG_IFACE}" peer "${engine_pub}" endpoint "${ENGINE_IP}:51820" allowed-ips '10.69.69.0/24' persistent-keepalive 25 2>/dev/null || true
    fi
    t006_log "wg ${WG_IFACE} up"
}

# ── Config fetch ───────────────────────────────────────────────────────────
t006_fetchconf() {
    local ts n s r body
    body="{\"node\":\"${NODE_ID}\"}"
    read -r ts n s < <(t006_sign "POST" "/a/nodeconf" "${body}") || true
    r="$(curl -sf --connect-timeout 5 --max-time 15 \
        -X POST "http://${ENGINE_IP}:8301/a/nodeconf" \
        -H 'Content-Type: application/json' \
        -H "x-engine-ts: ${ts}" \
        -H "x-engine-nonce: ${n}" \
        -H "x-engine-sig: ${s}" \
        -H "x-engine-node: ${NODE_ID}" \
        -d "${body}" 2>/dev/null || printf '%s' '')"
    if [[ -n "${r}" && "${r}" =~ ^[A-Za-z_]+= ]]; then
        printf '%s' "${r}" > "${CONF}"
        chmod 600 "${CONF}"
        t006_log 'nodeconf fetched'
    elif [[ -n "${r}" ]]; then
        t006_log 'nodeconf fetch returned invalid data'
    fi
}

t006_init() {
    t006_tmpfs
    mkdir -p "${LOG_DIR}" "${BOOT_STATE}"
    printf '%s' '1' > "${BOOT_STATE}.done"
    t006_log 'bootstrap init'
}

t006_start() {
    t006_tmpfs
    t006_fetchconf
    t006_wginit
    t006_report 'bootstrap-complete'
    t006_log 'bootstrap started'
}

t006_stop() {
    ip link del "${WG_IFACE}" 2>/dev/null || true
    umount "${SE_DIR}" 2>/dev/null || true
    t006_log 'bootstrap stopped'
}

t006_status() {
    if mountpoint -q "${SE_DIR}" 2>/dev/null; then
        printf '%s\n' 'tmpfs-mounted'
    else
        printf '%s\n' 'tmpfs-unmounted'
    fi
    if ip link show "${WG_IFACE}" &>/dev/null; then
        printf '%s\n' 'wg-up'
    else
        printf '%s\n' 'wg-down'
    fi
    cat "${BOOT_STATE}.done" 2>/dev/null || printf '%s\n' '0'
}

t006_run() {
    t006_tmpfs
    t006_fetchconf
    t006_wginit
}

# ── Cleanup ────────────────────────────────────────────────────────────────
cleanup_boot() {
    flock -u 300 2>/dev/null || true
}
trap cleanup_boot EXIT

# ── Main ───────────────────────────────────────────────────────────────────
case "${1:-}" in
    init)   t006_init ;;
    start)  t006_start ;;
    stop)   t006_stop ;;
    status) t006_status ;;
    run)    t006_run ;;
    *)      printf 'usage: %s init|start|stop|status|run\n' "$0"; exit 1 ;;
esac
