#!/bin/sh
# SecuBox Mesh Invite Generator
# Generates a join URL that can be shared with peer nodes
# Usage: sbx-mesh-invite [--auto-approve] [--ttl SECONDS]

set -e

VERSION="1.0.0"
TOKENS_FILE="/var/lib/secubox/p2p/master-link/tokens.json"
AUTO_APPROVE="true"
TTL=3600
MASTER_IP=""
API_PORT="7331"

# Parse arguments
while [ $# -gt 0 ]; do
    case "$1" in
        --auto-approve|-a)
            AUTO_APPROVE="true"
            shift
            ;;
        --manual-approve|-m)
            AUTO_APPROVE="false"
            shift
            ;;
        --ttl|-t)
            TTL="$2"
            shift 2
            ;;
        --ip|-i)
            MASTER_IP="$2"
            shift 2
            ;;
        --version|-v)
            echo "sbx-mesh-invite v$VERSION"
            exit 0
            ;;
        --help|-h)
            cat << 'EOF'
SecuBox Mesh Invite Generator v1.0.0

Usage:
  sbx-mesh-invite [options]

Options:
  -a, --auto-approve   Auto-approve joining nodes (default)
  -m, --manual-approve Require manual approval
  -t, --ttl SECONDS    Token validity in seconds (default: 3600)
  -i, --ip ADDRESS     Master IP address for the invite URL
  -v, --version        Show version
  -h, --help           Show this help

Output:
  Prints a join URL that can be copy-pasted to peer nodes.
  On the peer, run: sbx-mesh-join <URL>

Examples:
  sbx-mesh-invite                    # Default: auto-approve, 1h TTL
  sbx-mesh-invite -m -t 7200         # Manual approve, 2h TTL
  sbx-mesh-invite -i 192.168.1.1     # Specify master IP
EOF
            exit 0
            ;;
        *)
            echo "Unknown option: $1" >&2
            exit 1
            ;;
    esac
done

# Ensure tokens directory exists
mkdir -p "$(dirname "$TOKENS_FILE")"

# Generate random token (32 hex chars)
if command -v openssl >/dev/null; then
    TOKEN=$(openssl rand -hex 16)
elif [ -r /dev/urandom ]; then
    TOKEN=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n')
else
    # Fallback: use date + random
    TOKEN=$(date +%s%N | sha256sum | head -c 32)
fi

# Calculate hash
if command -v sha256sum >/dev/null; then
    HASH=$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)
elif command -v openssl >/dev/null; then
    HASH=$(printf '%s' "$TOKEN" | openssl dgst -sha256 | awk '{print $2}')
else
    echo "Error: No sha256 tool available" >&2
    exit 1
fi

# Get timestamps
NOW=$(date -Iseconds 2>/dev/null || date +%Y-%m-%dT%H:%M:%S)
NOW_TS=$(date +%s)
EXPIRES_TS=$((NOW_TS + TTL))
EXPIRES=$(date -Iseconds -d "@$EXPIRES_TS" 2>/dev/null || date -r "$EXPIRES_TS" -Iseconds 2>/dev/null || echo "$EXPIRES_TS")

# Get local IP for URL
LOCAL_IP="$MASTER_IP"
if [ -z "$LOCAL_IP" ]; then
    # Try common LAN interfaces first, prefer 192.168.x.x addresses
    for iface in br-lan eth0 enp0s8 enp0s3 ens3; do
        candidate=$(ip -4 addr show "$iface" 2>/dev/null | grep -oE 'inet 192\.168\.[0-9.]+' | awk '{print $2}' | head -1)
        if [ -n "$candidate" ]; then
            LOCAL_IP="$candidate"
            break
        fi
    done
    # Fallback to any non-loopback, non-10.x address
    if [ -z "$LOCAL_IP" ]; then
        LOCAL_IP=$(ip -4 addr show 2>/dev/null | grep -oE 'inet [0-9.]+' | grep -v '127.0.0' | grep -v 'inet 10\.' | awk '{print $2}' | head -1)
    fi
    [ -z "$LOCAL_IP" ] && LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
    [ -z "$LOCAL_IP" ] && LOCAL_IP="<MASTER_IP>"
fi

# Create new token entry
NEW_TOKEN="{
  \"hash\": \"$HASH\",
  \"type\": \"join\",
  \"created\": \"$NOW\",
  \"expires\": \"$EXPIRES\",
  \"expires_ts\": $EXPIRES_TS,
  \"ttl\": $TTL,
  \"status\": \"active\",
  \"auto_approve\": $AUTO_APPROVE
}"

# Add to tokens file
if [ -f "$TOKENS_FILE" ]; then
    # Append to existing array using Python or jq
    if command -v python3 >/dev/null; then
        python3 << PYEOF
import json
with open("$TOKENS_FILE", "r") as f:
    tokens = json.load(f)
tokens.append(json.loads('''$NEW_TOKEN'''))
with open("$TOKENS_FILE", "w") as f:
    json.dump(tokens, f, indent=2)
PYEOF
    elif command -v jq >/dev/null; then
        tmp=$(mktemp)
        jq ". + [$NEW_TOKEN]" "$TOKENS_FILE" > "$tmp" && mv "$tmp" "$TOKENS_FILE"
    else
        # Manual append (risky but works for simple cases)
        sed -i 's/]$/,'"$(echo "$NEW_TOKEN" | tr -d '\n')"']/' "$TOKENS_FILE"
    fi
else
    echo "[$NEW_TOKEN]" > "$TOKENS_FILE"
fi

# secubox-p2p / the aggregator's in-process p2p run as user 'secubox' and read
# this token store. sbx-mesh-invite is often run as root, which would leave
# tokens.json root-owned -> the secubox services crash with EACCES (this took
# down the in-process aggregator once). Re-own the store when running as root.
if [ "$(id -u)" = "0" ]; then
    chown -R secubox:secubox "$(dirname "$TOKENS_FILE")" 2>/dev/null || true
fi

# Output the invite
echo ""
echo "╔══════════════════════════════════════════════════════════════════╗"
echo "║                    SecuBox Mesh Invite                           ║"
echo "╠══════════════════════════════════════════════════════════════════╣"
echo "║ Token:       $TOKEN"
echo "║ Expires:     $EXPIRES"
echo "║ Auto-approve: $AUTO_APPROVE"
echo "╠══════════════════════════════════════════════════════════════════╣"
echo "║ Join URL (copy to peer node):                                    ║"
echo "╟──────────────────────────────────────────────────────────────────╢"
echo "║"
echo "║  https://${LOCAL_IP}/master-link/?token=${TOKEN}"
echo "║"
echo "╠══════════════════════════════════════════════════════════════════╣"
echo "║ Or run on the peer:                                              ║"
echo "╟──────────────────────────────────────────────────────────────────╢"
echo "║"
echo "║  sbx-mesh-join ${LOCAL_IP} ${TOKEN}"
echo "║"
echo "╚══════════════════════════════════════════════════════════════════╝"
echo ""
