#!/usr/bin/env bash
# Comprehensive Deployment Validation Script
# Validates all aspects of deployment to ensure correctness and completeness

set -euo pipefail

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

source "$PROJECT_ROOT/lib/common.sh"

# Load configuration
load_config "$PROJECT_ROOT/config/proxmox.conf" 2>/dev/null || true
load_config "$PROJECT_ROOT/config/network.conf" 2>/dev/null || true

# Load VMID ranges from config (defaults to new allocation starting at 1000)
VALIDATOR_START="${VMID_VALIDATORS_START:-1000}"
SENTRY_START="${VMID_SENTRIES_START:-1500}"
RPC_START="${VMID_RPC_START:-2500}"
# Support both singular and plural forms from config
VALIDATOR_COUNT="${VALIDATOR_COUNT:-${VALIDATORS_COUNT:-5}}"
SENTRY_COUNT="${SENTRY_COUNT:-${SENTRIES_COUNT:-4}}"
RPC_COUNT="${RPC_COUNT:-3}"

# Build VMID arrays and mappings dynamically
VALIDATORS=()
SENTRIES=()
RPCS=()
declare -A VMID_TO_NODE_TYPE
declare -A VMID_TO_NODE_NAME

# Build validators array and mappings
for ((i=0; i<VALIDATOR_COUNT; i++)); do
    vmid=$((VALIDATOR_START + i))
    validator_num=$((i + 1))
    VALIDATORS+=($vmid)
    VMID_TO_NODE_TYPE[$vmid]="validator"
    VMID_TO_NODE_NAME[$vmid]="validator-$validator_num"
done

# Build sentries array and mappings
for ((i=0; i<SENTRY_COUNT; i++)); do
    vmid=$((SENTRY_START + i))
    sentry_num=$((i + 2))  # sentry-2, sentry-3, etc.
    SENTRIES+=($vmid)
    VMID_TO_NODE_TYPE[$vmid]="sentry"
    VMID_TO_NODE_NAME[$vmid]="sentry-$sentry_num"
done

# Build RPC array and mappings
for ((i=0; i<RPC_COUNT; i++)); do
    vmid=$((RPC_START + i))
    rpc_num=$((i + 1))
    RPCS+=($vmid)
    VMID_TO_NODE_TYPE[$vmid]="rpc"
    VMID_TO_NODE_NAME[$vmid]="rpc-$rpc_num"
done

ALL_BESU=("${VALIDATORS[@]}" "${SENTRIES[@]}" "${RPCS[@]}")

VALIDATION_ERRORS=0
VALIDATION_WARNINGS=0

# Expected file locations by node type
declare -A EXPECTED_FILES_VALIDATOR
EXPECTED_FILES_VALIDATOR["/etc/besu/genesis.json"]="genesis.json"
EXPECTED_FILES_VALIDATOR["/etc/besu/config-validator.toml"]="config-validator.toml"
EXPECTED_FILES_VALIDATOR["/etc/besu/permissions-nodes.toml"]="permissions-nodes.toml"
EXPECTED_FILES_VALIDATOR["/etc/besu/permissions-accounts.toml"]="permissions-accounts.toml"
EXPECTED_FILES_VALIDATOR["/etc/besu/static-nodes.json"]="static-nodes.json"
# Add validator key directories dynamically
for ((i=1; i<=VALIDATOR_COUNT; i++)); do
    EXPECTED_FILES_VALIDATOR["/keys/validators/validator-$i"]="validator keys directory"
done

declare -A EXPECTED_FILES_SENTRY
EXPECTED_FILES_SENTRY["/etc/besu/genesis.json"]="genesis.json"
EXPECTED_FILES_SENTRY["/etc/besu/config-sentry.toml"]="config-sentry.toml"
EXPECTED_FILES_SENTRY["/etc/besu/permissions-nodes.toml"]="permissions-nodes.toml"
EXPECTED_FILES_SENTRY["/etc/besu/permissions-accounts.toml"]="permissions-accounts.toml"
EXPECTED_FILES_SENTRY["/etc/besu/static-nodes.json"]="static-nodes.json"

