#!/usr/bin/env bash
# recover-bootstrap.sh — Diagnose and recover from a failed VWAP bootstrap.
#
# If the second recenter() reverts mid-sequence (e.g. "amplitude not reached"),
# the LiquidityManager is left with positions deployed but cumulativeVolume == 0.
# This script diagnoses the state and retries the bootstrap.
#
# See docs/mainnet-bootstrap.md "Recovery from failed mid-sequence bootstrap"
# for the full manual procedure.
#
# Usage:
#   scripts/recover-bootstrap.sh --rpc-url <RPC> --private-key <KEY> --lm <LM_ADDRESS> [OPTIONS]
#
# Options:
#   --rpc-url <url>        RPC endpoint (required)
#   --private-key <key>    Deployer private key (required)
#   --lm <address>         LiquidityManager address (required)
#   --kraiken <address>    Kraiken token address (optional, for seed buy retry)
#   --seed-eth <amount>    Extra seed buy amount, e.g. "0.01ether" (default: skip seed buy)
#   --fee-dest <address>   Set feeDestination to this address if not already correct
#   --dry-run              Diagnose only, do not send transactions
#   --help                 Show this help message
set -euo pipefail

# ── Defaults ──────────────────────────────────────────────────────────
RPC_URL=""
PRIVATE_KEY=""
LM_ADDRESS=""
KRAIKEN=""
SEED_ETH=""
FEE_DEST=""
DRY_RUN=false

WETH="0x4200000000000000000000000000000000000006"
SWAP_ROUTER_MAINNET="0x2626664c2603336E57B271c5C0b26F421741e481"
SWAP_ROUTER_SEPOLIA="0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4"
MAX_UINT="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"

# ── Argument parsing ──────────────────────────────────────────────────
usage() {
  sed -n '/^# Usage:/,/^set -euo/p' "$0" | head -n -1 | sed 's/^# \?//'
  exit 0
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --rpc-url)    RPC_URL="$2"; shift 2 ;;
    --private-key) PRIVATE_KEY="$2"; shift 2 ;;
    --lm)         LM_ADDRESS="$2"; shift 2 ;;
    --kraiken)    KRAIKEN="$2"; shift 2 ;;
    --seed-eth)   SEED_ETH="$2"; shift 2 ;;
    --fee-dest)   FEE_DEST="$2"; shift 2 ;;
    --dry-run)    DRY_RUN=true; shift ;;
    --help|-h)    usage ;;
    *) echo "Unknown option: $1"; usage ;;
  esac
done

if [[ -z "$RPC_URL" || -z "$PRIVATE_KEY" || -z "$LM_ADDRESS" ]]; then
  echo "Error: --rpc-url, --private-key, and --lm are required."
  echo "Run with --help for usage."
  exit 1
fi

# ── Helpers ───────────────────────────────────────────────────────────
info()  { echo "[recover] $*"; }
warn()  { echo "[recover] WARNING: $*"; }
error() { echo "[recover] ERROR: $*" >&2; }

detect_swap_router() {
  local chain_id
  chain_id="$(cast chain-id --rpc-url "$RPC_URL" 2>/dev/null || echo "")"
  if [[ "$chain_id" == "8453" ]]; then
    echo "$SWAP_ROUTER_MAINNET"
  else
    echo "$SWAP_ROUTER_SEPOLIA"
  fi
}

# ── Step 1: Diagnose ─────────────────────────────────────────────────
info "Diagnosing LiquidityManager at $LM_ADDRESS ..."

CUMVOL="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "cumulativeVolume()(uint256)" 2>/dev/null || echo "ERROR")"
if [[ "$CUMVOL" == "ERROR" ]]; then
  error "Cannot read cumulativeVolume — is LM_ADDRESS correct?"
  exit 1
fi

FEE_DESTINATION="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "feeDestination()(address)" 2>/dev/null || echo "ERROR")"
FEE_LOCKED="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "feeDestinationLocked()(bool)" 2>/dev/null || echo "ERROR")"
LAST_RECENTER="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "lastRecenterTime()(uint256)" 2>/dev/null || echo "0")"

