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

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

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

POLKADOT_VERSION=${POLKADOT_VERSION:-stable2024}
POLKADOT_TEMPLATE_REPO="https://github.com/paritytech/polkadot-sdk-solochain-template.git"

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_WORK_PATH=${POLKADOT_WORK_PATH:-/var/lib/polkadot}
POLKADOT_CONFIG_PATH=${POLKADOT_CONFIG_PATH:-/etc/polkadot}
POLKADOT_BIN_PATH=${POLKADOT_BIN_PATH:-/usr/local/bin}
POLKADOT_NODE_BINARY=${POLKADOT_NODE_BINARY:-solochain-template-node}
POLKADOT_BUILD_PATH="/opt/polkadot-solochain-build"

POLKADOT_BASE_PATH=${POLKADOT_BASE_PATH:-/var/lib/polkadot/data}
POLKADOT_KEYSTORE_PATH=${POLKADOT_KEYSTORE_PATH:-/var/lib/polkadot/keystore}

POLKADOT_SYSTEMCTL_MODE=${POLKADOT_SYSTEMCTL_MODE:-enabled}

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

# Install system dependencies
echo "Installing system dependencies..."
if command -v apt-get >/dev/null 2>&1; then
    apt-get update
    apt-get install -y curl git build-essential pkg-config libssl-dev protobuf-compiler clang cmake
elif command -v yum >/dev/null 2>&1; then
    yum groupinstall -y "Development Tools"
    yum install -y curl git openssl-devel protobuf-compiler clang cmake pkg-config
elif command -v dnf >/dev/null 2>&1; then
    dnf groupinstall -y "Development Tools"
    dnf install -y curl git openssl-devel protobuf-compiler clang cmake pkg-config
else
    echo "Package manager not found. Please install dependencies manually."
    exit 1
fi

# Install Rust if not present
if ! command -v rustc >/dev/null 2>&1; then
    echo "Installing Rust..."
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
    source "$HOME/.cargo/env"
    rustup default stable
    rustup target add wasm32-unknown-unknown
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 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_KEYSTORE_PATH"
mkdir -p "$POLKADOT_RUN_USER_HOME"
mkdir -p "$POLKADOT_BUILD_PATH"

# Clone and build Polkadot solochain template
echo "Cloning Polkadot solochain template..."
cd "$POLKADOT_BUILD_PATH"

if [ ! -d "polkadot-sdk-solochain-template" ]; then
    git clone "$POLKADOT_TEMPLATE_REPO" polkadot-sdk-solochain-template
fi

cd polkadot-sdk-solochain-template

# Checkout specific version if needed
if [ "$POLKADOT_VERSION" != "stable2024" ] && [ "$POLKADOT_VERSION" != "latest" ]; then
    git checkout "$POLKADOT_VERSION" || echo "Version $POLKADOT_VERSION not found, using default branch"
fi

echo "Building Polkadot solochain node (this may take 20-30 minutes)..."
export RUST_LOG=info

# Build the node
cargo build --release

if [ ! -f "target/release/$POLKADOT_NODE_BINARY" ]; then
    echo "Failed to build Polkadot solochain node"
    exit 1
fi

# Install binary
echo "Installing binary..."
cp "target/release/$POLKADOT_NODE_BINARY" "$POLKADOT_BIN_PATH/"
chmod +x "$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY"

# Create chain specification if not exists
echo "Generating chain specification..."
if [ ! -f "$POLKADOT_CONFIG_PATH/local-testnet.json" ]; then
    cd "$POLKADOT_BUILD_PATH/polkadot-sdk-solochain-template"
    
    # Generate raw chain spec
    "$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY" build-spec --disable-default-bootnode --chain local > "$POLKADOT_CONFIG_PATH/local-testnet-plain.json"
    "$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY" build-spec --chain "$POLKADOT_CONFIG_PATH/local-testnet-plain.json" --raw --disable-default-bootnode > "$POLKADOT_CONFIG_PATH/local-testnet.json"
fi

# Create node key if not exists
if [ ! -f "$POLKADOT_CONFIG_PATH/node-key" ] && [ -z "$POLKADOT_NODE_KEY" ]; then
    echo "Generating node key..."
    openssl rand -hex 32 > "$POLKADOT_CONFIG_PATH/node-key"
fi

