#!/usr/bin/env bash
# Check deployer balances on all configured networks, estimate gas costs via gas API,
# ensure sufficient network token, then optionally deploy (Chain 138 phased core).
# Uses PRIVATE_KEY from .env (smom-dbis-138).
#
# Balance check: On EVM chains only the NATIVE token can be used for gas. We check that
# token for each network (cast balance = native currency). ERC-20 tokens (USDT, LINK, etc.)
# cannot be used for gas unless a meta-tx relayer is in use.
#
# Gas token per network (only these can be used for gas):
#   Chain 138, Ethereum, Base, Optimism, Sepolia, Base Sepolia, Optimism Sepolia → ETH
#   Polygon, Polygon Amoy → MATIC
#   BSC → BNB
#   Avalanche → AVAX
#   Cronos → CRO
#   Gnosis → xDAI
#   Arbitrum → ETH
#
# Usage:
#   ./scripts/deployment/check-balances-gas-and-deploy.sh                 # report only
#   ./scripts/deployment/check-balances-gas-and-deploy.sh --deploy        # deploy on Chain 138 (requires PRIVATE_KEY)
#
# Uses .env for RPCs and PRIVATE_KEY; --deploy is a tag (not .env).

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

source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_deploy_tag "$@"
DO_DEPLOY="${DO_DEPLOY:-0}"

# Infura: use Basic Auth URL when INFURA_PROJECT_SECRET is set (fixes "error sending request" from Infura)
SCRIPT_LIB="$SCRIPT_DIR/../lib"
[ -f "${SCRIPT_LIB}/infura.sh" ] && source "${SCRIPT_LIB}/infura.sh"

# Deployer address: use DEPLOYER_ADDRESS if set (matches MetaMask Portfolio), else derive from PRIVATE_KEY
if [ -n "${DEPLOYER_ADDRESS:-}" ]; then
  DEPLOYER="${DEPLOYER_ADDRESS}"
  [[ "$DEPLOYER" != 0x* ]] && DEPLOYER="0x$DEPLOYER"
else
  if [ -z "${PRIVATE_KEY:-}" ]; then
    echo "ERROR: Set PRIVATE_KEY in .env or set DEPLOYER_ADDRESS=0x4A666F96fC8764181194447A7dFdb7d471b301C8 for read-only balance check"
    exit 1
  fi
  DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || true)
  if [ -z "$DEPLOYER" ]; then
    echo "ERROR: Could not derive deployer address from PRIVATE_KEY (is 'cast' available?)"
    exit 1
  fi
fi

# Gas estimate for "full" deploy per chain (conservative)
GAS_FULL_DEPLOY_138="${GAS_FULL_DEPLOY_138:-5000000}"
GAS_FULL_DEPLOY_MAINNET="${GAS_FULL_DEPLOY_MAINNET:-5000000}"
BUFFER_BPS=120  # 20% buffer

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

# Short form for matching MetaMask Portfolio (0x4A66...b301C8)
DEPLOYER_SHORT="${DEPLOYER:0:6}...${DEPLOYER: -6}"

echo -e "${BLUE}============================================${NC}"
echo -e "${BLUE}Deployer balance & gas check (all networks)${NC}"
echo -e "${BLUE}============================================${NC}"
echo "Deployer: $DEPLOYER_SHORT  (full: $DEPLOYER)"
echo "  (Matches MetaMask Portfolio when RPCs are reachable; use DEPLOYER_ADDRESS=0x... to check a specific wallet)"
echo ""

# Format wei to ether with 8 decimal places (avoids excessive decimals from cast)
format_wei_to_ether() {
  local wei="${1:-0}"
  local eth
  eth=$(echo "scale=10; $wei / 1000000000000000000" | bc 2>/dev/null) || eth="0"
  printf "%.8f" "${eth:-0}"
}

# Infura Gas API: supported chain IDs (EIP-1559 style; API returns suggestedMaxFeePerGas in gwei)
INFURA_GAS_API_CHAINS="1 137 10 8453 42161 11155111 84532 11155420 80002 43114 56 100 324 534352"

