#!/bin/bash
# Info: Script to install Polkadot Bootnode
# Author: Provisioning System
# Release: 1.0
# Date: 2025-07-24

USAGE="install-polkadot-bootnode.sh"
[ "$1" == "-h" ] && echo "$USAGE" && exit 1

[ -r "env-polkadot-bootnode" ] && . ./env-polkadot-bootnode

POLKADOT_VERSION=${POLKADOT_VERSION:-latest}
POLKADOT_CHAIN=${POLKADOT_CHAIN:-polkadot}

# Determine architecture
ARCH="$(uname -m)"
case $ARCH in
    x86_64) ARCH="x86_64" ;;
    aarch64) ARCH="aarch64" ;;
    *) echo "Unsupported architecture: $ARCH" && exit 1 ;;
esac

# Set download URL based on version
if [ "$POLKADOT_VERSION" = "latest" ]; then
    POLKADOT_URL="https://github.com/paritytech/polkadot/releases/latest/download"
    POLKADOT_BINARY="polkadot"
else
    POLKADOT_URL="https://github.com/paritytech/polkadot/releases/download/${POLKADOT_VERSION}"
    POLKADOT_BINARY="polkadot"
fi

POLKADOT_BIN_PATH=${POLKADOT_BIN_PATH:-/usr/local/bin/polkadot}
POLKADOT_SYSTEMCTL_MODE=${POLKADOT_SYSTEMCTL_MODE:-enabled}

POLKADOT_CONFIG_PATH=${POLKADOT_CONFIG_PATH:-/etc/polkadot-bootnode}
POLKADOT_WORK_PATH=${POLKADOT_WORK_PATH:-/var/lib/polkadot-bootnode}
POLKADOT_BASE_PATH=${POLKADOT_BASE_PATH:-/var/lib/polkadot-bootnode/data}

POLKADOT_RUN_USER=${POLKADOT_RUN_USER:-polkadot}
POLKADOT_RUN_GROUP=${POLKADOT_RUN_GROUP:-polkadot}
POLKADOT_RUN_USER_HOME=${POLKADOT_RUN_USER_HOME:-/home/polkadot}

POLKADOT_BOOTNODE_NAME=${POLKADOT_BOOTNODE_NAME:-polkadot-bootnode}
POLKADOT_P2P_PORT=${POLKADOT_P2P_PORT:-30310}
POLKADOT_WS_PORT=${POLKADOT_WS_PORT:-30311}
POLKADOT_WSS_PORT=${POLKADOT_WSS_PORT:-30312}

echo "Installing Polkadot Bootnode ${POLKADOT_VERSION}..."

# Install dependencies
echo "Installing dependencies..."
if command -v apt-get >/dev/null 2>&1; then
    apt-get update
    apt-get install -y curl ca-certificates jq nginx certbot python3-certbot-nginx
elif command -v yum >/dev/null 2>&1; then
    yum update -y
    yum install -y curl ca-certificates jq nginx certbot python3-certbot-nginx
elif command -v dnf >/dev/null 2>&1; then
    dnf update -y
    dnf install -y curl ca-certificates jq nginx certbot python3-certbot-nginx
else
    echo "Package manager not found. Please install dependencies manually."
    exit 1
fi

# Create user and group
if ! id "$POLKADOT_RUN_USER" &>/dev/null; then
    groupadd -r "$POLKADOT_RUN_GROUP"
    useradd -r -g "$POLKADOT_RUN_GROUP" -d "$POLKADOT_RUN_USER_HOME" -s /bin/bash -c "Polkadot bootnode service user" "$POLKADOT_RUN_USER"
fi

# Create directories
mkdir -p "$POLKADOT_CONFIG_PATH"
mkdir -p "$POLKADOT_WORK_PATH"
mkdir -p "$POLKADOT_BASE_PATH"
mkdir -p "$POLKADOT_RUN_USER_HOME"

# Download and install Polkadot binary
cd /tmp
echo "Downloading Polkadot binary from ${POLKADOT_URL}/${POLKADOT_BINARY}..."
curl -L -o polkadot "${POLKADOT_URL}/${POLKADOT_BINARY}"

if [ ! -f "polkadot" ]; then
    echo "Failed to download Polkadot binary"
    exit 1
fi

