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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SMOM_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$SMOM_ROOT"

if [[ -f "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" ]]; then
  # shellcheck disable=SC1091
  source "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh"
  load_deployment_env --repo-root "$SMOM_ROOT"
else
  source "$SMOM_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true
fi

PLAN_JSON="${PLAN_JSON:-$SMOM_ROOT/config/chain138-eth-pmm-liquidity-plan.json}"
PROFILE="${PROFILE:-}"
EXECUTE="${EXECUTE:-0}"
RPC_URL_138="${RPC_URL_138:-${RPC_URL:-http://192.168.11.211:8545}}"
DODO_PMM_INTEGRATION_ADDRESS="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-${CHAIN_138_DODO_PMM_INTEGRATION:-0x5BDc62f1ae7D630c37A8B363a1d49845356Ee72d}}}"
PRIVATE_KEY="${PRIVATE_KEY:-}"

command -v jq >/dev/null 2>&1 || { echo "jq is required" >&2; exit 1; }
command -v cast >/dev/null 2>&1 || { echo "cast is required" >&2; exit 1; }

[[ -f "$PLAN_JSON" ]] || { echo "PLAN_JSON not found: $PLAN_JSON" >&2; exit 1; }
[[ -n "$DODO_PMM_INTEGRATION_ADDRESS" ]] || { echo "DODO_PMM_INTEGRATION_ADDRESS not set" >&2; exit 1; }
require_private_key_env || exit 1

