#!/bin/bash

BASEPATH="$(dirname "$0")"

if [ $# -lt 2 ]; then
    echo "Error: At least two parameters are required."
    exit 1
fi

RPC_URL=$1
shift

# Check for --starknet / --aztec / --cosmos / --ripple / --bitcoin flag
is_starknet=false
is_aztec=false
is_cosmos=false
is_ripple=false
is_bitcoin=false
if [ "$1" == "--starknet" ]; then
    is_starknet=true
    shift
elif [ "$1" == "--aztec" ]; then
    is_aztec=true
    shift
elif [ "$1" == "--cosmos" ]; then
    is_cosmos=true
    shift
elif [ "$1" == "--ripple" ]; then
    is_ripple=true
    shift
elif [ "$1" == "--bitcoin" ]; then
    is_bitcoin=true
    shift
fi

REF=""
for url in "$@"; do
    REF+="--url $url "
done

# Optional: You can remove the trailing space if needed
ref=${REF% }

# echo "ref: $ref"

timeout=3 # seconds

# CometBFT / cosmos (gaiad and the cosmos batch): no EVM RPC. Use the chain's own
# sync_info from the CometBFT /status method — catching_up=false means caught up to head.
# Short-circuits here; the EVM/starknet/aztec block-comparison path below is not used.
if $is_cosmos; then
    status=$(curl -L --ipv4 -m $timeout -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","id":1,"method":"status"}' "$RPC_URL")
    if [ $? -ne 0 ] || [ -z "$status" ]; then echo "timeout"; exit 1; fi
    catching_up=$(echo "$status" | jq -r '.result.sync_info.catching_up // .sync_info.catching_up' 2>/dev/null)
    node_height=$(echo "$status" | jq -r '.result.sync_info.latest_block_height // .sync_info.latest_block_height' 2>/dev/null)
    if [ -z "$node_height" ] || [ "$node_height" = "null" ]; then echo "error"; exit 1; fi
    if [ "$catching_up" = "true" ]; then echo "syncing"; exit 1; fi
    # catching_up=false => synced. If a reference endpoint is given, sanity-check head gap.
    if [ -n "$ref" ]; then
        ref_status=$($BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","id":1,"method":"status"}' $ref)
        ref_height=$(echo "$ref_status" | jq -r '.result.sync_info.latest_block_height // .sync_info.latest_block_height' 2>/dev/null)
        if [ -n "$ref_height" ] && [ "$ref_height" != "null" ] && [ "$ref_height" -gt 0 ] 2>/dev/null; then
            gap=$(( ref_height - node_height ))
            if [ "$gap" -gt 100 ]; then echo "behind ($gap)"; exit 1; fi
        fi
    fi
    echo "online"; exit 0
fi

# XRPL rippled: server_info — server_state full/proposing + fresh validated ledger = online.
# Short-circuits here; the EVM/starknet/aztec block-comparison path below is not used.
if $is_ripple; then
    status=$(curl -L --ipv4 -m $timeout -s -X POST -H "Content-Type: application/json" --data '{"method":"server_info"}' "$RPC_URL")
    if [ $? -ne 0 ] || [ -z "$status" ]; then echo "error"; exit 1; fi
    server_state=$(echo "$status" | jq -r '.result.info.server_state // .info.server_state' 2>/dev/null)
    ledger_age=$(echo "$status" | jq -r '.result.info.validated_ledger.age // .info.validated_ledger.age' 2>/dev/null)
    node_seq=$(echo "$status" | jq -r '.result.info.validated_ledger.seq // .info.validated_ledger.seq' 2>/dev/null)
    if [ -z "$server_state" ] || [ "$server_state" = "null" ]; then echo "error"; exit 1; fi
    case "$server_state" in
        connected|syncing|tracking)
            echo "syncing"; exit 1 ;;
        full|proposing)
            ;;
        *)
            echo "error"; exit 1 ;;
    esac
    if [ -z "$ledger_age" ] || [ "$ledger_age" = "null" ] || [ "$ledger_age" -gt 20 ] 2>/dev/null; then
        echo "behind"; exit 1
    fi
    if [ -n "$ref" ]; then
        ref_status=$($BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -H "Content-Type: application/json" --data '{"method":"server_info"}' $ref)
        ref_seq=$(echo "$ref_status" | jq -r '.result.info.validated_ledger.seq // .info.validated_ledger.seq' 2>/dev/null)
        if [ -n "$ref_seq" ] && [ "$ref_seq" != "null" ] && [ "$ref_seq" -gt 0 ] 2>/dev/null && [ -n "$node_seq" ] && [ "$node_seq" != "null" ]; then
            lag=$(( ref_seq - node_seq ))
            lo=${LAGGING_LAG:-5}; hi=${SYNCING_LAG:-10}
            if [ "$lo" -gt "$hi" ]; then tmp=$lo; lo=$hi; hi=$tmp; fi
            if [ "$lag" -le "$lo" ]; then
                echo "online"; exit 0
            elif [ "$lag" -le "$hi" ]; then
                echo "lagging"; exit 0
            else
                echo "syncing"; exit 1
            fi
        fi
    fi
    echo "online"; exit 0