# Get gas price in wei from Infura Gas API for a given chain_id (optional).
# Returns wei or empty; caller should fallback to cast gas-price.
get_gas_price_wei_infura_api() {
  local chain_id="${1:-1}"
  local key=""
  if [ -n "${INFURA_GAS_API:-}" ]; then
    local url="$INFURA_GAS_API"
    if [[ "$url" == *"/v3/"* ]]; then
      key="${url#*v3/}"
      key="${key%%/*}"
    else
      key="$url"
    fi
  elif [ -n "${INFURA_PROJECT_ID:-}" ]; then
    key="${INFURA_PROJECT_ID}"
  fi
  if [ -z "$key" ] || ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
    return 1
  fi
  local api_url="https://gas.api.infura.io/v3/${key}/networks/${chain_id}/suggestedGasFees"
  local res
  res=$(curl -sL --connect-timeout 5 "$api_url" 2>/dev/null || true)
  if [ -z "$res" ] || echo "$res" | grep -qi "error\|required\|private key\|not found"; then
    return 1
  fi
  local gwei
  gwei=$(echo "$res" | jq -r '.medium.suggestedMaxFeePerGas // .standard.suggestedMaxFeePerGas // .standard.maxFeePerGas // .low.suggestedMaxFeePerGas // empty' 2>/dev/null)
  if [ -z "$gwei" ] || [ "$gwei" = "null" ]; then
    return 1
  fi
  local wei
  wei=$(echo "scale=0; ($gwei) * 1000000000 / 1" | bc 2>/dev/null)
  [ -n "$wei" ] && [ "$wei" != "0" ] && echo "$wei"
}

# Get mainnet gas price from Infura Gas API (preferred) or RPC fallback.
get_mainnet_gas_price_wei() {
  local wei
  wei=$(get_gas_price_wei_infura_api 1)
  if [ -z "$wei" ] || [ "$wei" = "0" ]; then
    [ -n "${ETHEREUM_MAINNET_RPC:-}" ] && command -v cast >/dev/null 2>&1 && wei=$(cast gas-price --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null || true)
  fi
  [ -n "$wei" ] && [ "$wei" != "0" ] && echo "$wei" || echo "30000000000"
}

# Resolve gas price for a chain: try Infura Gas API first (if chain supported), else RPC, else default_wei.
# Usage: get_gas_price_for_chain chain_id rpc_url default_wei
# Output: wei (and sets GAS_SOURCE="Infura Gas API" or "RPC" or "default")
get_gas_price_for_chain() {
  local chain_id="$1"
  local rpc_url="$2"
  local default_wei="${3:-30000000000}"
  local wei=""
  [ -n "$rpc_url" ] && type ensure_infura_rpc_url &>/dev/null && rpc_url=$(ensure_infura_rpc_url "$rpc_url")
  if [[ " $INFURA_GAS_API_CHAINS " == *" $chain_id "* ]]; then
    wei=$(get_gas_price_wei_infura_api "$chain_id")
    [ -n "$wei" ] && GAS_SOURCE="Infura Gas API" && echo "$wei" && return
  fi
  if [ -n "$rpc_url" ] && command -v cast >/dev/null 2>&1; then
    wei=$(cast gas-price --rpc-url "$rpc_url" 2>/dev/null || true)
    [ -n "$wei" ] && [ "$wei" != "0" ] && GAS_SOURCE="RPC" && echo "$wei" && return
  fi
  GAS_SOURCE="default"
  echo "$default_wei"
}

mainnet_gas_wei=$(get_mainnet_gas_price_wei)
mainnet_gas_gwei=$(printf "%.2f" $(echo "scale=4; $mainnet_gas_wei / 1000000000" | bc 2>/dev/null || echo "30"))
echo "Gas prices (verified via Infura Gas API where supported, else RPC or default):"
echo "  Ethereum Mainnet (1): ${mainnet_gas_gwei} gwei (Infura Gas API)"
echo ""