EXECUTION_CONFIG="$(jq -r '.executionConfig' "$PLAN_JSON")"
if [[ "$EXECUTION_CONFIG" != /* ]]; then
  EXECUTION_CONFIG="$SMOM_ROOT/${EXECUTION_CONFIG#smom-dbis-138/}"
fi
[[ -f "$EXECUTION_CONFIG" ]] || { echo "Execution config not found: $EXECUTION_CONFIG" >&2; exit 1; }

if [[ -z "$PROFILE" ]]; then
  PROFILE="$(jq -r '.defaultProfile' "$PLAN_JSON")"
fi

FIAT_BASE_UNITS="$(jq -r --arg p "$PROFILE" '.profiles[$p].fiatBaseUnits' "$PLAN_JSON")"
XAU_BASE_UNITS="$(jq -r --arg p "$PROFILE" '.profiles[$p].xauBaseUnits' "$PLAN_JSON")"
[[ "$FIAT_BASE_UNITS" != "null" ]] || { echo "Unknown PROFILE: $PROFILE" >&2; exit 1; }
[[ "$XAU_BASE_UNITS" != "null" ]] || { echo "Unknown PROFILE: $PROFILE" >&2; exit 1; }

APPROVE_GAS_LIMIT="$(jq -r '.execution.approveGasLimit' "$PLAN_JSON")"
MINT_GAS_LIMIT="$(jq -r '.execution.mintGasLimit' "$PLAN_JSON")"
WRAP_GAS_LIMIT="$(jq -r '.execution.wrapGasLimit' "$PLAN_JSON")"
ADD_LIQUIDITY_GAS_LIMIT="$(jq -r '.execution.addLiquidityGasLimit' "$PLAN_JSON")"
GAS_PRICE_WEI="${CHAIN_GAS_PRICE:-$(jq -r '.execution.legacyGasPriceWei' "$PLAN_JSON")}"
WRAP_WHEN_NEEDED="$(jq -r '.execution.wrapNativeEthWhenNeeded' "$PLAN_JSON")"
MINT_WHEN_OWNER="$(jq -r '.execution.mintMissingBaseWhenOwner' "$PLAN_JSON")"
APPROVE_MAX="$(jq -r '.execution.approveMax' "$PLAN_JSON")"

DEPLOYER="$(derive_deployer_address || true)"
[[ -n "$DEPLOYER" ]] || { echo "ERROR: Could not derive DEPLOYER_ADDRESS from PRIVATE_KEY." >&2; exit 1; }
WETH_ADDRESS="$(jq -r '.tokens.WETH' "$EXECUTION_CONFIG")"
MAX_UINT="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
ZERO_ADDR="0x0000000000000000000000000000000000000000"

log() {
  printf '%s\n' "$*"
}

get_pool_reserves() {
  local pool="$1"
  local lines
  mapfile -t lines < <(cast call "$pool" 'getVaultReserve()(uint256,uint256)' --rpc-url "$RPC_URL_138")
  printf '%s\t%s\n' "$(uint_clean "${lines[0]:-0}")" "$(uint_clean "${lines[1]:-0}")"
}

uint_clean() {
  printf '%s\n' "$1" | awk '{print $1}'
}

hex_to_addr() {
  local raw="${1#0x}"
  if [[ ${#raw} -lt 40 ]]; then
    printf '%s\n' "$ZERO_ADDR"
    return 0
  fi
  printf '0x%s\n' "${raw: -40}"
}

send_tx() {
  local to="$1"
  shift
  cast send "$to" "$@" \
    --rpc-url "$RPC_URL_138" \
    --private-key "$PRIVATE_KEY" \
    --legacy \
    --gas-price "$GAS_PRICE_WEI" \
    -q
}

big_add() {
  python3 - "$1" "$2" <<'PY'
import sys
print(int(sys.argv[1]) + int(sys.argv[2]))
PY
}

big_sub_if_positive() {
  python3 - "$1" "$2" <<'PY'
import sys
a = int(sys.argv[1])
b = int(sys.argv[2])
print(a - b if a > b else 0)
PY
}

big_lt() {
  python3 - "$1" "$2" <<'PY'
import sys
print("1" if int(sys.argv[1]) < int(sys.argv[2]) else "0")
PY
}

raw_to_human_6() {
  awk -v v="$1" 'BEGIN { printf "%.6f", v / 1000000 }'
}

raw_to_human_18() {
  awk -v v="$1" 'BEGIN { printf "%.18f", v / 1000000000000000000 }'
}

mul_div_round() {
  awk -v a="$1" -v b="$2" -v c="$3" 'BEGIN { printf "%.0f", (a * b) / c }'
}

derive_usd_per_eth() {
  local pool base_reserve quote_reserve
  local cusdt quote
  cusdt="$(jq -r '.tokens.cUSDT' "$EXECUTION_CONFIG")"
  quote="$WETH_ADDRESS"
  pool="$(hex_to_addr "$(cast call "$DODO_PMM_INTEGRATION_ADDRESS" 'pools(address,address)(address)' "$cusdt" "$quote" --rpc-url "$RPC_URL_138")")"
  [[ "$pool" != "$ZERO_ADDR" ]] || { echo "0"; return 1; }
  read -r base_reserve quote_reserve < <(get_pool_reserves "$pool")
  if [[ "$base_reserve" == "0" || "$quote_reserve" == "0" ]]; then
    echo "0"
    return 1
  fi
  awk -v base="$base_reserve" -v quote="$quote_reserve" 'BEGIN { printf "%.12f", (base / 1000000) / (quote / 1000000000000000000) }'
}

derive_xau_usd_per_unit() {
  local pool base_symbol quote_symbol base_addr quote_addr base_reserve quote_reserve fallback
  base_symbol="$(jq -r '.xauPricing.poolBaseSymbol' "$PLAN_JSON")"
  quote_symbol="$(jq -r '.xauPricing.poolQuoteSymbol' "$PLAN_JSON")"
  fallback="$(jq -r '.xauPricing.fallbackUsdPerUnit' "$PLAN_JSON")"
  base_addr="$(jq -r --arg sym "$base_symbol" '.tokens[$sym]' "$EXECUTION_CONFIG")"
  quote_addr="$(jq -r --arg sym "$quote_symbol" '.tokens[$sym]' "$EXECUTION_CONFIG")"
  pool="$(hex_to_addr "$(cast call "$DODO_PMM_INTEGRATION_ADDRESS" 'pools(address,address)(address)' "$base_addr" "$quote_addr" --rpc-url "$RPC_URL_138")")"
  if [[ "$pool" == "$ZERO_ADDR" ]]; then
    echo "$fallback"
    return 0
  fi
  read -r base_reserve quote_reserve < <(get_pool_reserves "$pool")
  if [[ "$base_reserve" == "0" || "$quote_reserve" == "0" ]]; then
    echo "$fallback"
    return 0
  fi
  awk -v base="$base_reserve" -v quote="$quote_reserve" 'BEGIN { printf "%.12f", (quote / 1000000) / (base / 1000000) }'
}

usd_per_eth="$(derive_usd_per_eth)"
[[ "$usd_per_eth" != "0" ]] || { echo "Could not derive USD per ETH from live cUSDT/WETH pool" >&2; exit 1; }
xau_usd_per_unit="$(derive_xau_usd_per_unit)"

log "=== Chain 138 ETH PMM Liquidity Funding ==="
log "Mode:        $( [[ "$EXECUTE" == "1" ]] && echo EXECUTE || echo DRY_RUN )"
log "Profile:     $PROFILE"
log "Plan:        $PLAN_JSON"
log "Config:      $EXECUTION_CONFIG"
log "Integration: $DODO_PMM_INTEGRATION_ADDRESS"
log "RPC:         $RPC_URL_138"
log "Deployer:    $DEPLOYER"
log "USD per ETH: $usd_per_eth"
log "XAU USD:     $xau_usd_per_unit"
log ""

total_quote_units=0
wrap_needed=0

declare -a ROWS=()
while IFS=$'\t' read -r base_symbol base_address; do
  pool="$(hex_to_addr "$(cast call "$DODO_PMM_INTEGRATION_ADDRESS" 'pools(address,address)(address)' "$base_address" "$WETH_ADDRESS" --rpc-url "$RPC_URL_138")")"
  [[ "$pool" != "$ZERO_ADDR" ]] || continue

  case "$base_symbol" in
    cXAUC|cXAUT)
      base_units="$XAU_BASE_UNITS"
      usd_per_unit="$xau_usd_per_unit"
      ;;
    *)
      base_units="$FIAT_BASE_UNITS"
      usd_per_unit="$(jq -r --arg sym "$base_symbol" '.usdPerUnit[$sym]' "$PLAN_JSON")"
      [[ "$usd_per_unit" != "null" ]] || { echo "Missing usdPerUnit for $base_symbol" >&2; exit 1; }
      ;;
  esac

  quote_units="$(awk -v base="$base_units" -v usd="$usd_per_unit" -v usd_eth="$usd_per_eth" 'BEGIN { printf "%.0f", ((base / 1000000) * usd / usd_eth) * 1000000000000000000 }')"
  read -r current_base_reserve current_quote_reserve < <(get_pool_reserves "$pool")
  base_delta="$(big_sub_if_positive "$base_units" "$current_base_reserve")"
  quote_delta="$(big_sub_if_positive "$quote_units" "$current_quote_reserve")"
  base_balance="$(cast call "$base_address" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL_138" 2>/dev/null || echo 0)"
  base_balance="$(uint_clean "$base_balance")"
  owner_addr="$(cast call "$base_address" 'owner()(address)' --rpc-url "$RPC_URL_138" 2>/dev/null || echo "$ZERO_ADDR")"
  ROWS+=("$base_symbol|$base_address|$pool|$base_units|$quote_units|$current_base_reserve|$current_quote_reserve|$base_delta|$quote_delta|$base_balance|$owner_addr")
  total_quote_units="$(big_add "$total_quote_units" "$quote_delta")"
done < <(jq -r '.explicitPairs[] | [.baseSymbol, (.baseSymbol as $s | .baseSymbol)] | @tsv' "$EXECUTION_CONFIG" | while IFS=$'\t' read -r base_symbol _; do
  base_address="$(jq -r --arg sym "$base_symbol" '.tokens[$sym]' "$EXECUTION_CONFIG")"
  printf '%s\t%s\n' "$base_symbol" "$base_address"
done)

weth_balance="$(cast call "$WETH_ADDRESS" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL_138" 2>/dev/null || echo 0)"
weth_balance="$(uint_clean "$weth_balance")"
eth_balance="$(cast balance "$DEPLOYER" --rpc-url "$RPC_URL_138" 2>/dev/null || echo 0)"
if [[ "$(big_lt "$weth_balance" "$total_quote_units")" == "1" ]]; then
  wrap_needed="$(big_sub_if_positive "$total_quote_units" "$weth_balance")"
fi

log "Current ETH:  $(raw_to_human_18 "$eth_balance")"
log "Current WETH: $(raw_to_human_18 "$weth_balance")"
log "Total WETH needed for profile: $(raw_to_human_18 "$total_quote_units")"
log "Additional WETH to wrap:       $(raw_to_human_18 "$wrap_needed")"
log ""

for row in "${ROWS[@]}"; do
  IFS='|' read -r base_symbol base_address pool base_units quote_units current_base_reserve current_quote_reserve base_delta quote_delta base_balance owner_addr <<< "$row"
  need_mint=0
  if [[ "$(big_lt "$base_balance" "$base_delta")" == "1" ]]; then
    need_mint="$(big_sub_if_positive "$base_delta" "$base_balance")"
  fi
  log "$base_symbol pool=$pool"
  log "  target base:   $(raw_to_human_6 "$base_units")"
  log "  target quote:  $(raw_to_human_18 "$quote_units") WETH"
  log "  current base:  $(raw_to_human_6 "$current_base_reserve")"
  log "  current quote: $(raw_to_human_18 "$current_quote_reserve") WETH"
  log "  top-up base:   $(raw_to_human_6 "$base_delta")"
  log "  top-up quote:  $(raw_to_human_18 "$quote_delta") WETH"
  log "  base balance: $(raw_to_human_6 "$base_balance")"
  if [[ "$need_mint" != "0" ]]; then
    log "  mint needed:  $(raw_to_human_6 "$need_mint")"
  else
    log "  mint needed:  no"
  fi
done

if [[ "$EXECUTE" != "1" ]]; then
  log ""
  log "Dry run only. Re-run with EXECUTE=1 to mint/wrap/approve/add liquidity."
  exit 0
fi

if [[ "$wrap_needed" != "0" ]]; then
  if [[ "$WRAP_WHEN_NEEDED" != "true" ]]; then
    echo "Need additional WETH but wrapNativeEthWhenNeeded=false" >&2
    exit 1
  fi
  if [[ "$(big_lt "$eth_balance" "$wrap_needed")" == "1" ]]; then
    echo "Insufficient ETH to wrap required WETH" >&2
    exit 1
  fi
  log "Wrapping $(raw_to_human_18 "$wrap_needed") ETH into WETH"
  send_tx "$WETH_ADDRESS" 'deposit()' --value "$wrap_needed" --gas-limit "$WRAP_GAS_LIMIT" >/dev/null
fi

for row in "${ROWS[@]}"; do
  IFS='|' read -r base_symbol base_address pool base_units quote_units current_base_reserve current_quote_reserve base_delta quote_delta base_balance owner_addr <<< "$row"
  if [[ "$base_delta" == "0" && "$quote_delta" == "0" ]]; then
    log "Skipping $base_symbol/WETH; already at or above target."
    continue
  fi

  if [[ "$(big_lt "$base_balance" "$base_delta")" == "1" ]]; then
    mint_amount="$(big_sub_if_positive "$base_delta" "$base_balance")"
    if [[ "$MINT_WHEN_OWNER" != "true" ]]; then
      echo "Need to mint $base_symbol but mintMissingBaseWhenOwner=false" >&2
      exit 1
    fi
    if [[ "${owner_addr,,}" != "${DEPLOYER,,}" ]]; then
      echo "Cannot mint $base_symbol; deployer is not owner ($owner_addr)" >&2
      exit 1
    fi
    log "Minting $(raw_to_human_6 "$mint_amount") $base_symbol"
    send_tx "$base_address" 'mint(address,uint256)' "$DEPLOYER" "$mint_amount" --gas-limit "$MINT_GAS_LIMIT" >/dev/null
  fi

  if [[ "$APPROVE_MAX" == "true" ]]; then
    log "Approving $base_symbol to integration"
    send_tx "$base_address" 'approve(address,uint256)' "$DODO_PMM_INTEGRATION_ADDRESS" "$MAX_UINT" --gas-limit "$APPROVE_GAS_LIMIT" >/dev/null
    log "Approving WETH for $base_symbol pair"
    send_tx "$WETH_ADDRESS" 'approve(address,uint256)' "$DODO_PMM_INTEGRATION_ADDRESS" "$MAX_UINT" --gas-limit "$APPROVE_GAS_LIMIT" >/dev/null
  fi

  log "Adding liquidity to $base_symbol/WETH at $pool"
  send_tx "$DODO_PMM_INTEGRATION_ADDRESS" 'addLiquidity(address,uint256,uint256)' "$pool" "$base_delta" "$quote_delta" --gas-limit "$ADD_LIQUIDITY_GAS_LIMIT" >/dev/null
done

log ""
log "Liquidity funding complete."
