#!/usr/bin/env bash
# Deploy Besu Nodes (Validators, Sentries, RPC) on Proxmox VE LXC containers

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

source "$PROJECT_ROOT/lib/common.sh"
source "$PROJECT_ROOT/lib/proxmox-api.sh"
source "$PROJECT_ROOT/lib/container-utils.sh" 2>/dev/null || true
source "$PROJECT_ROOT/lib/validation.sh" 2>/dev/null || true
source "$PROJECT_ROOT/lib/rollback.sh" 2>/dev/null || true
source "$PROJECT_ROOT/lib/parallel-deploy.sh" 2>/dev/null || true
source "$PROJECT_ROOT/lib/batch-parallel.sh" 2>/dev/null || true

# Load configuration - use explicit PROJECT_ROOT to ensure correct path
load_config "$PROJECT_ROOT/config/proxmox.conf"
load_config "$PROJECT_ROOT/config/network.conf" || {
    log_warn "network.conf not found, using defaults"
}

# Default values - use config file values with fallbacks
VALIDATOR_COUNT="${VALIDATORS_COUNT:-${VALIDATOR_COUNT:-5}}"
SENTRY_COUNT="${SENTRIES_COUNT:-${SENTRY_COUNT:-4}}"
RPC_COUNT="${RPC_COUNT:-3}"

# VMID ranges
VMID_VALIDATORS_START="${VMID_VALIDATORS_START:-1000}"
VMID_SENTRIES_START="${VMID_SENTRIES_START:-1500}"
VMID_RPC_START="${VMID_RPC_START:-2500}"

log_info "Starting Besu nodes deployment..."

# Check if running on Proxmox host
if ! command_exists pct; then
    error_exit "This script must be run on Proxmox host (pct command not found)"
fi

check_root

# Ensure OS template exists before deployment
ensure_os_template "${CONTAINER_OS_TEMPLATE:-local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst}" || {
    error_exit "OS template not available. Please download it first."
}