declare -A EXPECTED_FILES_RPC
EXPECTED_FILES_RPC["/etc/besu/genesis.json"]="genesis.json"
EXPECTED_FILES_RPC["/etc/besu/config-rpc-public.toml"]="config-rpc-public.toml"
EXPECTED_FILES_RPC["/etc/besu/permissions-nodes.toml"]="permissions-nodes.toml"
EXPECTED_FILES_RPC["/etc/besu/permissions-accounts.toml"]="permissions-accounts.toml"
EXPECTED_FILES_RPC["/etc/besu/static-nodes.json"]="static-nodes.json"

log_info "========================================="
log_info "Comprehensive Deployment Validation"
log_info "========================================="
log_info ""

# ============================================================================
# Validation 1: Node Count and Types
# ============================================================================
log_info "=== Validation 1: Node Count and Types ==="

EXPECTED_VALIDATORS=$VALIDATOR_COUNT
EXPECTED_SENTRIES=$SENTRY_COUNT
EXPECTED_RPCS=$RPC_COUNT
EXPECTED_TOTAL=$((EXPECTED_VALIDATORS + EXPECTED_SENTRIES + EXPECTED_RPCS))

ACTUAL_VALIDATORS=0
ACTUAL_SENTRIES=0
ACTUAL_RPCS=0
ACTUAL_TOTAL=0

for vmid in "${ALL_BESU[@]}"; do
    # Check if container exists: pct status returns 0 if container exists
    if pct status "$vmid" &>/dev/null; then
        ACTUAL_TOTAL=$((ACTUAL_TOTAL + 1))
        node_type="${VMID_TO_NODE_TYPE[$vmid]}"
        case "$node_type" in
            validator) ACTUAL_VALIDATORS=$((ACTUAL_VALIDATORS + 1)) ;;
            sentry) ACTUAL_SENTRIES=$((ACTUAL_SENTRIES + 1)) ;;
            rpc) ACTUAL_RPCS=$((ACTUAL_RPCS + 1)) ;;
        esac
    fi
done

if [[ $ACTUAL_VALIDATORS -eq $EXPECTED_VALIDATORS ]]; then
    log_success "✓ Validator count correct: $ACTUAL_VALIDATORS"
else
    log_error "✗ Validator count mismatch: expected $EXPECTED_VALIDATORS, found $ACTUAL_VALIDATORS"
    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi

if [[ $ACTUAL_SENTRIES -eq $EXPECTED_SENTRIES ]]; then
    log_success "✓ Sentry count correct: $ACTUAL_SENTRIES"
else
    log_error "✗ Sentry count mismatch: expected $EXPECTED_SENTRIES, found $ACTUAL_SENTRIES"
    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi

if [[ $ACTUAL_RPCS -eq $EXPECTED_RPCS ]]; then
    log_success "✓ RPC count correct: $ACTUAL_RPCS"
else
    log_error "✗ RPC count mismatch: expected $EXPECTED_RPCS, found $ACTUAL_RPCS"
    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi

log_info ""

# ============================================================================
# Validation 2: Correct Templates Used
# ============================================================================
log_info "=== Validation 2: Correct Configuration Templates ==="

for vmid in "${VALIDATORS[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        if pct exec "$vmid" -- test -f /etc/besu/config-validator.toml 2>/dev/null; then
            log_success "✓ Container $vmid: config-validator.toml present"
        else
            log_error "✗ Container $vmid: config-validator.toml missing"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
        
        # Should NOT have sentry or RPC config
        if pct exec "$vmid" -- test -f /etc/besu/config-sentry.toml 2>/dev/null; then
            log_error "✗ Container $vmid: config-sentry.toml should not exist (validator)"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
        if pct exec "$vmid" -- test -f /etc/besu/config-rpc-public.toml 2>/dev/null; then
            log_error "✗ Container $vmid: config-rpc-public.toml should not exist (validator)"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    fi
