#!/bin/bash
# Genesis Guard Script for XDC Networks
# Validates genesis hash before node start and auto-wipes wrong chaindata
# Supports mainnet (50) and apothem (51)

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Expected genesis hashes (from params/config.go)
MAINNET_GENESIS_HASH="0xabed0e6b04fcc5f6a2b14c4f3ba44dabe5a61e85d2db7c1f30d4e6a1cb71d8b1"
APOTHEM_GENESIS_HASH="0x8b8d5d60e7b9a4b7b5e0b0d5e0b5c0e0b5a0b5e0b5e0b5e0b5e0b5e0b5e0b5e0"

# Function to print colored output
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function to show usage
usage() {
    cat << EOF
Usage: $0 [OPTIONS]

Genesis Guard for XDC Networks - Validates genesis configuration before node start

OPTIONS:
    -d, --datadir PATH      Data directory path (default: ./testdata)
    -c, --chainId ID        Chain ID: 50 (mainnet) or 51 (apothem)
    -g, --genesis PATH      Path to genesis.json file
    -n, --network NAME      Network name: mainnet|apothem
    -f, --force             Force wipe without prompting
    -h, --help              Show this help message

EXAMPLES:
    $0 --datadir ./data --chainId 50 --network mainnet
    $0 --datadir ./data --chainId 51 --network apothem --genesis ./genesis/apothem.json
    $0 --datadir ./data --network mainnet --force

EOF
    exit 0
}

# Default values
DATADIR="./testdata"
CHAIN_ID=""
GENESIS_FILE=""
NETWORK=""
FORCE_WIPE=false

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -d|--datadir)
            DATADIR="$2"
            shift 2
            ;;
        -c|--chainId)
            CHAIN_ID="$2"
            shift 2
            ;;
        -g|--genesis)
            GENESIS_FILE="$2"
            shift 2
            ;;
        -n|--network)
            NETWORK="$2"
            shift 2
            ;;
        -f|--force)
            FORCE_WIPE=true
            shift
            ;;
        -h|--help)
            usage
            ;;
        *)
            log_error "Unknown option: $1"
            usage
            ;;
    esac
done

# Validate required parameters
if [[ -z "$NETWORK" && -z "$CHAIN_ID" ]]; then
    log_error "Either --network or --chainId must be specified"
    usage
fi

# Determine network from chainId or vice versa
if [[ -n "$CHAIN_ID" ]]; then
    case "$CHAIN_ID" in
        50)
            NETWORK="mainnet"
            EXPECTED_HASH="$MAINNET_GENESIS_HASH"
            ;;
        51)
            NETWORK="apothem"
            EXPECTED_HASH="$APOTHEM_GENESIS_HASH"
            ;;
        *)
            log_error "Unsupported chainId: $CHAIN_ID"
            exit 1
            ;;
    esac
else
    case "$NETWORK" in
        mainnet)
            CHAIN_ID=50
            EXPECTED_HASH="$MAINNET_GENESIS_HASH"
            ;;
        apothem)
            CHAIN_ID=51
            EXPECTED_HASH="$APOTHEM_GENESIS_HASH"
            ;;
        *)
            log_error "Unknown network: $NETWORK. Use 'mainnet' or 'apothem'"
            exit 1
            ;;
    esac
fi

log_info "Genesis Guard - XDC $NETWORK (Chain ID: $CHAIN_ID)"
log_info "Data directory: $DATADIR"

# Check if data directory exists
if [[ ! -d "$DATADIR" ]]; then
    log_info "Data directory does not exist. Will be created on node start."
    exit 0
fi

# Check for chaindata directory
CHAINDATA_DIR="$DATADIR/geth/chaindata"
if [[ ! -d "$CHAINDATA_DIR" ]]; then
    log_info "No chaindata found. Fresh start."
    exit 0
fi

