#!/usr/bin/env bash
# Update All Oracle Contracts with Current Token Prices
# This script reads the token list and updates oracle contracts for all tokens
# Usage: ./scripts/update-all-oracle-prices.sh [rpc-url] [private-key]

set -euo pipefail

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_detail() { echo -e "${CYAN}[DETAIL]${NC} $1"; }

RPC_URL="${1:-https://rpc-http-pub.d-bis.org}"
PRIVATE_KEY="${2:-${DEPLOYER_PRIVATE_KEY:-}}"

if [ -z "$PRIVATE_KEY" ]; then
    log_error "Private key required"
    log_info "Usage: $0 [rpc-url] [private-key]"
    log_info "   OR: Set DEPLOYER_PRIVATE_KEY environment variable"
    exit 1
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TOKEN_LIST_FILE="${TOKEN_LIST_FILE:-$PROJECT_ROOT/token-lists/lists/dbis-138.tokenlist.json}"

if [ ! -f "$TOKEN_LIST_FILE" ]; then
    log_error "Token list file not found: $TOKEN_LIST_FILE"
    exit 1
fi

echo "========================================="
echo "Update All Oracle Prices"
echo "========================================="
echo ""
log_info "RPC URL: $RPC_URL"
log_info "Token List: $TOKEN_LIST_FILE"
echo ""

# Check RPC connectivity
log_info "Checking RPC connectivity..."
if ! curl -s -X POST -H "Content-Type: application/json" \
    --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
    "$RPC_URL" >/dev/null 2>&1; then
    log_error "RPC is not accessible at $RPC_URL"
    exit 1
fi
log_success "RPC is accessible"
echo ""

# Parse token list and map tokens to CoinGecko IDs
# Token mapping: symbol -> coingecko_id
declare -A TOKEN_MAP=(
    ["ETH"]="ethereum"
    ["WETH"]="ethereum"  # WETH tracks ETH price
    ["WETH10"]="ethereum"  # WETH10 tracks ETH price
    ["LINK"]="chainlink"
    ["ETH-USD"]="ethereum"  # Oracle contract for ETH/USD
)