# Function to create and configure Besu node
create_besu_node() {
    local node_type="$1"  # validator, sentry, rpc
    local vmid="$2"
    local hostname="$3"
    local ip_address="$4"
    local memory="${5:-4096}"
    local cores="${6:-2}"
    local disk="${7:-100}"
    
    log_info "Creating $node_type node: $hostname (VMID: $vmid, IP: $ip_address)"
    
    # Determine network configuration
    local vlan=""
    case "$node_type" in
        validator)
            vlan="${VLAN_VALIDATORS:-100}"
            ;;
        sentry)
            vlan="${VLAN_SENTRIES:-101}"
            ;;
        rpc)
            vlan="${VLAN_RPC:-102}"
            ;;
    esac
    
    # Two-step network configuration approach for reliability:
    # 1. Create container with DHCP (more reliable)
    # 2. Configure static IP after creation using pct set
    
    # Network configuration variables with debugging
    local gateway="${GATEWAY:-192.168.11.1}"
    local netmask_raw="${NETMASK:-24}"
    local bridge="${PROXMOX_BRIDGE:-vmbr0}"
    
    # Convert netmask to CIDR format if needed (255.255.255.0 -> 24)
    local netmask="$netmask_raw"
    if [[ "$netmask_raw" == "255.255.255.0" ]]; then
        netmask="24"
    elif [[ "$netmask_raw" =~ ^[0-9]+$ ]] && [[ "$netmask_raw" -ge 0 ]] && [[ "$netmask_raw" -le 32 ]]; then
        # Already in CIDR format
        netmask="$netmask_raw"
    else
        # Default to 24 if invalid format
        log_warn "Invalid NETMASK format: $netmask_raw, using default: 24"
        netmask="24"
    fi
    
    # Debug logging for network configuration
    log_info "Network configuration variables:"
    log_info "  PROXMOX_BRIDGE: ${PROXMOX_BRIDGE:-vmbr0} (using: $bridge)"
    log_info "  GATEWAY: ${GATEWAY:-192.168.11.1} (using: $gateway)"
    log_info "  NETMASK: ${NETMASK:-24} (raw: $netmask_raw, using CIDR: $netmask)"
    log_info "  IP Address: $ip_address"
    
    # Initial network config for creation (use DHCP for reliability)
    local initial_network_config="bridge=${bridge},name=eth0,ip=dhcp,type=veth"
    log_info "Initial network config (for creation): $initial_network_config"
    
    # Static IP config (will be applied after creation)
    local static_network_config="bridge=${bridge},name=eth0,ip=${ip_address}/${netmask},gw=${gateway},type=veth"
    log_info "Static network config (to apply after creation): $static_network_config"
    
    # Create container
    if pct list | grep -q "^\s*$vmid\s"; then
        log_warn "Container $vmid already exists, skipping creation"
    else
        # Pre-deployment validation (if validation functions available)
        if command_exists pre_deployment_validation 2>/dev/null; then
            pre_deployment_validation "$vmid" "$memory" "$cores" "$disk" || {
                log_warn "Pre-deployment validation had warnings, continuing..."
            }
        fi
        
        log_info "Creating container $vmid with DHCP network configuration..."
        # Create container with DHCP (more reliable than static IP during creation)
        if ! pct create "$vmid" \
            "${CONTAINER_OS_TEMPLATE:-local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst}" \
            --storage "${PROXMOX_STORAGE:-local-lvm}" \
            --hostname "$hostname" \
            --memory "$memory" \
            --cores "$cores" \
            --rootfs "${PROXMOX_STORAGE:-local-lvm}:${disk}" \
            --net0 "$initial_network_config" \
            --unprivileged "${CONTAINER_UNPRIVILEGED:-1}" \
            --swap "${CONTAINER_SWAP:-512}" \
            --onboot "${CONTAINER_ONBOOT:-1}" \
            --timezone "${CONTAINER_TIMEZONE:-America/Los_Angeles}" \
            --features nesting=1,keyctl=1 2>&1; then
            log_error "Failed to create container $vmid. Check the error messages above."
            return 1
        fi
        
        log_success "Container $vmid created with DHCP configuration"
        
        # Wait a moment for container to be registered
        sleep 1
        
        # Verify container was actually created
        if ! pct list | grep -q "^\s*$vmid\s"; then
            log_error "Container $vmid creation reported success but container does not exist"
            return 1
        fi
        
        # Configure static IP address (two-step approach)
        log_info "Configuring static IP address $ip_address/$netmask for container $vmid..."
        if ! pct set "$vmid" --net0 "$static_network_config" 2>&1; then
            log_error "Failed to configure static IP for container $vmid"
            log_warn "Container $vmid exists but has DHCP configuration. You may need to manually configure the IP address."
            # Continue anyway - container exists and can be configured later
        else
            log_success "Static IP address configured for container $vmid"
        fi
        
        # Also configure DNS servers
        pct set "$vmid" --nameserver "8.8.8.8 8.8.4.4" 2>/dev/null || log_warn "Failed to set DNS servers for $vmid (non-critical)"
    fi
    
    # Wait for container to be ready
    wait_for_container "$vmid"
    
    # Configure container
    log_info "Configuring container $vmid..."
    
    # Enable features (firewall is configured at the Proxmox host level, not per-container)
    pct set "$vmid" --features nesting=1,keyctl=1
    
    # Start container and wait for readiness (required for pct push and pct exec)
    if ! start_container_and_wait "$vmid"; then
        log_error "Failed to start container $vmid"
        return 1
    fi
    
    # Verify container is ready for file operations
    if ! verify_container_ready "$vmid"; then
        log_error "Container $vmid is not ready for file operations"
        return 1
    fi
    
    # Configure locale in container to suppress warnings
    log_info "Configuring locale in container $vmid..."
    pct exec "$vmid" -- bash -c "export LC_ALL=C; export LANG=C; echo 'export LC_ALL=C' >> /root/.bashrc; echo 'export LANG=C' >> /root/.bashrc; echo 'export LC_ALL=C' >> /etc/environment; echo 'export LANG=C' >> /etc/environment" 2>/dev/null || true
    
    # Install Besu
    local install_script="$PROJECT_ROOT/install/besu-${node_type}-install.sh"
    if [[ ! -f "$install_script" ]]; then
        log_error "Install script not found: $install_script"
        return 1
    fi
    
    log_info "Installing Besu in container $vmid..."
    # Push install script (locale warnings from pct push are harmless)
    pct push "$vmid" "$install_script" /tmp/install.sh 2>&1 | grep -vE "(perl: warning|locale: Cannot set|Setting locale failed)" || true
    if ! pct exec "$vmid" -- test -f /tmp/install.sh 2>/dev/null; then
        log_error "Failed to push install script to container $vmid"
        return 1
    fi
    # Execute install script (filter locale warnings but preserve other output)
    local install_output
    install_output=$(pct exec "$vmid" -- bash -c "export LC_ALL=C; export LANG=C; bash /tmp/install.sh" 2>&1)
    local install_exit=$?
    # Filter locale warnings but show everything else
    echo "$install_output" | grep -vE "(perl: warning|locale: Cannot set|Setting locale failed|Falling back to the standard locale)" || true
    if [[ $install_exit -ne 0 ]]; then
        log_error "Failed to execute install script in container $vmid"
        return 1
    fi
    
    log_success "$node_type node $hostname (VMID: $vmid) deployed successfully"
    
    # Register for rollback
    if command_exists register_container 2>/dev/null; then
        register_container "$vmid" "besu-$node_type"
    fi
    
    # Return container info (IP address is configured as static IP)
    echo "$vmid:$hostname:$ip_address"
}

