#!/usr/bin/env bash
# ============================================================
# Timmy Node — Auto-sweep hot wallet to cold storage
#
# Run manually:  bash /opt/timmy-node/sweep.sh
# Run by cron:   configured by ops.sh configure-sweep
#
# Config:  /opt/timmy-node/sweep.conf
# State:   /opt/timmy-node/sweep-state   (address index, auto-managed)
# Addresses: /opt/timmy-node/sweep-addresses.txt  (for list mode)
# ============================================================
set -euo pipefail

INFRA_DIR="/opt/timmy-node"
CONF_FILE="$INFRA_DIR/sweep.conf"
STATE_FILE="$INFRA_DIR/sweep-state"
ADDR_LIST_FILE="$INFRA_DIR/sweep-addresses.txt"
LOG_FILE="/var/log/timmy-sweep.log"
TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M:%S UTC')

log() { echo "[$TIMESTAMP] $*" | tee -a "$LOG_FILE"; }

# ── Load config ──────────────────────────────────────────────
if [[ ! -f "$CONF_FILE" ]]; then
  log "SKIP — no sweep.conf found at $CONF_FILE (run: bash ops.sh configure-sweep)"
  exit 0
fi

source "$CONF_FILE"

SWEEP_MODE="${SWEEP_MODE:-static}"
COLD_ADDRESS="${COLD_ADDRESS:-}"
XPUB="${XPUB:-}"
KEEP_SATS="${KEEP_SATS:-300000}"
MIN_SWEEP="${MIN_SWEEP:-50000}"

# ── Resolve destination address ──────────────────────────────
# Sets SWEEP_TO or exits. Logs the resolved address and remaining capacity.
resolve_address() {
  case "$SWEEP_MODE" in

    xpub)
      if [[ -z "$XPUB" ]]; then
        log "ERROR — SWEEP_MODE=xpub but XPUB not set in $CONF_FILE"
        exit 1
      fi
      NEXT_INDEX=0
      [[ -f "$STATE_FILE" ]] && source "$STATE_FILE"

      DESC="wpkh(${XPUB}/0/${NEXT_INDEX})"
      CHECKSUM_DESC=$(docker exec bitcoin bitcoin-cli \
        -datadir=/home/bitcoin/.bitcoin \
        getdescriptorinfo "$DESC" 2>&1 | jq -r '.descriptor // empty')

      if [[ -z "$CHECKSUM_DESC" ]]; then
        log "ERROR — could not get descriptor info for index $NEXT_INDEX (is Bitcoin Core synced?)"
        exit 1
      fi

      DERIVED=$(docker exec bitcoin bitcoin-cli \
        -datadir=/home/bitcoin/.bitcoin \
        deriveaddresses "$CHECKSUM_DESC" 2>&1 | jq -r '.[0] // empty')

      if [[ -z "$DERIVED" || "$DERIVED" == "null" ]]; then
        log "ERROR — could not derive address at xpub index $NEXT_INDEX"
        exit 1
      fi

      SWEEP_TO="$DERIVED"
      log "ADDRESS — xpub index ${NEXT_INDEX} → ${SWEEP_TO}"
      ;;

    list)
      if [[ ! -f "$ADDR_LIST_FILE" ]]; then
        log "ERROR — SWEEP_MODE=list but $ADDR_LIST_FILE not found (run: bash ops.sh configure-sweep)"
        exit 1
      fi
      NEXT_INDEX=0
      [[ -f "$STATE_FILE" ]] && source "$STATE_FILE"

      ADDR=$(sed -n "$((NEXT_INDEX + 1))p" "$ADDR_LIST_FILE" | tr -d '[:space:]')
      if [[ -z "$ADDR" ]]; then
        log "ERROR — address list exhausted at index ${NEXT_INDEX} — add more addresses via ops.sh configure-sweep"
        exit 1
      fi

      TOTAL=$(grep -c '[^[:space:]]' "$ADDR_LIST_FILE" || true)
      REMAINING=$(( TOTAL - NEXT_INDEX ))
      if (( REMAINING <= 5 )); then
        log "WARNING — only ${REMAINING} address(es) remaining in list, add more soon"
      fi

      SWEEP_TO="$ADDR"
      log "ADDRESS — list index ${NEXT_INDEX} (${REMAINING} remaining) → ${SWEEP_TO}"
      ;;

    static|*)
      if [[ -z "$COLD_ADDRESS" ]]; then
        log "SKIP — COLD_ADDRESS not set in $CONF_FILE (run: bash ops.sh configure-sweep)"
        exit 0
      fi
      SWEEP_TO="$COLD_ADDRESS"
      ;;
  esac
}

resolve_address

# ── Get confirmed on-chain balance ───────────────────────────
BALANCE=$(docker exec lnd lncli --network=mainnet walletbalance 2>/dev/null \
  | jq -r '.confirmed_balance // "0"')

if [[ -z "$BALANCE" || "$BALANCE" == "null" ]]; then
  log "ERROR — could not read LND wallet balance (is LND running?)"
  exit 1
fi

log "Balance: ${BALANCE} sats  |  keep: ${KEEP_SATS}  |  destination: ${SWEEP_TO}"

# ── Calculate sweep amount ────────────────────────────────────
SWEEP_AMT=$(( BALANCE - KEEP_SATS ))

if (( SWEEP_AMT < MIN_SWEEP )); then
  log "SKIP — sweep amount ${SWEEP_AMT} sats is below MIN_SWEEP ${MIN_SWEEP} sats (nothing sent)"
  exit 0
fi

# ── Send to cold address ──────────────────────────────────────
log "SWEEP — sending ${SWEEP_AMT} sats to ${SWEEP_TO}..."

if ! SEND_RESULT=$(docker exec lnd lncli --network=mainnet sendcoins \
  --addr "$SWEEP_TO" \
  --amt "$SWEEP_AMT" \
  2>&1)
then
  log "ERROR — sendcoins failed: $SEND_RESULT"
  exit 1
fi

TXID=$(echo "$SEND_RESULT" | jq -r '.txid // empty' 2>/dev/null || echo "")

if [[ -z "$TXID" ]]; then
  log "ERROR — sendcoins returned no txid: $SEND_RESULT"
  exit 1
fi

log "SUCCESS — txid=${TXID}  amount=${SWEEP_AMT} sats  →  ${SWEEP_TO}"

# ── Advance address index (xpub / list modes) ─────────────────
if [[ "$SWEEP_MODE" == "xpub" || "$SWEEP_MODE" == "list" ]]; then
  NEXT_INDEX=0
  [[ -f "$STATE_FILE" ]] && source "$STATE_FILE"
  NEW_INDEX=$(( NEXT_INDEX + 1 ))
  echo "NEXT_INDEX=$NEW_INDEX" > "$STATE_FILE"
  chmod 600 "$STATE_FILE"
  log "INDEX — advanced to ${NEW_INDEX} for next sweep"
fi

# ── Trigger channel state backup ──────────────────────────────
log "BACKUP — triggering channel state backup after sweep..."
bash "$INFRA_DIR/ops.sh" backup >> "$LOG_FILE" 2>&1 && \
  log "BACKUP — complete" || \
  log "BACKUP — WARNING: backup failed, check ops.sh backup manually"

exit 0
