#!/usr/bin/env bash
set -euo pipefail

# Install jq if not available
if ! command -v jq >/dev/null 2>&1; then
  apk add --no-cache jq >/dev/null 2>&1 || apt-get update && apt-get install -y jq >/dev/null 2>&1 || true
fi

ROOT_DIR=/workspace
GIT_BRANCH="${GIT_BRANCH:-}"

# Checkout branch if specified
if [[ -n "$GIT_BRANCH" ]]; then
  cd "$ROOT_DIR"
  git config --global --add safe.directory "$ROOT_DIR" 2>/dev/null || true
  CURRENT=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")

  if [[ "$CURRENT" != "$GIT_BRANCH" ]]; then
    echo "[bootstrap] Switching to branch: $GIT_BRANCH"
    # Try local branch first, then remote
    if git rev-parse --verify "$GIT_BRANCH" >/dev/null 2>&1; then
      git checkout "$GIT_BRANCH" 2>/dev/null || echo "[bootstrap] WARNING: Could not checkout $GIT_BRANCH"
    else
      git fetch origin "$GIT_BRANCH" 2>/dev/null || true
      git checkout "$GIT_BRANCH" 2>/dev/null || echo "[bootstrap] WARNING: Could not checkout $GIT_BRANCH"
    fi
  fi
fi

STATE_DIR=$ROOT_DIR/tmp/containers
LOG_DIR=$STATE_DIR/logs
SETUP_LOG=$LOG_DIR/setup.log
MNEMONIC_FILE=$ROOT_DIR/onchain/.secret.local

mkdir -p "$LOG_DIR"
: >"$SETUP_LOG"

# ── Configure shared bootstrap variables ──
ANVIL_RPC=${ANVIL_RPC:-"http://anvil:8545"}
CONTRACT_ENV=$STATE_DIR/contracts.env

# Derive NETWORK_NAME from FORK_URL if not explicitly set.
# Callers may override by exporting NETWORK_NAME before starting the stack.
# Chain ID 8453 = Base mainnet; anything else (including 84532 Base Sepolia) defaults to Sepolia fork.
if [[ -z "${NETWORK_NAME:-}" ]]; then
  _fork_url="${FORK_URL:-}"
  if [[ -n "$_fork_url" ]]; then
    _chain_id=$(cast chain-id --rpc-url "$_fork_url" 2>/dev/null || echo "")
    if [[ "$_chain_id" == "8453" ]]; then
      NETWORK_NAME="BASE_MAINNET_LOCAL_FORK"
    else
      NETWORK_NAME="BASE_SEPOLIA_LOCAL_FORK"
    fi
  else
    NETWORK_NAME="BASE_SEPOLIA_LOCAL_FORK"
  fi
fi

LOG_FILE=$SETUP_LOG
ONCHAIN_DIR=$ROOT_DIR/onchain
TXNBOT_FUND_VALUE=${TXNBOT_FUND_VALUE:-1ether}

# Source shared bootstrap functions
# shellcheck source=../scripts/bootstrap-common.sh
source "$ROOT_DIR/scripts/bootstrap-common.sh"

# ── Local-only helpers ─────────────────────────────────────────────────

maybe_set_deployer_from_mnemonic() {
  if [[ -n "$DEPLOYER_PK" && "$DEPLOYER_PK" != "$DEFAULT_DEPLOYER_PK" ]]; then
    return
  fi
  if [[ -f "$MNEMONIC_FILE" ]]; then
    local mnemonic pk addr
    mnemonic="$(tr -d '\n\r' <"$MNEMONIC_FILE")"
    if [[ -n "$mnemonic" ]]; then
      pk="$(cast wallet private-key --mnemonic "$mnemonic" --mnemonic-derivation-path "m/44'/60'/0'/0/0")"
      addr="$(cast wallet address --private-key "$pk")"
      DEPLOYER_PK=${pk}
      DEPLOYER_ADDR=${addr}
    fi
  fi
}

derive_txnbot_wallet() {
  if [[ -f "$MNEMONIC_FILE" ]]; then
    local mnemonic
    mnemonic="$(tr -d '\n\r' <"$MNEMONIC_FILE")"
    if [[ -n "$mnemonic" ]]; then
      TXNBOT_PRIVATE_KEY="$(cast wallet private-key --mnemonic "$mnemonic" --mnemonic-index 2)"
      TXNBOT_ADDRESS="$(cast wallet address --private-key "$TXNBOT_PRIVATE_KEY")"
      bootstrap_log "Derived txnBot wallet: $TXNBOT_ADDRESS (account index 2)"
      return
    fi
  fi
  # Fallback to hardcoded Anvil account 1
  TXNBOT_PRIVATE_KEY=$DEFAULT_TXNBOT_PK
  TXNBOT_ADDRESS=$DEFAULT_TXNBOT_ADDR
  bootstrap_log "Using default txnBot wallet: $TXNBOT_ADDRESS"
}