# Map of oracle addresses (token symbol -> aggregator address)
# Note: Updates go to the aggregator, but dApps read from the proxy
# Aggregator: 0x99b3511a2d315a497c8112c1fdd8d508d4b1e506 (for updates)
# Proxy: 0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6 (for reading)
declare -A ORACLE_ADDRESSES=(
    ["ETH-USD"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506"  # Aggregator address for updates
    ["ETH"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506"
    ["WETH"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506"  # Uses ETH/USD oracle
    ["WETH10"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506"  # Uses ETH/USD oracle
    # ["LINK-USD"]="0x..."  # Would need separate oracle contract
)

# Extract tokens from token list
TOKENS=$(jq -r '.tokens[] | select(.tags[]? | contains("oracle") or contains("pricefeed")) | "\(.symbol)|\(.address)|\(.name)"' "$TOKEN_LIST_FILE" 2>/dev/null || echo "")

if [ -z "$TOKENS" ]; then
    log_warn "No oracle/pricefeed tokens found in token list"
    log_info "Looking for all tokens..."
    TOKENS=$(jq -r '.tokens[] | "\(.symbol)|\(.address)|\(.name)"' "$TOKEN_LIST_FILE" 2>/dev/null || echo "")
fi

if [ -z "$TOKENS" ]; then
    log_error "Could not parse tokens from token list"
    exit 1
fi

# Build list of unique CoinGecko IDs to fetch
COINGECKO_IDS=()
while IFS='|' read -r SYMBOL ADDRESS NAME; do
    if [ -z "$SYMBOL" ]; then continue; fi
    COINGECKO_ID="${TOKEN_MAP[$SYMBOL]}"
    if [ -n "$COINGECKO_ID" ] && [[ ! " ${COINGECKO_IDS[@]} " =~ " ${COINGECKO_ID} " ]]; then
        COINGECKO_IDS+=("$COINGECKO_ID")
    fi
done <<< "$TOKENS"

if [ ${#COINGECKO_IDS[@]} -eq 0 ]; then
    log_error "No valid CoinGecko IDs found for tokens"
    exit 1
fi

log_info "Tokens to update: ${COINGECKO_IDS[*]}"
echo ""

# Fetch prices from CoinGecko
log_info "Fetching prices from CoinGecko..."
COINGECKO_IDS_CSV=$(IFS=,; echo "${COINGECKO_IDS[*]}")
PRICES_JSON=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=${COINGECKO_IDS_CSV}&vs_currencies=usd" 2>/dev/null || echo "{}")

if [ -z "$PRICES_JSON" ] || [ "$PRICES_JSON" = "{}" ]; then
    log_error "Failed to fetch prices from CoinGecko"
    exit 1
fi

log_success "Prices fetched successfully"
echo ""

# Update each oracle
UPDATED=0
FAILED=0

log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log_info "Updating Oracle Contracts"
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

while IFS='|' read -r SYMBOL ADDRESS NAME; do
    if [ -z "$SYMBOL" ]; then continue; fi
    
    # Skip if not an oracle/pricefeed token (unless it's a wrapped token that uses ETH oracle)
    if [[ ! "$NAME" =~ "Price Feed" ]] && [[ ! "$SYMBOL" =~ ^(WETH|WETH10|ETH)$ ]]; then
        continue
    fi
    
    COINGECKO_ID="${TOKEN_MAP[$SYMBOL]}"
    if [ -z "$COINGECKO_ID" ]; then
        log_warn "No CoinGecko mapping for $SYMBOL ($NAME), skipping..."
        continue
    fi
    
    ORACLE_ADDRESS="${ORACLE_ADDRESSES[$SYMBOL]}"
    if [ -z "$ORACLE_ADDRESS" ]; then
        log_warn "No oracle address configured for $SYMBOL, skipping..."
        continue
    fi
    
    # Get price from CoinGecko response
    PRICE=$(echo "$PRICES_JSON" | jq -r ".[\"$COINGECKO_ID\"].usd // empty" 2>/dev/null || echo "")
    
    if [ -z "$PRICE" ] || [ "$PRICE" = "null" ] || [ "$PRICE" = "0" ]; then
        log_error "Could not get price for $SYMBOL (CoinGecko ID: $COINGECKO_ID)"
        ((FAILED++))
        continue
    fi
    
    log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    log_info "Updating: $NAME ($SYMBOL)"
    log_detail "Oracle Address: $ORACLE_ADDRESS"
    log_detail "Current Price: \$$PRICE USD"
    
    # Convert to 8 decimals (oracle format)
    PRICE_DECIMALS=$(python3 << PYEOF
price = float("$PRICE")
decimals = int(price * 100000000)
print(decimals)
PYEOF
)
    
    log_detail "Price in 8 decimals: $PRICE_DECIMALS"
    
    # Check current oracle price
    CURRENT_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \
        "latestRoundData()" \
        --rpc-url "$RPC_URL" 2>/dev/null || echo "")
    
    if [ -n "$CURRENT_ORACLE_DATA" ] && [ "$CURRENT_ORACLE_DATA" != "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ]; then
        CURRENT_ANSWER=$(echo "$CURRENT_ORACLE_DATA" | cut -c 131-194)
        CURRENT_PRICE=$(python3 << PYEOF
answer_hex = "$CURRENT_ANSWER"
answer_int = int(answer_hex, 16)
if answer_int > 2**255:
    answer_int = answer_int - 2**256
price = answer_int / 100000000
print(price)
PYEOF
)
        log_detail "Current oracle price: \$$(printf '%.2f' $CURRENT_PRICE)"
        
        # Check if update is needed (only update if difference > 0.5%)
        PRICE_DIFF=$(python3 << PYEOF
current = float("$CURRENT_PRICE")
new = float("$PRICE")
if current == 0:
    print(100)  # Always update if current is zero
else:
    diff = abs(new - current) / current * 100
    print(diff)
PYEOF
)
        
        if (( $(echo "$PRICE_DIFF < 0.5" | bc -l 2>/dev/null || echo "0") )); then
            log_warn "Price difference is less than 0.5% (${PRICE_DIFF}%)"
            log_info "Skipping update to save gas"
            echo ""
            continue
        fi
    fi
    
    # Update oracle contract
    log_info "Sending transaction to update oracle..."
    
    # Try different update methods (use uint256 for updateAnswer)
    TX_HASH=""
    for METHOD_SIG in "updateAnswer(uint256)" "transmit(int256)" "setLatestAnswer(int256)"; do
        METHOD=$(echo "$METHOD_SIG" | cut -d'(' -f1)
        TX_HASH=$(cast send "$ORACLE_ADDRESS" \
            "$METHOD_SIG" \
            "$PRICE_DECIMALS" \
            --rpc-url "$RPC_URL" \
            --private-key "$PRIVATE_KEY" \
            --json 2>/dev/null | python3 -c "import sys, json; print(json.load(sys.stdin).get('transactionHash', ''))" 2>/dev/null || echo "")
        
        if [ -n "$TX_HASH" ] && [ "$TX_HASH" != "null" ]; then
            log_success "Transaction sent using $METHOD: $TX_HASH"
            break
        fi
    done
    
    if [ -z "$TX_HASH" ]; then
        log_error "Failed to update oracle for $SYMBOL"
        log_warn "Tried methods: updateAnswer, transmit, setLatestAnswer"
        ((FAILED++))
        echo ""
        continue
    fi
    
    # Wait briefly for confirmation
    sleep 3
    
    # Verify update
    NEW_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \
        "latestRoundData()" \
        --rpc-url "$RPC_URL" 2>/dev/null || echo "")
    
    if [ -n "$NEW_ORACLE_DATA" ]; then
        NEW_ANSWER=$(echo "$NEW_ORACLE_DATA" | cut -c 131-194)
        NEW_PRICE=$(python3 << PYEOF
answer_hex = "$NEW_ANSWER"
answer_int = int(answer_hex, 16)
if answer_int > 2**255:
    answer_int = answer_int - 2**256
price = answer_int / 100000000
print(price)
PYEOF
)
        log_success "Oracle updated: \$$(printf '%.2f' $NEW_PRICE) USD"
        ((UPDATED++))
    else
        log_warn "Could not verify update (may need more time)"
        ((UPDATED++))
    fi
    
    echo ""
    
done <<< "$TOKENS"

echo ""
echo "========================================="
echo "Summary"
echo "========================================="
echo ""
log_success "Successfully updated: $UPDATED oracle(s)"
if [ $FAILED -gt 0 ]; then
    log_warn "Failed to update: $FAILED oracle(s)"
fi
echo ""

if [ $UPDATED -gt 0 ]; then
    log_info "Oracle prices have been updated successfully!"
    log_info ""
    log_info "Next steps:"
    log_info "  1. Verify prices using: cast call <oracle-address> 'latestRoundData()' --rpc-url $RPC_URL"
    log_info "  2. Check oracle publisher service is running (VMID 3500) for automatic updates"
    log_info "  3. dApps can now query oracle contracts for USD prices"
fi
echo ""

