#!/usr/bin/env bash
# Validate Besu configuration - check all config files, keys, and genesis.json
# Ensures everything is in the correct place and properly formatted

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# PROJECT_ROOT should be one level up from scripts directory
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# Source common functions
if [[ -f "$PROJECT_ROOT/lib/common.sh" ]]; then
    source "$PROJECT_ROOT/lib/common.sh"
else
    log_info() { echo "[INFO] $1"; }
    log_success() { echo "[✓] $1"; }
    log_warn() { echo "[WARNING] $1"; }
    log_error() { echo "[ERROR] $1"; exit 1; }
    error_exit() { echo "[ERROR] $1"; exit 1; }
fi

load_config 2>/dev/null || true

# Container arrays
VALIDATORS=(1000 1001 1002 1003 1004)
SENTRIES=(1500 1501 1502 1503)
RPCS=(2500 2501 2502)

# Node name mappings
declare -A VMID_TO_NODE
VMID_TO_NODE[1000]="validator-1"
VMID_TO_NODE[1001]="validator-2"
VMID_TO_NODE[1002]="validator-3"
VMID_TO_NODE[1003]="validator-4"
VMID_TO_NODE[1004]="validator-5"
VMID_TO_NODE[1500]="sentry-1"
VMID_TO_NODE[1501]="sentry-2"
VMID_TO_NODE[1502]="sentry-3"
VMID_TO_NODE[1503]="sentry-4"
VMID_TO_NODE[2500]="rpc-1"
VMID_TO_NODE[2501]="rpc-2"
VMID_TO_NODE[2502]="rpc-3"

log_info "Validating Besu configuration on all containers"

# 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

validation_errors=0
validation_warnings=0

# Function to validate validator keys
validate_validator_keys() {
    local vmid="$1"
    local node_name="${VMID_TO_NODE[$vmid]}"
    local keys_dir="/keys/validators/$node_name"
    
    log_info "Validating validator keys for $node_name (container $vmid)"
    
    if ! pct exec "$vmid" -- test -d "$keys_dir" 2>/dev/null; then
        log_error "Validator keys directory not found: $keys_dir"
        validation_errors=$((validation_errors + 1))
        return 1
    fi
    
    log_success "Keys directory exists: $keys_dir"
    
    # Check for key files (different formats may exist)
    local has_key=false
    local key_files=("key" "key.pem" "key.priv")
    
    for key_file in "${key_files[@]}"; do
        if pct exec "$vmid" -- test -f "$keys_dir/$key_file" 2>/dev/null; then
            log_success "Found key file: $key_file"
            has_key=true
            
            # Check file permissions (should be readable only by owner)
            local perms=$(pct exec "$vmid" -- stat -c "%a" "$keys_dir/$key_file" 2>/dev/null || echo "000")
            if [[ "$perms" != "600" && "$perms" != "400" ]]; then
                log_warn "Key file $key_file has insecure permissions: $perms (should be 600 or 400)"
                validation_warnings=$((validation_warnings + 1))
            fi
            break
        fi
    done
    
    if [[ "$has_key" == "false" ]]; then
        log_error "No key file found in $keys_dir (expected: key, key.pem, or key.priv)"
        validation_errors=$((validation_errors + 1))
    fi
    
    # Check for address file
    if pct exec "$vmid" -- test -f "$keys_dir/address.txt" 2>/dev/null || pct exec "$vmid" -- test -f "$keys_dir/address" 2>/dev/null; then
        local addr_file=""
        if pct exec "$vmid" -- test -f "$keys_dir/address.txt" 2>/dev/null; then
            addr_file="$keys_dir/address.txt"
        else
            addr_file="$keys_dir/address"
        fi
        
        local address=$(pct exec "$vmid" -- cat "$addr_file" 2>/dev/null | tr -d '[:space:]')
        if [[ "$address" =~ ^0x[0-9a-fA-F]{40}$ ]]; then
            log_success "Validator address format valid: $address"
        else
            log_error "Invalid validator address format: $address (should be 0x followed by 40 hex chars)"
            validation_errors=$((validation_errors + 1))
        fi
    else
        log_warn "Address file not found (address.txt or address)"
        validation_warnings=$((validation_warnings + 1))
    fi
    
    # Check ownership
    local owner=$(pct exec "$vmid" -- stat -c "%U:%G" "$keys_dir" 2>/dev/null || echo "unknown")
    if [[ "$owner" != "besu:besu" ]]; then
        log_warn "Keys directory ownership is $owner (should be besu:besu)"
        validation_warnings=$((validation_warnings + 1))
    fi
}