# Create runtime configuration
cat > "$POLKADOT_CONFIG_PATH/runtime-config.json" << EOF
{
  "name": "${POLKADOT_RUNTIME_NAME:-solochain-template}",
  "version": "${POLKADOT_RUNTIME_VERSION:-1.0.0}",
  "pvm_enabled": ${POLKADOT_PVM_ENABLED:-true},
  "wasm_execution": "${POLKADOT_WASM_EXECUTION:-compiled}",
  "heap_pages": ${POLKADOT_HEAP_PAGES:-64}
}
EOF

# 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_KEYSTORE_PATH"
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_RUN_USER_HOME"
chown -R "$POLKADOT_RUN_USER:$POLKADOT_RUN_GROUP" "$POLKADOT_CONFIG_PATH"

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

[Service]
Type=simple
User=$POLKADOT_RUN_USER
Group=$POLKADOT_RUN_GROUP
EnvironmentFile=$POLKADOT_CONFIG_PATH/node.env
WorkingDirectory=$POLKADOT_WORK_PATH
ExecStart=$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY \\
    --base-path $POLKADOT_BASE_PATH \\
    --chain $POLKADOT_CONFIG_PATH/local-testnet.json \\
    --port 30333 \\
    --rpc-port ${POLKADOT_RPC_PORT:-9944} \\
    --rpc-bind-addr ${POLKADOT_RPC_BIND_ADDR:-127.0.0.1} \\
    --validator \\
    --name \${POLKADOT_NODE_NAME:-SolochainNode} \\
    --execution ${POLKADOT_EXECUTION_STRATEGY:-wasm} \\
    --state-cache-size ${POLKADOT_STATE_CACHE_SIZE:-67108864} \\
    --log ${POLKADOT_LOG_LEVEL:-info}

Restart=always
RestartSec=10

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

# Resource limits
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

# Create environment file for systemd service
cat > "$POLKADOT_CONFIG_PATH/node.env" << EOF
POLKADOT_NODE_NAME=${POLKADOT_NETWORK_NAME:-SolochainNode}
RUST_LOG=${POLKADOT_LOG_LEVEL:-info}
EOF

# Load additional environment variables from template if available
if [ -f "env-polkadot-solochain" ]; then
    cat env-polkadot-solochain >> "$POLKADOT_CONFIG_PATH/node.env"
fi

# Initialize keys for development if in dev mode
if [ "${POLKADOT_DEV_MODE:-false}" = "true" ] || [ "${POLKADOT_ALICE_VALIDATOR:-false}" = "true" ]; then
    echo "Setting up development keys..."
    sudo -u "$POLKADOT_RUN_USER" "$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY" key insert \
        --base-path "$POLKADOT_BASE_PATH" \
        --chain "$POLKADOT_CONFIG_PATH/local-testnet.json" \
        --scheme Sr25519 \
        --suri "//Alice" \
        --key-type aura \
        --password-interactive < /dev/null || true
        
    sudo -u "$POLKADOT_RUN_USER" "$POLKADOT_BIN_PATH/$POLKADOT_NODE_BINARY" key insert \
        --base-path "$POLKADOT_BASE_PATH" \
        --chain "$POLKADOT_CONFIG_PATH/local-testnet.json" \
        --scheme Ed25519 \
        --suri "//Alice" \
        --key-type gran \
        --password-interactive < /dev/null || true
fi

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

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

echo "Polkadot Solochain installation completed!"
echo "Service: polkadot-solochain.service"
echo "RPC endpoint: ws://${POLKADOT_RPC_BIND_ADDR:-127.0.0.1}:${POLKADOT_RPC_PORT:-9944}"
echo "HTTP RPC endpoint: http://${POLKADOT_RPC_BIND_ADDR:-127.0.0.1}:${POLKADOT_HTTP_PORT:-9933}"
echo "Configuration: $POLKADOT_CONFIG_PATH/"
echo "Data directory: $POLKADOT_BASE_PATH"
echo "Keystore: $POLKADOT_KEYSTORE_PATH"
echo ""
echo "Connect with Polkadot-JS Apps:"
echo "https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F${POLKADOT_RPC_BIND_ADDR:-127.0.0.1}%3A${POLKADOT_RPC_PORT:-9944}"

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

# Cleanup build directory if requested
if [ "${POLKADOT_CLEANUP_BUILD:-false}" = "true" ]; then
    echo "Cleaning up build directory..."
    rm -rf "$POLKADOT_BUILD_PATH"
fi