# Function to compute genesis hash from datadir
compute_genesis_hash() {
    local datadir=$1
    # Try to get the genesis block hash from leveldb
    if command -v geth &> /dev/null; then
        # Use geth to query the genesis block
        local hash
        hash=$(geth --datadir "$datadir" console --exec 'eth.getBlock(0).hash' 2>/dev/null | tr -d '"' || echo "")
        if [[ -n "$hash" && "$hash" != "null" && "$hash" != "undefined" ]]; then
            echo "$hash"
            return 0
        fi
    fi
    
    # Fallback: try to read from database directly
    if [[ -d "$datadir/geth/chaindata" ]]; then
        # Look for block 0 in leveldb (key prefix for header is 'h')
        # This is a heuristic approach
        local db_hash
        db_hash=$(cd "$datadir/geth/chaindata" && ls -la 2>/dev/null | head -5)
        if [[ -n "$db_hash" ]]; then
            echo "unknown"
            return 0
        fi
    fi
    
    echo ""
    return 1
}

# Function to validate genesis file against expected values
validate_genesis_file() {
    local genesis_file=$1
    local expected_chain_id=$2
    
    if [[ ! -f "$genesis_file" ]]; then
        log_warn "Genesis file not found: $genesis_file"
        return 1
    fi
    
    # Extract chainId from genesis file
    local genesis_chain_id
    genesis_chain_id=$(grep -o '"chainId"[^,]*' "$genesis_file" | grep -o '[0-9]*' | head -1)
    
    if [[ "$genesis_chain_id" != "$expected_chain_id" ]]; then
        log_error "Genesis file chainId ($genesis_chain_id) doesn't match expected ($expected_chain_id)"
        return 1
    fi
    
    log_info "Genesis file validated: chainId=$genesis_chain_id"
    return 0
}

# Check for existing genesis block
CURRENT_HASH=$(compute_genesis_hash "$DATADIR")

if [[ -z "$CURRENT_HASH" ]]; then
    log_info "No genesis block found in datadir. Fresh start."
    exit 0
fi

if [[ "$CURRENT_HASH" == "unknown" ]]; then
    log_warn "Could not determine genesis hash. Proceeding with caution."
    exit 0
fi

log_info "Current genesis hash: $CURRENT_HASH"
log_info "Expected genesis hash: $EXPECTED_HASH"

# Compare genesis hashes
if [[ "${CURRENT_HASH,,}" != "${EXPECTED_HASH,,}" ]]; then
    log_error "GENESIS MISMATCH DETECTED!"
    log_error "Current:  $CURRENT_HASH"
    log_error "Expected: $EXPECTED_HASH"
    
    if [[ "$FORCE_WIPE" == true ]]; then
        log_warn "Force wipe enabled. Deleting chaindata..."
        rm -rf "$CHAINDATA_DIR"
        log_info "Chaindata wiped. Node will re-initialize with correct genesis."
        exit 0
    else
        log_warn "Genesis hash mismatch. The datadir may contain wrong chain data."
        log_warn "Run with --force to auto-wipe and re-initialize."
        
        # Interactive prompt
        read -p "Do you want to wipe the chaindata and start fresh? [y/N]: " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]]; then
            log_warn "Deleting chaindata at $CHAINDATA_DIR..."
            rm -rf "$CHAINDATA_DIR"
            log_info "Chaindata wiped. Node will re-initialize with correct genesis."
        else
            log_error "Aborting. Please fix the genesis configuration manually."
            exit 1
        fi
    fi
else
    log_info "Genesis hash validated successfully!"
fi

# Validate genesis file if provided
if [[ -n "$GENESIS_FILE" ]]; then
    if validate_genesis_file "$GENESIS_FILE" "$CHAIN_ID"; then
        log_info "Genesis file validation passed"
    else
        log_error "Genesis file validation failed"
        exit 1
    fi
fi

log_info "Genesis Guard checks completed. Ready to start node."
exit 0