# Function to validate configuration files
validate_config_files() {
    local vmid="$1"
    local node_type="$2"  # validator, sentry, rpc
    
    log_info "Validating configuration files for $node_type node (container $vmid)"
    
    # Check genesis.json (required for all)
    if pct exec "$vmid" -- test -f "/etc/besu/genesis.json" 2>/dev/null; then
        log_success "genesis.json exists"
        
        # Validate JSON syntax
        if pct exec "$vmid" -- python3 -m json.tool /etc/besu/genesis.json >/dev/null 2>&1 || \
           pct exec "$vmid" -- jq empty /etc/besu/genesis.json 2>/dev/null; then
            log_success "genesis.json is valid JSON"
        else
            log_error "genesis.json is not valid JSON"
            validation_errors=$((validation_errors + 1))
        fi
    else
        log_error "genesis.json not found at /etc/besu/genesis.json"
        validation_errors=$((validation_errors + 1))
    fi
    
    # Check node-specific config file
    local config_file=""
    case "$node_type" in
        validator)
            config_file="/etc/besu/config-validator.toml"
            ;;
        sentry)
            config_file="/etc/besu/config-sentry.toml"
            ;;
        rpc)
            # Try different RPC config files
            if pct exec "$vmid" -- test -f "/etc/besu/config-rpc-core.toml" 2>/dev/null; then
                config_file="/etc/besu/config-rpc-core.toml"
            elif pct exec "$vmid" -- test -f "/etc/besu/config-rpc-perm.toml" 2>/dev/null; then
                config_file="/etc/besu/config-rpc-perm.toml"
            elif pct exec "$vmid" -- test -f "/etc/besu/config-rpc-public.toml" 2>/dev/null; then
                config_file="/etc/besu/config-rpc-public.toml"
            fi
            ;;
    esac
    
    if [[ -n "$config_file" ]]; then
        if pct exec "$vmid" -- test -f "$config_file" 2>/dev/null; then
            log_success "Config file exists: $config_file"
            
            # Check if config references genesis.json correctly
            if pct exec "$vmid" -- grep -q "genesis-file.*genesis.json" "$config_file" 2>/dev/null; then
                log_success "Config file references genesis.json"
            else
                log_warn "Config file may not reference genesis.json correctly"
                validation_warnings=$((validation_warnings + 1))
            fi
        else
            log_error "Config file not found: $config_file"
            validation_errors=$((validation_errors + 1))
        fi
    fi
    
    # Check permissions-nodes.toml (should exist for all)
    if pct exec "$vmid" -- test -f "/etc/besu/permissions-nodes.toml" 2>/dev/null; then
        log_success "permissions-nodes.toml exists"
    else
        log_warn "permissions-nodes.toml not found (may be optional)"
        validation_warnings=$((validation_warnings + 1))
    fi
    
    # Check static-nodes.json (should exist, may be empty array)
    if pct exec "$vmid" -- test -f "/etc/besu/static-nodes.json" 2>/dev/null; then
        log_success "static-nodes.json exists"
        
        # Validate JSON syntax
        if pct exec "$vmid" -- python3 -m json.tool /etc/besu/static-nodes.json >/dev/null 2>&1 || \
           pct exec "$vmid" -- jq empty /etc/besu/static-nodes.json 2>/dev/null; then
            log_success "static-nodes.json is valid JSON"
        else
            log_warn "static-nodes.json is not valid JSON"
            validation_warnings=$((validation_warnings + 1))
        fi
    else
        log_warn "static-nodes.json not found (will be created if needed)"
        validation_warnings=$((validation_warnings + 1))
    fi
    
    # Check directory ownership
    local owner=$(pct exec "$vmid" -- stat -c "%U:%G" /etc/besu 2>/dev/null || echo "unknown")
    if [[ "$owner" != "besu:besu" && "$owner" != "root:root" ]]; then
        log_warn "Config directory ownership is $owner (should be besu:besu or root:root)"
        validation_warnings=$((validation_warnings + 1))
    fi
}

# Function to check nodekey
check_nodekey() {
    local vmid="$1"
    
    if pct exec "$vmid" -- test -f "/data/besu/nodekey" 2>/dev/null; then
        log_success "nodekey exists at /data/besu/nodekey"
        
        # Check file size (should be 32 bytes / 64 hex chars)
        local size=$(pct exec "$vmid" -- stat -c "%s" /data/besu/nodekey 2>/dev/null || echo "0")
        if [[ "$size" -eq 32 ]]; then
            log_success "nodekey has correct size (32 bytes)"
        else
            log_warn "nodekey size is $size bytes (expected 32 bytes)"
            validation_warnings=$((validation_warnings + 1))
        fi
        
        # Check ownership
        local owner=$(pct exec "$vmid" -- stat -c "%U:%G" /data/besu/nodekey 2>/dev/null || echo "unknown")
        if [[ "$owner" == "besu:besu" ]]; then
            log_success "nodekey ownership is correct (besu:besu)"
        else
            log_warn "nodekey ownership is $owner (should be besu:besu)"
            validation_warnings=$((validation_warnings + 1))
        fi
    else
        log_info "nodekey not found (will be auto-generated on first start)"
    fi
}

# Validate all containers
all_vmids=("${VALIDATORS[@]}" "${SENTRIES[@]}" "${RPCS[@]}")

for vmid in "${all_vmids[@]}"; do
    if ! pct list | grep -q "^\s*$vmid\s"; then
        log_warn "Container $vmid does not exist, skipping"
        continue
    fi
    
    if ! pct status "$vmid" 2>/dev/null | grep -q "status: running"; then
        log_warn "Container $vmid is not running, skipping"
        continue
    fi
    
    log_info ""
    log_info "=== Validating container $vmid ==="
    
    # Determine node type
    local node_type=""
    if [[ " ${VALIDATORS[@]} " =~ " ${vmid} " ]]; then
        node_type="validator"
        validate_validator_keys "$vmid"
    elif [[ " ${SENTRIES[@]} " =~ " ${vmid} " ]]; then
        node_type="sentry"
    elif [[ " ${RPCS[@]} " =~ " ${vmid} " ]]; then
        node_type="rpc"
    fi
    
    validate_config_files "$vmid" "$node_type"
    check_nodekey "$vmid"
    
    echo ""  # Blank line between containers
done

log_info ""
log_success "Validation completed!"
log_info "Summary:"
log_info "  Errors: $validation_errors"
log_info "  Warnings: $validation_warnings"

if [[ $validation_errors -gt 0 ]]; then
    log_error "Validation found $validation_errors errors - please fix before starting services"
    exit 1
elif [[ $validation_warnings -gt 0 ]]; then
    log_warn "Validation found $validation_warnings warnings - review and fix if needed"
    exit 0
else
    log_success "All validations passed!"
    exit 0
fi