# Check native (gas) token balance for one network. Only this token can be used for gas on EVM.
check_network() {
  local name="$1"
  local rpc="$2"
  local chain_id="${3:-}"
  local gas_token="${4:-ETH}"
  local gas_limit="${5:-$GAS_FULL_DEPLOY_MAINNET}"
  local gas_price_wei="${6:-$mainnet_gas_wei}"

  if [ -z "$rpc" ]; then
    echo -e "  ${YELLOW}$name (chain $chain_id): no RPC — gas token = $gas_token (not checked)${NC}"
    return 0
  fi
  type ensure_infura_rpc_url &>/dev/null && rpc=$(ensure_infura_rpc_url "$rpc")
  local balance_wei
  balance_wei=$(cast balance "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null) || balance_wei=""
  local rpc_ok=1
  if [ -z "$balance_wei" ] || ! [[ "$balance_wei" =~ ^[0-9]+$ ]]; then
    rpc_ok=0
    balance_wei="0"
  fi
  local balance_display
  if [ "$rpc_ok" = "0" ]; then
    balance_display="(unable to fetch — RPC unreachable?)"
  else
    balance_display=$(format_wei_to_ether "$balance_wei")
  fi
  local cost_wei
  cost_wei=$(echo "$gas_limit * $gas_price_wei" | bc 2>/dev/null || echo "0")
  local cost_with_buffer
  cost_with_buffer=$(echo "$cost_wei * $BUFFER_BPS / 100" | bc 2>/dev/null || echo "$cost_wei")
  local cost_display
  cost_display=$(format_wei_to_ether "$cost_with_buffer")
  local ok=0
  [ "$rpc_ok" = "1" ] && [ "$(echo "$balance_wei >= $cost_with_buffer" | bc 2>/dev/null)" = "1" ] && ok=1
  if [ "$ok" = "1" ]; then
    echo -e "  ${GREEN}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — OK for deploy${NC}"
  elif [ "$rpc_ok" = "0" ]; then
    echo -e "  ${YELLOW}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — check RPC / run from network with access${NC}"
  else
    echo -e "  ${RED}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — INSUFFICIENT for deploy${NC}"
  fi
  return $((1 - ok))
}

# All networks: order matches MetaMask Portfolio (Ethereum, BSC, Arbitrum, Optimism, Polygon, Cronos, …)
# Gas needed from Infura Gas API or RPC. Native gas token only (ETH, BNB, POL, CRO, etc.).
echo "Checking gas token balance (same order as MetaMask Portfolio where applicable):"
echo ""
any_insufficient=0
# --- Portfolio main networks (Ethereum, BSC, Arbitrum, Optimism, Polygon, Cronos) ---
check_network "Ethereum Mainnet"  "${ETHEREUM_MAINNET_RPC:-}"     "1"      "ETH"   "$GAS_FULL_DEPLOY_MAINNET" "$mainnet_gas_wei" || any_insufficient=1
check_network "BSC"               "${BSC_RPC_URL:-${BSC_MAINNET_RPC:-https://bsc-dataseed.binance.org}}" "56"     "BNB"   "5000000" "$(get_gas_price_for_chain 56 "${BSC_RPC_URL:-${BSC_MAINNET_RPC:-}}" "5000000000")" || true
check_network "Arbitrum"         "${ARBITRUM_MAINNET_RPC:-https://arbitrum-one.publicnode.com}"       "42161"  "ETH"   "5000000" "$(get_gas_price_for_chain 42161 "${ARBITRUM_MAINNET_RPC:-}" "100000000")" || true
check_network "Optimism"         "${OPTIMISM_MAINNET_RPC:-}"      "10"     "ETH"   "5000000" "$(get_gas_price_for_chain 10 "${OPTIMISM_MAINNET_RPC:-}" "1000000")" || true
check_network "Polygon"           "${POLYGON_MAINNET_RPC:-}"      "137"    "POL"   "5000000" "$(get_gas_price_for_chain 137 "${POLYGON_MAINNET_RPC:-}" "50000000000")" || any_insufficient=1
check_network "Cronos"           "${CRONOS_RPC_URL:-https://evm.cronos.org}"                          "25"     "CRO"   "5000000" "$(get_gas_price_for_chain 25 "${CRONOS_RPC_URL:-}" "1000000000")" || true
# --- Chain 138 (project chain) ---
check_network "Chain 138"           "${RPC_URL_138:-}"              "138"    "ETH"   "$GAS_FULL_DEPLOY_138" "$(cast gas-price --rpc-url "${RPC_URL_138:-http://192.168.11.211:8545}" 2>/dev/null || echo "1000000000")" || any_insufficient=1
# --- Other mainnets ---
check_network "Base"              "${BASE_MAINNET_RPC:-}"          "8453"   "ETH"   "5000000" "$(get_gas_price_for_chain 8453 "${BASE_MAINNET_RPC:-}" "100000000")" || true
check_network "Avalanche"        "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-https://avalanche-c-chain.publicnode.com}}" "43114" "AVAX" "5000000" "$(get_gas_price_for_chain 43114 "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-}}" "25000000000")" || true
check_network "Gnosis"           "${GNOSIS_MAINNET_RPC:-${GNOSIS_RPC:-https://rpc.gnosischain.com}}"  "100"    "xDAI"  "5000000" "$(get_gas_price_for_chain 100 "${GNOSIS_MAINNET_RPC:-${GNOSIS_RPC:-}}" "1000000000")" || true
# --- Testnets ---
check_network "Ethereum Sepolia"  "${ETHEREUM_SEPOLIA_RPC:-}"     "11155111" "ETH"  "5000000" "$(get_gas_price_for_chain 11155111 "${ETHEREUM_SEPOLIA_RPC:-}" "20000000000")" || true
check_network "Polygon Amoy"      "${POLYGON_AMOY_RPC:-}"         "80002"  "MATIC" "5000000" "$(get_gas_price_for_chain 80002 "${POLYGON_AMOY_RPC:-}" "30000000000")" || true
check_network "Base Sepolia"      "${BASE_SEPOLIA_RPC:-}"          "84532"  "ETH"   "5000000" "$(get_gas_price_for_chain 84532 "${BASE_SEPOLIA_RPC:-}" "100000000")" || true
check_network "Optimism Sepolia" "${OPTIMISM_SEPOLIA_RPC:-}"      "11155420" "ETH"  "5000000" "$(get_gas_price_for_chain 11155420 "${OPTIMISM_SEPOLIA_RPC:-}" "1000000")" || true