fi

# Bitcoin-family (bitcoind/dogecoind): getblockchaininfo — initialblockdownload=true means syncing.
# Short-circuits here; the EVM/starknet/aztec block-comparison path below is not used.
if $is_bitcoin; then
    status=$(curl -L --ipv4 -m $timeout -s -u username:password -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"1.0","id":1,"method":"getblockchaininfo","params":[]}' "$RPC_URL")
    if [ $? -ne 0 ] || [ -z "$status" ]; then echo "error"; exit 1; fi
    ibd=$(echo "$status" | jq -r '.result.initialblockdownload' 2>/dev/null)
    node_height=$(echo "$status" | jq -r '.result.blocks' 2>/dev/null)
    if [ -z "$node_height" ] || [ "$node_height" = "null" ]; then echo "error"; exit 1; fi
    if [ "$ibd" = "true" ]; then echo "syncing"; exit 1; fi
    if [ -n "$ref" ]; then
        ref_status=$($BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"1.0","id":1,"method":"getblockcount","params":[]}' $ref)
        ref_height=$(echo "$ref_status" | jq -r '.result' 2>/dev/null)
        if [ -n "$ref_height" ] && [ "$ref_height" != "null" ] && [ "$ref_height" -gt 0 ] 2>/dev/null; then
            lag=$(( ref_height - node_height ))
            lo=${LAGGING_LAG:-2}; hi=${SYNCING_LAG:-6}
            if [ "$lo" -gt "$hi" ]; then tmp=$lo; lo=$hi; hi=$tmp; fi
            if [ "$lag" -le "$lo" ]; then
                echo "online"; exit 0
            elif [ "$lag" -le "$hi" ]; then
                echo "lagging"; exit 0
            else
                echo "syncing"; exit 1
            fi
        fi
    fi
    echo "online"; exit 0
fi

response_file=$(mktemp)

# Use appropriate RPC method based on chain type
if $is_starknet; then
    rpc_method='{"jsonrpc":"2.0","method":"starknet_getBlockWithTxHashes","params":["latest"],"id":1}'
elif $is_aztec; then
    rpc_method='{"jsonrpc":"2.0","method":"node_getBlock","params":["latest"],"id":1}'
else
    rpc_method='{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", false],"id":1}'
fi

http_status_code=$(curl -L --ipv4 -m $timeout -s -X POST -w "%{http_code}" -o "$response_file" -H "Content-Type: application/json" --data "$rpc_method" $RPC_URL)