done

for vmid in "${SENTRIES[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        if pct exec "$vmid" -- test -f /etc/besu/config-sentry.toml 2>/dev/null; then
            log_success "✓ Container $vmid: config-sentry.toml present"
        else
            log_error "✗ Container $vmid: config-sentry.toml missing"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    fi
done

# RPC nodes - check for type-specific config files
declare -A RPC_VMID_TO_CONFIG
RPC_VMID_TO_CONFIG[2500]="config-rpc-core.toml"      # Core RPC
RPC_VMID_TO_CONFIG[2501]="config-rpc-perm.toml"      # Permissioned RPC
RPC_VMID_TO_CONFIG[2502]="config-rpc-public.toml"    # Public RPC

for vmid in "${RPCS[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        expected_config="${RPC_VMID_TO_CONFIG[$vmid]}"
        if [[ -z "$expected_config" ]]; then
            log_warn "⚠ Container $vmid: Unknown RPC type, checking for any RPC config"
            expected_config="config-rpc-public.toml"
        fi
        
        if pct exec "$vmid" -- test -f "/etc/besu/$expected_config" 2>/dev/null; then
            log_success "✓ Container $vmid: $expected_config present"
        else
            log_error "✗ Container $vmid: $expected_config missing"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    fi
done

log_info ""

# ============================================================================
# Validation 3: All Required Files Copied to Correct Locations
# ============================================================================
log_info "=== Validation 3: Required Files in Correct Locations ==="

validate_files_for_node_type() {
    local vmid=$1
    local node_type=$2
    local -n expected_files=$3
    
    for file_path in "${!expected_files[@]}"; do
        local file_desc="${expected_files[$file_path]}"
        if pct exec "$vmid" -- test -f "$file_path" 2>/dev/null || pct exec "$vmid" -- test -d "$file_path" 2>/dev/null; then
            log_success "  ✓ Container $vmid: $file_path exists"
        else
            log_error "  ✗ Container $vmid: $file_path missing ($file_desc)"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    done
}

for vmid in "${VALIDATORS[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        log_info "Checking validator $vmid..."
        validate_files_for_node_type "$vmid" "validator" EXPECTED_FILES_VALIDATOR
    fi
done

for vmid in "${SENTRIES[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        log_info "Checking sentry $vmid..."
        validate_files_for_node_type "$vmid" "sentry" EXPECTED_FILES_SENTRY
    fi
done

for vmid in "${RPCS[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        log_info "Checking RPC $vmid..."
        validate_files_for_node_type "$vmid" "rpc" EXPECTED_FILES_RPC
    fi
done

log_info ""

# ============================================================================
# Validation 4: Genesis.json Validation
# ============================================================================
log_info "=== Validation 4: Genesis.json Validation ==="

# Check genesis.json exists on all nodes and is identical
GENESIS_SAMPLE=""
FIRST_VMID=""

for vmid in "${ALL_BESU[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        if pct exec "$vmid" -- test -f /etc/besu/genesis.json 2>/dev/null; then
            if [[ -z "$GENESIS_SAMPLE" ]]; then
                FIRST_VMID="$vmid"
                GENESIS_SAMPLE=$(pct exec "$vmid" -- cat /etc/besu/genesis.json 2>/dev/null | python3 -m json.tool 2>/dev/null)
                GENESIS_HASH=$(echo "$GENESIS_SAMPLE" | sha256sum | cut -d' ' -f1)
                log_success "✓ Genesis.json found on container $vmid"
            else
                CURRENT_GENESIS=$(pct exec "$vmid" -- cat /etc/besu/genesis.json 2>/dev/null | python3 -m json.tool 2>/dev/null)
                CURRENT_HASH=$(echo "$CURRENT_GENESIS" | sha256sum | cut -d' ' -f1)
                if [[ "$GENESIS_HASH" == "$CURRENT_HASH" ]]; then
                    log_success "✓ Container $vmid: genesis.json matches"
                else
                    log_error "✗ Container $vmid: genesis.json differs from container $FIRST_VMID"
                    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
                fi
            fi
        else
            log_error "✗ Container $vmid: genesis.json missing"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    fi