echo ""
echo "Gas token summary: each chain uses only its native token for gas. ERC-20 (USDT, LINK, etc.) cannot pay gas."
echo "Gas needed above was computed from: Infura Gas API (chains 1, 10, 56, 100, 137, 42161, 43114, 8453, 84532, 80002, 11155111, 11155420) or RPC eth_gasPrice when API unavailable."

echo ""
if [ "${DO_DEPLOY:-0}" = "1" ]; then
  if [ -n "${DEPLOYER_ADDRESS:-}" ]; then
    echo -e "${RED}ERROR: --deploy requires PRIVATE_KEY in .env (unset DEPLOYER_ADDRESS to use key-derived deployer).${NC}"
    exit 1
  fi
  if [ -z "${PRIVATE_KEY:-}" ]; then
    echo -e "${RED}ERROR: PRIVATE_KEY required for --deploy.${NC}"
    exit 1
  fi
  echo -e "${BLUE}Deploy phase (Chain 138 only; other chains need CCIP_* env)${NC}"
  RPC_138="${RPC_URL_138:-http://192.168.11.211:8545}"
  balance_138=$(cast balance "$DEPLOYER" --rpc-url "$RPC_138" 2>/dev/null || echo "0")
  need_138=$(echo "5000000 * 1000000000 * $BUFFER_BPS / 100" | bc 2>/dev/null || echo "6000000000000000000")
  if [ -n "$balance_138" ] && [ "$(echo "$balance_138 >= $need_138" | bc 2>/dev/null)" = "1" ]; then
    echo "Deploying phased core (01_DeployCore, 02_DeployBridges) on Chain 138..."
    export PRIVATE_KEY
    out_01=$(mktemp)
    trap "rm -f $out_01" EXIT
    # Chain 138 often requires minimum gas price (e.g. 1 gwei)
    GAS_PRICE_138="${GAS_PRICE_138:-1000000000}"
    if forge script script/deploy/01_DeployCore.s.sol:DeployCore \
      --rpc-url "$RPC_138" \
      --private-key "$PRIVATE_KEY" \
      --broadcast \
      --with-gas-price "$GAS_PRICE_138" \
      -vvv 2>&1 | tee "$out_01"; then
      reg=$(grep "UNIVERSAL_ASSET_REGISTRY" "$out_01" | tail -1 | grep -oE "0x[a-fA-F0-9]{40}" | head -1)
      if [ -n "$reg" ] && [ -n "${CCIP_ROUTER:-}" ]; then
        export UNIVERSAL_ASSET_REGISTRY="$reg"
        forge script script/deploy/02_DeployBridges.s.sol:DeployBridges \
          --rpc-url "$RPC_138" \
          --private-key "$PRIVATE_KEY" \
          --broadcast \
          --with-gas-price "$GAS_PRICE_138" \
          -vvv 2>&1 || echo "02_DeployBridges failed or skipped."
      fi
    else
      echo "01_DeployCore failed or skipped (may already be deployed)."
    fi
    echo -e "${GREEN}Chain 138 deploy phase finished.${NC}"
  else
    echo -e "${RED}Chain 138 balance insufficient for deploy (need more native ETH on 138). Fund deployer and re-run.${NC}"
    exit 1
  fi
else
  echo "Run with --deploy to run deployment on Chain 138 (phased core)."
  echo "Other chains: fund deployer with that chain's native token (MATIC, BNB, etc.) and set CCIP_* in .env for DeployAll."
fi