# Install binary
chmod +x polkadot
mv polkadot "$(dirname "$POLKADOT_BIN_PATH")/"

# Generate node key for bootnode
echo "Generating bootnode key..."
NODE_KEY_FILE="${POLKADOT_NODE_KEY_FILE:-$POLKADOT_CONFIG_PATH/node-key}"
"$POLKADOT_BIN_PATH" key generate-node-key --file "$NODE_KEY_FILE"

# Extract peer ID from node key
PEER_ID=$("$POLKADOT_BIN_PATH" key inspect-node-key --file "$NODE_KEY_FILE")
echo "Bootnode Peer ID: $PEER_ID"

# Save peer ID for reference
echo "$PEER_ID" > "$POLKADOT_CONFIG_PATH/peer-id"

# Set ownership
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_WORK_PATH"
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_BASE_PATH"
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_RUN_USER_HOME"
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_CONFIG_PATH"

# Build bootnode arguments
BOOTNODE_ARGS="--chain $POLKADOT_CHAIN"
BOOTNODE_ARGS="$BOOTNODE_ARGS --name $POLKADOT_BOOTNODE_NAME"
BOOTNODE_ARGS="$BOOTNODE_ARGS --base-path $POLKADOT_BASE_PATH"
BOOTNODE_ARGS="$BOOTNODE_ARGS --node-key-file $NODE_KEY_FILE"

# Network configuration - bootnode specific ports
BOOTNODE_ARGS="$BOOTNODE_ARGS --listen-addr /ip4/0.0.0.0/tcp/$POLKADOT_P2P_PORT"
BOOTNODE_ARGS="$BOOTNODE_ARGS --listen-addr /ip4/0.0.0.0/tcp/$POLKADOT_WS_PORT/ws"

# Public address configuration
if [ -n "$POLKADOT_PUBLIC_ADDR" ]; then
    BOOTNODE_ARGS="$BOOTNODE_ARGS --public-addr $POLKADOT_PUBLIC_ADDR"
fi

# External addresses
if [ -n "$POLKADOT_EXTERNAL_ADDRESSES" ]; then
    IFS=',' read -ra EXTERNALS <<< "$POLKADOT_EXTERNAL_ADDRESSES"
    for external in "${EXTERNALS[@]}"; do
        BOOTNODE_ARGS="$BOOTNODE_ARGS --public-addr $external"
    done
fi

# Performance settings
BOOTNODE_ARGS="$BOOTNODE_ARGS --execution ${POLKADOT_EXECUTION:-wasm}"
BOOTNODE_ARGS="$BOOTNODE_ARGS --state-cache-size ${POLKADOT_STATE_CACHE_SIZE:-67108864}"

# Telemetry
if [ "${POLKADOT_TELEMETRY_ENABLED:-true}" = "true" ]; then
    BOOTNODE_ARGS="$BOOTNODE_ARGS --telemetry-url '${POLKADOT_TELEMETRY_URL:-wss://telemetry.polkadot.io/submit/} ${POLKADOT_TELEMETRY_VERBOSITY:-0}'"
fi

# Logging
LOG_CONFIG="${POLKADOT_LOG_LEVEL:-info}"
if [ -n "$POLKADOT_LOG_TARGETS" ]; then
    LOG_CONFIG="$LOG_CONFIG,${POLKADOT_LOG_TARGETS}"
fi
BOOTNODE_ARGS="$BOOTNODE_ARGS --log $LOG_CONFIG"

# Create systemd service file
cat > /etc/systemd/system/polkadot-bootnode.service << EOF
[Unit]
Description=Polkadot Bootnode
Documentation=https://docs.polkadot.network/
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$POLKADOT_RUN_USER
Group=$POLKADOT_RUN_GROUP
Environment=RUST_LOG=${POLKADOT_LOG_LEVEL:-info}
WorkingDirectory=$POLKADOT_WORK_PATH
ExecStart=$POLKADOT_BIN_PATH $BOOTNODE_ARGS
Restart=always
RestartSec=10

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$POLKADOT_WORK_PATH $POLKADOT_BASE_PATH $POLKADOT_CONFIG_PATH
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

# Resource limits
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

# Setup WSS proxy if enabled
if [ "${POLKADOT_WSS_ENABLED:-false}" = "true" ]; then
    echo "Setting up secure WebSocket proxy for bootnode..."
    
    # Create nginx configuration for bootnode WSS
    cat > /etc/nginx/sites-available/polkadot-bootnode-wss << EOF