done

# Validate genesis.json structure
if [[ -n "$GENESIS_SAMPLE" ]]; then
    log_info "Validating genesis.json structure..."
    
    # Check for QBFT configuration
    if echo "$GENESIS_SAMPLE" | python3 -c "import sys, json; data=json.load(sys.stdin); exit(0 if 'config' in data and 'qbft' in data.get('config', {}) else 1)" 2>/dev/null; then
        log_success "✓ QBFT configuration present in genesis.json"
    else
        log_error "✗ QBFT configuration missing in genesis.json"
        VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
    fi
    
    # Check for extraData (should exist but may be empty for dynamic validators)
    if echo "$GENESIS_SAMPLE" | python3 -c "import sys, json; data=json.load(sys.stdin); exit(0 if 'extraData' in data else 1)" 2>/dev/null; then
        log_success "✓ extraData field present in genesis.json"
        
        # Validate extraData format (should be hex string)
        EXTRA_DATA=$(echo "$GENESIS_SAMPLE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('extraData', ''))" 2>/dev/null)
        if [[ "$EXTRA_DATA" =~ ^0x[0-9a-fA-F]*$ ]] || [[ -z "$EXTRA_DATA" ]]; then
            log_success "✓ extraData format valid"
        else
            log_error "✗ extraData format invalid: $EXTRA_DATA"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    else
        log_error "✗ extraData field missing in genesis.json"
        VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
    fi
    
    # For dynamic validators, QBFT config should exist but validators array should NOT
    if echo "$GENESIS_SAMPLE" | python3 -c "import sys, json; data=json.load(sys.stdin); qbft=data.get('config', {}).get('qbft', {}); exit(0 if 'validators' not in qbft else 1)" 2>/dev/null; then
        log_success "✓ Dynamic validator setup confirmed (no validators array in QBFT config)"
    else
        log_warn "⚠ Validators array found in QBFT config (expected for dynamic validators)"
        VALIDATION_WARNINGS=$((VALIDATION_WARNINGS + 1))
    fi
else
    log_error "✗ Could not validate genesis.json (file not found)"
    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi

log_info ""

# ============================================================================
# Validation 5: Validator Keys Validation
# ============================================================================
log_info "=== Validation 5: Validator Keys Validation ==="

for vmid in "${VALIDATORS[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        validator_name="${VMID_TO_NODE_NAME[$vmid]}"
        keys_dir="/keys/validators/$validator_name"
        
        if pct exec "$vmid" -- test -d "$keys_dir" 2>/dev/null; then
            log_success "✓ Container $vmid: Validator keys directory exists: $keys_dir"
            
            # Check for required key files
            for key_file in "key.pem" "address.txt"; do
                if pct exec "$vmid" -- test -f "$keys_dir/$key_file" 2>/dev/null; then
                    log_success "  ✓ Container $vmid: $key_file exists"
                else
                    log_warn "  ⚠ Container $vmid: $key_file missing (may not be critical)"
                    VALIDATION_WARNINGS=$((VALIDATION_WARNINGS + 1))
                fi
            done
            
            # Validate address format if present
            if pct exec "$vmid" -- test -f "$keys_dir/address.txt" 2>/dev/null; then
                ADDRESS=$(pct exec "$vmid" -- cat "$keys_dir/address.txt" 2>/dev/null | tr -d '[:space:]')
                if [[ "$ADDRESS" =~ ^0x[0-9a-fA-F]{40}$ ]]; then
                    log_success "  ✓ Container $vmid: Validator address format valid: $ADDRESS"
                else
                    log_error "  ✗ Container $vmid: Invalid validator address format: $ADDRESS"
                    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
                fi
            fi
        else
            log_error "✗ Container $vmid: Validator keys directory missing: $keys_dir"
            VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
        fi
    fi