if [ $? -eq 0 ]; then
    if [[ $http_status_code -eq 200 ]]; then
        response=$(cat "$response_file")

        if $is_starknet; then
            # Starknet returns decimal timestamp and block_number
            latest_block_timestamp_decimal=$(echo "$response" | jq -r '.result.timestamp')
            latest_block_number=$(echo "$response" | jq -r '.result.block_number')
            latest_block_hash=$(echo "$response" | jq -r '.result.block_hash')
        elif $is_aztec; then
            # Aztec: node_getBlock("latest") returns blockHash, header.globalVariables.blockNumber, header.globalVariables.timestamp
            latest_block_number=$(echo "$response" | jq -r '.result.header.globalVariables.blockNumber')
            latest_block_timestamp_decimal=$(echo "$response" | jq -r '.result.header.globalVariables.timestamp')
            latest_block_hash=$(echo "$response" | jq -r '.result.blockHash')
            if [ "$latest_block_number" = "null" ] || [ "$latest_block_timestamp_decimal" = "null" ] || [ -z "$latest_block_timestamp_decimal" ]; then
                echo "error"
                exit 1
            fi
        else
            # Ethereum returns hex timestamp and number
            latest_block_timestamp=$(echo "$response" | jq -r '.result.timestamp')
            latest_block_timestamp_decimal=$((16#${latest_block_timestamp#0x}))
            latest_block_number=$(echo "$response" | jq -r '.result.number')
            latest_block_hash=$(echo "$response" | jq -r '.result.hash')
        fi

        current_time=$(date +%s)
        time_difference=$((current_time - latest_block_timestamp_decimal))

        rm "$response_file"

        if [ -n "$ref" ]; then
            MAX_RETRIES=3
            attempt=1
            
            while [ $attempt -le $MAX_RETRIES ]; do
                # Re-fetch local latest block for retries > 1
                if [ $attempt -gt 1 ]; then
                    sleep 3
                    # Re-query local latest block and update variables
                    response_file=$(mktemp)
                    http_status_code=$(curl -L --ipv4 -m $timeout -s -X POST -w "%{http_code}" -o "$response_file" -H "Content-Type: application/json" --data "$rpc_method" $RPC_URL)
                    if [ $? -eq 0 ] && [[ $http_status_code -eq 200 ]]; then
                        response=$(cat "$response_file")
                        if $is_starknet; then
                            latest_block_timestamp_decimal=$(echo "$response" | jq -r '.result.timestamp')
                            latest_block_number=$(echo "$response" | jq -r '.result.block_number')
                            latest_block_hash=$(echo "$response" | jq -r '.result.block_hash')
                        elif $is_aztec; then
                            latest_block_number=$(echo "$response" | jq -r '.result.header.globalVariables.blockNumber')
                            latest_block_timestamp_decimal=$(echo "$response" | jq -r '.result.header.globalVariables.timestamp')
                            latest_block_hash=$(echo "$response" | jq -r '.result.blockHash')
                            if [ "$latest_block_number" = "null" ] || [ "$latest_block_timestamp_decimal" = "null" ] || [ -z "$latest_block_timestamp_decimal" ]; then
                                echo "error"
                                exit 1
                            fi
                        else
                            latest_block_timestamp=$(echo "$response" | jq -r '.result.timestamp')
                            latest_block_timestamp_decimal=$((16#${latest_block_timestamp#0x}))
                            latest_block_number=$(echo "$response" | jq -r '.result.number')
                            latest_block_hash=$(echo "$response" | jq -r '.result.hash')
                        fi
                        current_time=$(date +%s)
                        time_difference=$((current_time - latest_block_timestamp_decimal))
                        rm "$response_file"
                    else
                        rm "$response_file"
                        echo "error"
                        exit 1
                    fi
                fi
                
                response_file2=$(mktemp)

                if [ $attempt -eq 1 ]; then
                    sleep 3 # to give the reference node more time to import the block if it is very current
                fi

            if $is_starknet; then
                # Starknet uses block_id object with block_number
                rpc_method2="{\"jsonrpc\":\"2.0\",\"method\":\"starknet_getBlockWithTxHashes\",\"params\":[{\"block_number\":$latest_block_number}],\"id\":1}"
            elif $is_aztec; then
                rpc_method2="{\"jsonrpc\":\"2.0\",\"method\":\"node_getBlock\",\"params\":[$latest_block_number],\"id\":1}"
            else
                rpc_method2="{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNumber\",\"params\":[\"$latest_block_number\", false],\"id\":1}"
            fi

            http_status_code2=$($BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -w "%{http_code}" -o "$response_file2" -H "Content-Type: application/json" --data "$rpc_method2" $ref)

	    curl_code2=$?

            if [ $curl_code2 -eq 0 ]; then
                if [[ $http_status_code2 -eq 200 ]]; then
                    response2=$(cat "$response_file2")
                    if $is_starknet; then
                        latest_block_hash2=$(echo "$response2" | jq -r '.result.block_hash')
                    elif $is_aztec; then
                        latest_block_hash2=$(echo "$response2" | jq -r '.result.blockHash')
                    else
                        latest_block_hash2=$(echo "$response2" | jq -r '.result.hash')
                    fi

                    rm "$response_file2"
                    
                    # Proceed if hashes match (or both empty for Aztec when API omits hash)
                    if [ "$latest_block_hash" == "$latest_block_hash2" ]; then
                        response_file3=$(mktemp)
			status_file3=$(mktemp)

                        if $is_aztec; then
                            # Aztec: node_getBlock("latest") - same single-request pattern as eth/starknet
                            rpc_method_latest='{"jsonrpc":"2.0","method":"node_getBlock","params":["latest"],"id":1}'
                            {
                                $BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -w "%{http_code} %{time_total}" -o "$response_file3" -H "Content-Type: application/json" --data "$rpc_method_latest" $ref > "$status_file3"
                            } &
                            pid3=$!
                            response_file4=$(mktemp)
                            status_file4=$(mktemp)
                            {
                                curl -L --ipv4 -m $timeout -s -X POST -w "%{http_code} %{time_total}" -o "$response_file4" -H "Content-Type: application/json" --data "$rpc_method_latest" $RPC_URL > "$status_file4"
                            } &
                            pid4=$!
                        else
                            if $is_starknet; then
                                rpc_method_latest='{"jsonrpc":"2.0","method":"starknet_getBlockWithTxHashes","params":["latest"],"id":1}'
                            else
                                rpc_method_latest='{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", false],"id":1}'
                            fi
                            {
			        $BASEPATH/multicurl.sh -L --ipv4 -m $timeout -s -X POST -w "%{http_code} %{time_total}" -o "$response_file3" -H "Content-Type: application/json" --data "$rpc_method_latest" $ref > "$status_file3"
			    } &
			    pid3=$!
			    response_file4=$(mktemp)
			    status_file4=$(mktemp)
			    {
			        curl -L --ipv4 -m $timeout -s -X POST -w "%{http_code} %{time_total}" -o "$response_file4" -H "Content-Type: application/json" --data "$rpc_method_latest" $RPC_URL > "$status_file4"
			    } &
			    pid4=$!
                        fi

			wait $pid3
			curl_code3=$?
			http_status_code3=$(cat "$status_file3" | cut -d ' ' -f 1)
			request_time3=$(cat "$status_file3" | cut -d ' ' -f 2)
			rm "$status_file3"

			wait $pid4
			curl_code4=$?
			http_status_code4=$(cat "$status_file4" | cut -d ' ' -f 1)
			request_time4=$(cat "$status_file4" | cut -d ' ' -f 2)			
			rm "$status_file4"
			
			# echo "lets check"
			
			if [ $curl_code3 -eq 0 ]; then
                            if [[ $http_status_code3 -eq 200 ]]; then
                                response3=$(cat "$response_file3")

                                if $is_starknet; then
                                    ref_num=$(echo "$response3" | jq -r '.result.block_number // empty')
                                elif $is_aztec; then
                                    ref_num=$(echo "$response3" | jq -r '.result.header.globalVariables.blockNumber // empty')
                                else
                                    ref_num_hex=$(echo "$response3" | jq -r '.result.number // empty')
                                    ref_num=$([ -n "$ref_num_hex" ] && printf '%d' "$ref_num_hex" 2>/dev/null)
                                fi

				# echo "refer: $latest_block_timestamp_decimal3"
                                rm "$response_file3"

				if [ $curl_code4 -eq 0 ]; then
				    if [[ $http_status_code4 -eq 200 ]]; then
					response4=$(cat "$response_file4")

					if $is_starknet; then
					    local_num=$(echo "$response4" | jq -r '.result.block_number // empty')
					elif $is_aztec; then
					    local_num=$(echo "$response4" | jq -r '.result.header.globalVariables.blockNumber // empty')
					else
					    local_num_hex=$(echo "$response4" | jq -r '.result.number // empty')
					    local_num=$([ -n "$local_num_hex" ] && printf '%d' "$local_num_hex" 2>/dev/null)
					fi

					#echo "local: $latest_block_timestamp_decimal4"
					rm "$response_file4"
				
					# Lag in BLOCKS between the reference head and the local head
					# (positive => local behind). Compare against dRPC's own per-chain
					# thresholds (LAGGING_LAG / SYNCING_LAG from chains.yaml via
					# sync-status.sh) so our status matches the dRPC gateway's view.
					# dRPC uses the two thresholds inconsistently (sometimes
					# lagging<syncing, sometimes the reverse), so treat the smaller as
					# the online boundary and the larger as the syncing/drop boundary.
					if [ -z "$ref_num" ] || [ -z "$local_num" ]; then
					    echo "error"
					    exit 1
					fi
					lag=$(( ref_num - local_num ))
					lo=${LAGGING_LAG:-2}; hi=${SYNCING_LAG:-6}
					if [ "$lo" -gt "$hi" ]; then tmp=$lo; lo=$hi; hi=$tmp; fi
					if [ "$lag" -le "$lo" ]; then
					    echo "online"
					    exit 0
					elif [ "$lag" -le "$hi" ]; then
					    echo "lagging"
					    exit 0
					else
					    echo "syncing"
					    exit 1
					fi
				    else
					echo "error"
					exit 1
				    fi
                                fi
                            fi
                        fi
                    else
                        # Hash mismatch - retry if we have attempts left
                        if [ $attempt -lt $MAX_RETRIES ]; then
                            rm "$response_file2"
                            attempt=$((attempt + 1))
                            continue
                        else
                            rm "$response_file2"
                            echo "forked"
                            exit 1
                        fi
                    fi
		else 
		    echo "unverified ($http_status_code2)"
		    exit 1
                fi 
            else
                rm "$response_file2"
                if [ $attempt -lt $MAX_RETRIES ]; then
                    attempt=$((attempt + 1))
                    continue
                fi
                echo "unverified (reference unreachable)"
                exit 1
            fi
            done
            
            echo "unverified ($curl_code)"
            exit 0
        elif [ $time_difference -lt 60 ]; then
            echo "online"
            exit 0
        else
            echo "behind"
            exit 1
        fi        
    elif [[ $http_status_code -eq 404 ]]; then
        echo "offline"
        exit 1
    elif [[ $http_status_code -eq 401 ]]; then
        echo "unauthorized"
        exit 1
    elif [[ $http_status_code -eq 500 ]]; then
        echo "error"
        exit 1    
    else
        echo "Unexpected HTTP status code: $http_status_code"
        exit 1
    fi
else
    echo "timeout"
    exit 1        
fi