server {
    listen ${POLKADOT_WSS_PORT} ssl http2;
    server_name ${POLKADOT_WSS_DOMAIN};

    # SSL configuration
    ssl_certificate ${POLKADOT_SSL_CERT_FILE};
    ssl_certificate_key ${POLKADOT_SSL_KEY_FILE};
    
    # SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # Rate limiting for bootnode
    limit_req_zone \$binary_remote_addr zone=bootnode_limit:10m rate=${POLKADOT_WSS_RATE_LIMIT:-1000}r/m;
    limit_req zone=bootnode_limit burst=50 nodelay;

    location / {
        proxy_pass http://127.0.0.1:$POLKADOT_WS_PORT;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        
        # WebSocket specific
        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }
}
EOF

    # Enable site
    ln -sf /etc/nginx/sites-available/polkadot-bootnode-wss /etc/nginx/sites-enabled/
    
    # Test nginx configuration
    nginx -t && systemctl restart nginx
fi

# Create bootnode info file
cat > "$POLKADOT_CONFIG_PATH/bootnode-info.json" << EOF
{
  "peer_id": "$PEER_ID",
  "chain": "$POLKADOT_CHAIN",
  "name": "$POLKADOT_BOOTNODE_NAME",
  "p2p_port": $POLKADOT_P2P_PORT,
  "ws_port": $POLKADOT_WS_PORT,
  "wss_port": $POLKADOT_WSS_PORT,
  "public_addr": "${POLKADOT_PUBLIC_ADDR:-}",
  "wss_enabled": ${POLKADOT_WSS_ENABLED:-false},
  "wss_domain": "${POLKADOT_WSS_DOMAIN:-}",
  "connections": {
    "p2p": "/ip4/YOUR_IP/tcp/$POLKADOT_P2P_PORT/p2p/$PEER_ID",
    "ws": "/ip4/YOUR_IP/tcp/$POLKADOT_WS_PORT/ws/p2p/$PEER_ID",
    "wss": "$([ "${POLKADOT_WSS_ENABLED:-false}" = "true" ] && echo "wss://${POLKADOT_WSS_DOMAIN}:${POLKADOT_WSS_PORT}" || echo "N/A")"
  }
}
EOF

# Enable and start service
systemctl daemon-reload
systemctl "$POLKADOT_SYSTEMCTL_MODE" polkadot-bootnode.service

if [ "$POLKADOT_SYSTEMCTL_MODE" = "enabled" ]; then
    systemctl start polkadot-bootnode.service
    
    # Wait a moment for service to start
    sleep 5
fi

echo "=========================================="
echo "Polkadot Bootnode installation completed!"
echo "=========================================="
echo "Service: polkadot-bootnode.service"
echo "Chain: $POLKADOT_CHAIN"
echo "Bootnode name: $POLKADOT_BOOTNODE_NAME"
echo "Peer ID: $PEER_ID"
echo ""
echo "Connection endpoints:"
echo "P2P:      /ip4/YOUR_IP/tcp/$POLKADOT_P2P_PORT/p2p/$PEER_ID"
echo "WS:       /ip4/YOUR_IP/tcp/$POLKADOT_WS_PORT/ws/p2p/$PEER_ID"

if [ "${POLKADOT_WSS_ENABLED:-false}" = "true" ]; then
    echo "WSS:      wss://${POLKADOT_WSS_DOMAIN}:${POLKADOT_WSS_PORT}"
fi

echo ""
echo "Configuration: $POLKADOT_CONFIG_PATH/"
echo "Node key: $NODE_KEY_FILE"
echo "Bootnode info: $POLKADOT_CONFIG_PATH/bootnode-info.json"

# Display service status
if systemctl is-active --quiet polkadot-bootnode.service; then
    echo "✅ Polkadot bootnode service is running"
else
    echo "⚠️  Polkadot bootnode service status:"
    systemctl status polkadot-bootnode.service --no-pager -l
fi

echo ""
echo "To use this bootnode, add the following to other nodes:"
echo "--bootnode /ip4/YOUR_IP/tcp/$POLKADOT_P2P_PORT/p2p/$PEER_ID"

# Cleanup
cd /
rm -rf /tmp/polkadot