done

log_info ""

# ============================================================================
# Validation 6: Configuration File Consistency
# ============================================================================
log_info "=== Validation 6: Configuration File Consistency ==="

# Check that permissions-nodes.toml is consistent across all nodes
PERMISSIONS_SAMPLE=""
FIRST_VMID=""

for vmid in "${ALL_BESU[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        if pct exec "$vmid" -- test -f /etc/besu/permissions-nodes.toml 2>/dev/null; then
            if [[ -z "$PERMISSIONS_SAMPLE" ]]; then
                FIRST_VMID="$vmid"
                PERMISSIONS_SAMPLE=$(pct exec "$vmid" -- cat /etc/besu/permissions-nodes.toml 2>/dev/null)
                PERMISSIONS_HASH=$(echo "$PERMISSIONS_SAMPLE" | sha256sum | cut -d' ' -f1)
                log_success "✓ permissions-nodes.toml found on container $vmid"
            else
                CURRENT_PERMISSIONS=$(pct exec "$vmid" -- cat /etc/besu/permissions-nodes.toml 2>/dev/null)
                CURRENT_HASH=$(echo "$CURRENT_PERMISSIONS" | sha256sum | cut -d' ' -f1)
                if [[ "$PERMISSIONS_HASH" == "$CURRENT_HASH" ]]; then
                    log_success "✓ Container $vmid: permissions-nodes.toml matches"
                else
                    log_error "✗ Container $vmid: permissions-nodes.toml differs from container $FIRST_VMID"
                    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
                fi
            fi
        fi
    fi
done

# Check static-nodes.json consistency
STATIC_NODES_SAMPLE=""
FIRST_VMID=""

for vmid in "${ALL_BESU[@]}"; do
    if pct status "$vmid" &>/dev/null; then
        if pct exec "$vmid" -- test -f /etc/besu/static-nodes.json 2>/dev/null; then
            if [[ -z "$STATIC_NODES_SAMPLE" ]]; then
                FIRST_VMID="$vmid"
                STATIC_NODES_SAMPLE=$(pct exec "$vmid" -- cat /etc/besu/static-nodes.json 2>/dev/null | python3 -m json.tool 2>/dev/null)
                STATIC_NODES_HASH=$(echo "$STATIC_NODES_SAMPLE" | sha256sum | cut -d' ' -f1)
                log_success "✓ static-nodes.json found on container $vmid"
            else
                CURRENT_STATIC=$(pct exec "$vmid" -- cat /etc/besu/static-nodes.json 2>/dev/null | python3 -m json.tool 2>/dev/null)
                CURRENT_HASH=$(echo "$CURRENT_STATIC" | sha256sum | cut -d' ' -f1)
                if [[ "$STATIC_NODES_HASH" == "$CURRENT_HASH" ]]; then
                    log_success "✓ Container $vmid: static-nodes.json matches"
                else
                    log_error "✗ Container $vmid: static-nodes.json differs from container $FIRST_VMID"
                    VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
                fi
            fi
        fi
    fi
done

log_info ""

# ============================================================================
# Summary
# ============================================================================
log_info "========================================="
log_info "Validation Summary"
log_info "========================================="
log_info "Errors: $VALIDATION_ERRORS"
log_info "Warnings: $VALIDATION_WARNINGS"
log_info ""

if [[ $VALIDATION_ERRORS -eq 0 ]]; then
    if [[ $VALIDATION_WARNINGS -eq 0 ]]; then
        log_success "✓ All validations passed!"
        exit 0
    else
        log_warn "⚠ Validations passed with $VALIDATION_WARNINGS warning(s)"
        log_info "Review warnings above, but deployment is acceptable"
        exit 0
    fi
else
    log_error "✗ Validation failed with $VALIDATION_ERRORS error(s)"
    log_info "Please fix the errors before proceeding"
    exit 1
fi