info "  cumulativeVolume:    $CUMVOL"
info "  feeDestination:      $FEE_DESTINATION"
info "  feeDestinationLocked: $FEE_LOCKED"
info "  lastRecenterTime:    $LAST_RECENTER"

# ── Check: already bootstrapped? ─────────────────────────────────────
if [[ "$CUMVOL" != "0" ]]; then
  info "VWAP bootstrap already complete (cumulativeVolume=$CUMVOL). Nothing to recover."
  exit 0
fi

info "cumulativeVolume is 0 — bootstrap incomplete, recovery needed."

# ── Check: feeDestination ────────────────────────────────────────────
if [[ "$FEE_DESTINATION" == "0x0000000000000000000000000000000000000000" ]]; then
  warn "feeDestination is not set (zero address)."
  if [[ -n "$FEE_DEST" ]]; then
    info "Will set feeDestination to $FEE_DEST"
  else
    warn "Pass --fee-dest <address> to set it during recovery."
  fi
fi

if [[ -n "$FEE_DEST" && "$FEE_DESTINATION" != "$FEE_DEST" ]]; then
  if [[ "$FEE_LOCKED" == "true" ]]; then
    error "feeDestination is locked at $FEE_DESTINATION — cannot change to $FEE_DEST."
    error "Manual intervention required."
    exit 1
  fi
  if [[ "$DRY_RUN" == "true" ]]; then
    info "[dry-run] Would set feeDestination to $FEE_DEST"
  else
    info "Setting feeDestination to $FEE_DEST ..."
    cast send --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
      "$LM_ADDRESS" "setFeeDestination(address)" "$FEE_DEST"
    info "feeDestination updated."
  fi
fi

# ── Check: cooldown ──────────────────────────────────────────────────
NOW="$(cast block latest --rpc-url "$RPC_URL" --field timestamp 2>/dev/null || echo "0")"
COOLDOWN_END=$(( LAST_RECENTER + 60 ))
if [[ "$NOW" -lt "$COOLDOWN_END" ]]; then
  REMAINING=$(( COOLDOWN_END - NOW ))
  warn "Recenter cooldown has not elapsed. ${REMAINING}s remaining."
  warn "Wait and re-run this script."
  if [[ "$DRY_RUN" == "true" ]]; then
    exit 0
  fi
  info "Polling for recenter cooldown to elapse (timeout: 5 min) ..."
  POLL_ATTEMPTS=0
  MAX_POLL_ATTEMPTS=60  # 60 × 5s = 5 min
  while true; do
    POLL_ATTEMPTS=$(( POLL_ATTEMPTS + 1 ))
    if [[ "$POLL_ATTEMPTS" -gt "$MAX_POLL_ATTEMPTS" ]]; then
      error "Timed out waiting for recenter cooldown (${MAX_POLL_ATTEMPTS} polls). RPC may be degraded."
      exit 1
    fi
    NOW="$(cast block latest --rpc-url "$RPC_URL" --field timestamp 2>/dev/null || echo "0")"
    if [[ "$NOW" -ge "$COOLDOWN_END" ]]; then
      info "Recenter cooldown elapsed."
      break
    fi
    REMAINING=$(( COOLDOWN_END - NOW ))
    info "  ${REMAINING}s remaining ..."
    sleep 5
  done
fi