write_ponder_env() {
  cat >"$ROOT_DIR/services/ponder/.env.local" <<EOPONDER
PONDER_NETWORK=$NETWORK_NAME
KRAIKEN_ADDRESS=$KRAIKEN
STAKE_ADDRESS=$STAKE
START_BLOCK=$DEPLOY_BLOCK
PONDER_RPC_URL_${NETWORK_NAME}=$ANVIL_RPC
DATABASE_URL=postgresql://ponder:ponder_local@postgres:5432/ponder_local
DATABASE_SCHEMA=ponder_local_${DEPLOY_BLOCK}
EOPONDER
}

write_txn_bot_env() {
  local txnbot_env=$STATE_DIR/txnBot.env
  local provider_url=${TXNBOT_PROVIDER_URL:-$ANVIL_RPC}
  local graphql_endpoint=${TXNBOT_GRAPHQL_ENDPOINT:-http://ponder:42069/graphql}
  cat >"$txnbot_env" <<EOTXNBOT
ENVIRONMENT=$NETWORK_NAME
PROVIDER_URL=$provider_url
PRIVATE_KEY=$TXNBOT_PRIVATE_KEY
LM_CONTRACT_ADDRESS=$LIQUIDITY_MANAGER
STAKE_CONTRACT_ADDRESS=$STAKE
GRAPHQL_ENDPOINT=$graphql_endpoint
WALLET_ADDRESS=$TXNBOT_ADDRESS
PORT=43069
EOTXNBOT
}

prime_chain() {
  bootstrap_log "Pre-mining 5 blocks (minimal warmup for fast Ponder sync)..."
  if cast rpc --rpc-url "$ANVIL_RPC" anvil_mine "0x5" "0x1" >/dev/null 2>&1; then
    bootstrap_log "Mined 5 blocks"
  else
    bootstrap_log "Batch mining failed, using individual evm_mine calls"
    for i in {1..5}; do
      cast rpc --rpc-url "$ANVIL_RPC" evm_mine >/dev/null 2>&1 || true
    done
  fi
  bootstrap_log "Pre-mining complete"
}

# ── Main ───────────────────────────────────────────────────────────────

main() {
  local start_time
  start_time=$(date +%s%3N)

  bootstrap_log "Waiting for Anvil"
  wait_for_rpc

  # Idempotency: if deployments-local.json exists and contracts have code,
  # bootstrap already ran against this Anvil instance — skip.
  local deploy_file="$ONCHAIN_DIR/deployments-local.json"
  if [[ -f "$deploy_file" ]]; then
    local krk_addr
    krk_addr=$(jq -r '.contracts.Kraiken // empty' "$deploy_file" 2>/dev/null || true)
    if [[ -n "$krk_addr" ]]; then
      local code
      code=$(cast call --rpc-url "$ANVIL_RPC" "$krk_addr" "decimals()(uint8)" 2>/dev/null || true)
      if [[ -n "$code" && "$code" != "0x" ]]; then
        bootstrap_log "Already bootstrapped (Kraiken at $krk_addr responds) — skipping"
        return 0
      fi
    fi
  fi
  maybe_set_deployer_from_mnemonic

  # On forked networks, well-known addresses (Anvil mnemonic accounts) may
  # have code (e.g. ERC-4337 Account Abstraction proxies on Base Sepolia).
  # The feeDestination lock in LiquidityManager treats any address with code
  # as a contract and locks permanently. Strip code so they behave as EOAs.
  bootstrap_log "Clearing code from deployer + feeDest (fork safety)"
  cast rpc --rpc-url "$ANVIL_RPC" anvil_setCode "$DEPLOYER_ADDR" "0x" 2>/dev/null || true
  # 0xf6a3... carries 171 bytes of code on Base mainnet and may also carry code on Base
  # Sepolia. Clear it before setFeeDestination is called so LiquidityManager does not
  # permanently lock feeDestinationLocked (#760).
  cast rpc --rpc-url "$ANVIL_RPC" anvil_setCode "$FEE_DEST" "0x" 2>/dev/null || true

  derive_txnbot_wallet
  run_forge_script
  extract_addresses
  write_contracts_env
  bootstrap_vwap
  fund_liquidity_manager
  seed_application_state
  write_deployments_json
  write_ponder_env
  write_txn_bot_env
  fund_txn_bot_wallet
  prime_chain &
  local prime_pid=$!
  wait "$prime_pid"

  local end_time
  end_time=$(date +%s%3N)
  local elapsed_ms=$((end_time - start_time))
  local elapsed_sec
  elapsed_sec=$(awk -v ms="$elapsed_ms" 'BEGIN { printf "%.3f", ms/1000 }')
  bootstrap_log "Bootstrap complete in ${elapsed_sec}s"
  bootstrap_log "Kraiken: $KRAIKEN"
  bootstrap_log "Stake: $STAKE"
  bootstrap_log "LiquidityManager: $LIQUIDITY_MANAGER"
  bootstrap_log "txnBot: $TXNBOT_ADDRESS"
}

main "$@"