# Deploy Validator nodes
log_info "Deploying Validator nodes..."
validators=()
for i in $(seq 0 $((VALIDATOR_COUNT - 1))); do
    vmid=$((VMID_VALIDATORS_START + i))
    hostname="besu-validator-$((i + 1))"
    ip_octet=$((100 + i))
    ip_address="${VALIDATORS_SUBNET:-192.168.11}.${ip_octet}"
    
    node_info=$(create_besu_node \
        "validator" \
        "$vmid" \
        "$hostname" \
        "$ip_address" \
        "${VALIDATOR_MEMORY:-8192}" \
        "${VALIDATOR_CORES:-4}" \
        "${VALIDATOR_DISK:-100}")
    
    validators+=("$node_info")
done

log_success "Deployed $VALIDATOR_COUNT validator nodes"

# Deploy Sentry nodes
log_info "Deploying Sentry nodes..."
sentries=()
for i in $(seq 0 $((SENTRY_COUNT - 1))); do
    vmid=$((VMID_SENTRIES_START + i))
    hostname="besu-sentry-$((i + 1))"
    ip_octet=$((150 + i))
    ip_address="${SENTRIES_SUBNET:-192.168.11}.${ip_octet}"
    
    node_info=$(create_besu_node \
        "sentry" \
        "$vmid" \
        "$hostname" \
        "$ip_address" \
        "${SENTRY_MEMORY:-4096}" \
        "${SENTRY_CORES:-2}" \
        "${SENTRY_DISK:-100}")
    
    sentries+=("$node_info")
done

log_success "Deployed $SENTRY_COUNT sentry nodes"

# Deploy RPC nodes
log_info "Deploying RPC nodes..."
rpcs=()
for i in $(seq 0 $((RPC_COUNT - 1))); do
    vmid=$((VMID_RPC_START + i))
    hostname="besu-rpc-$((i + 1))"
    ip_octet=$((250 + i))
    ip_address="${RPC_SUBNET:-192.168.11}.${ip_octet}"
    
    node_info=$(create_besu_node \
        "rpc" \
        "$vmid" \
        "$hostname" \
        "$ip_address" \
        "${RPC_MEMORY:-16384}" \
        "${RPC_CORES:-4}" \
        "${RPC_DISK:-200}")
    
    rpcs+=("$node_info")
done

log_success "Deployed $RPC_COUNT RPC nodes"

# Save inventory
log_info "Saving deployment inventory..."
INVENTORY_FILE="$PROJECT_ROOT/config/inventory.conf"
cat > "$INVENTORY_FILE" <<EOF
# SMOM-DBIS-138 Container Inventory
# Generated: $(date)

# Validators
EOF

for validator in "${validators[@]}"; do
    IFS=':' read -r vmid hostname ip <<< "$validator"
    echo "VALIDATOR_${hostname//-/}_VMID=$vmid" >> "$INVENTORY_FILE"
    echo "VALIDATOR_${hostname//-/}_IP=$ip" >> "$INVENTORY_FILE"
done

cat >> "$INVENTORY_FILE" <<EOF

# Sentries
EOF

for sentry in "${sentries[@]}"; do
    IFS=':' read -r vmid hostname ip <<< "$sentry"
    echo "SENTRY_${hostname//-/}_VMID=$vmid" >> "$INVENTORY_FILE"
    echo "SENTRY_${hostname//-/}_IP=$ip" >> "$INVENTORY_FILE"
done

cat >> "$INVENTORY_FILE" <<EOF

# RPC Nodes
EOF

for rpc in "${rpcs[@]}"; do
    IFS=':' read -r vmid hostname ip <<< "$rpc"
    echo "RPC_${hostname//-/}_VMID=$vmid" >> "$INVENTORY_FILE"
    echo "RPC_${hostname//-/}_IP=$ip" >> "$INVENTORY_FILE"
done

log_success "Inventory saved to $INVENTORY_FILE"

log_success "Besu nodes deployment completed!"
log_info "Summary:"
log_info "  Validators: $VALIDATOR_COUNT"
log_info "  Sentries: $SENTRY_COUNT"
log_info "  RPC Nodes: $RPC_COUNT"
log_info ""
log_info "Next steps:"
log_info "1. Copy configuration files (genesis.json, static-nodes.json) to containers"
log_info "2. Copy validator keys to validator containers"
log_info "3. Update static-nodes.json with all node IPs"
log_info "4. Start Besu services in containers"