# ── Optional: extra seed buy ─────────────────────────────────────────
if [[ -n "$SEED_ETH" && -n "$KRAIKEN" ]]; then
  SWAP_ROUTER="$(detect_swap_router)"
  DEPLOYER_ADDR="$(cast wallet address --private-key "$PRIVATE_KEY")"

  if [[ "$DRY_RUN" == "true" ]]; then
    info "[dry-run] Would execute seed buy: $SEED_ETH WETH -> KRAIKEN"
  else
    info "Executing seed buy ($SEED_ETH WETH -> KRAIKEN) ..."

    SEED_WEI="$(cast --to-unit "$SEED_ETH" wei)"
    cast send --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
      "$WETH" "deposit()" --value "$SEED_ETH"
    cast send --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
      "$WETH" "approve(address,uint256)" "$SWAP_ROUTER" "$MAX_UINT"

    # Determine swap direction from token ordering
    WETH_LOWER=$(echo "$WETH" | tr '[:upper:]' '[:lower:]' | sed 's/^0x//')
    KRAIKEN_LOWER=$(echo "$KRAIKEN" | tr '[:upper:]' '[:lower:]' | sed 's/^0x//')
    if [[ "$WETH_LOWER" < "$KRAIKEN_LOWER" ]]; then
      SQRT_LIMIT=4295128740
    else
      SQRT_LIMIT=1461446703485210103287273052203988822378723970341
    fi

    cast send --legacy --gas-limit 300000 --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
      "$SWAP_ROUTER" "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \
      "($WETH,$KRAIKEN,10000,$DEPLOYER_ADDR,$SEED_WEI,0,$SQRT_LIMIT)"
    info "Seed buy complete."

    # Poll until recenter cooldown elapses
    info "Polling for recenter cooldown to elapse (timeout: 5 min) ..."
    LAST_RECENTER_AFTER="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "lastRecenterTime()(uint256)" 2>/dev/null || echo "$LAST_RECENTER")"
    COOLDOWN_TARGET=$(( LAST_RECENTER_AFTER + 60 ))
    POLL_ATTEMPTS=0
    MAX_POLL_ATTEMPTS=60  # 60 × 5s = 5 min
    while true; do
      POLL_ATTEMPTS=$(( POLL_ATTEMPTS + 1 ))
      if [[ "$POLL_ATTEMPTS" -gt "$MAX_POLL_ATTEMPTS" ]]; then
        error "Timed out waiting for recenter cooldown (${MAX_POLL_ATTEMPTS} polls). RPC may be degraded."
        exit 1
      fi
      NOW="$(cast block latest --rpc-url "$RPC_URL" --field timestamp 2>/dev/null || echo "0")"
      if [[ "$NOW" -ge "$COOLDOWN_TARGET" ]]; then
        info "Recenter cooldown elapsed."
        break
      fi
      REMAINING=$(( COOLDOWN_TARGET - NOW ))
      info "  ${REMAINING}s remaining ..."
      sleep 5
    done
  fi
fi

# ── Retry second recenter ────────────────────────────────────────────
if [[ "$DRY_RUN" == "true" ]]; then
  info "[dry-run] Would call recenter() on $LM_ADDRESS"
  info "[dry-run] Done. Re-run without --dry-run to execute."
  exit 0
fi

info "Calling recenter() to complete VWAP bootstrap ..."
if ! cast send --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
  "$LM_ADDRESS" "recenter()" 2>&1; then
  error "recenter() reverted. Check the revert reason above."
  error "Common causes:"
  error "  - 'amplitude not reached.' -> need larger seed buy (use --seed-eth with --kraiken)"
  error "  - 'price deviated from oracle' -> wait for TWAP history"
  error "  - 'recenter cooldown' -> wait 60s and retry"
  exit 1
fi

# ── Verify ────────────────────────────────────────────────────────────
CUMVOL="$(cast call --rpc-url "$RPC_URL" "$LM_ADDRESS" "cumulativeVolume()(uint256)" 2>/dev/null || echo "0")"
if [[ "$CUMVOL" == "0" || -z "$CUMVOL" ]]; then
  error "Recovery failed — cumulativeVolume is still 0."
  error "The anchor position may have no fees. Try a larger seed buy:"
  error "  $0 --rpc-url $RPC_URL --private-key <KEY> --lm $LM_ADDRESS --kraiken <ADDR> --seed-eth 0.01ether"
  exit 1
fi

info "Recovery successful! cumulativeVolume=$CUMVOL"
info "VWAP bootstrap is complete."
