#!/usr/bin/env bash
# MYTC validator bootstrap — gets you from "fresh Ubuntu VPS" to "bonded
# validator" in two commands instead of four days. Foundation-recommended
# defaults; designed to be re-run safely (idempotent where it makes sense).
#
# Usage:
#   curl -sSL https://app.mytmessenger.mytherrablockchain.org/dl/become-validator.sh | sudo bash -s -- init --moniker "MyValidator"
#   # ↑ One command: installs mytcd, syncs, claims 1000 MYTC faucet, creates validator
#
# Or step-by-step:
#   sudo /usr/local/bin/mytc-bootstrap init --moniker "MyValidator"
#   sudo /usr/local/bin/mytc-bootstrap join --amount 1000
#
# Targets: Ubuntu 22.04 / 24.04 / Debian 12 on x86_64. Other distros may
# work but are not tested.

set -euo pipefail

readonly CHAIN_ID="mytherra-1"
readonly DOWNLOAD_BASE="https://app.mytmessenger.mytherrablockchain.org/dl"
readonly RPC_PRIMARY="https://app.mytmessenger.mytherrablockchain.org/mytc-rpc"
readonly RPC_SECONDARY="http://87.106.31.141:26657"
readonly P2P_FOUNDATION_1="5c67756024ba0566e5408330e9055b0009bae23a@217.154.114.75:26656"
readonly P2P_FOUNDATION_2="4b1bf1f6447be80665c4da7d040d05d1769e1e01@87.106.31.141:26656"
readonly MYTC_USER="mytc"
readonly MYTC_HOME="/home/${MYTC_USER}/.mytc"
readonly BIN_PATH="/usr/local/bin/mytcd"
readonly SERVICE_NAME="mytc"
readonly KEYRING="test"
readonly FAUCET_URL="https://app.mytmessenger.mytherrablockchain.org/faucet"

# ── Output helpers ──────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log()  { echo -e "${CYAN}▸${NC} $*"; }
ok()   { echo -e "${GREEN}✓${NC} $*"; }
warn() { echo -e "${YELLOW}⚠${NC}  $*" >&2; }
die()  { echo -e "${RED}✗ $*${NC}" >&2; exit 1; }

# ── Pre-flight ──────────────────────────────────────────────────────────────
need_root() {
  [[ $EUID -eq 0 ]] || die "Run as root (sudo)."
}

check_platform() {
  [[ "$(uname -s)" == "Linux" ]]   || die "Linux only. Detected: $(uname -s)"
  [[ "$(uname -m)" == "x86_64" ]]  || die "x86_64 only. Detected: $(uname -m)"
  command -v apt-get >/dev/null     || die "Need apt-get (Debian/Ubuntu only)."
}

install_deps() {
  log "Installing dependencies (curl, jq, ca-certificates)…"
  export DEBIAN_FRONTEND=noninteractive
  apt-get update -qq
  apt-get install -y -qq curl jq ca-certificates >/dev/null
  ok "Dependencies installed."
}

ensure_user() {
  if ! id -u "$MYTC_USER" >/dev/null 2>&1; then
    log "Creating system user '$MYTC_USER'…"
    useradd --system --create-home --shell /bin/bash "$MYTC_USER"
    ok "User '$MYTC_USER' created."
  fi
}

# ── Binary install ──────────────────────────────────────────────────────────
download_binary() {
  if [[ -x "$BIN_PATH" ]] && "$BIN_PATH" version >/dev/null 2>&1; then
    log "mytcd already installed at $BIN_PATH ($("$BIN_PATH" version 2>&1 | head -1))"
    return
  fi
  log "Downloading mytcd binary from $DOWNLOAD_BASE…"
  curl -fsSL "$DOWNLOAD_BASE/mytcd-linux-amd64" -o "$BIN_PATH.new"
  chmod +x "$BIN_PATH.new"
  mv "$BIN_PATH.new" "$BIN_PATH"
  ok "Binary installed: $($BIN_PATH version 2>&1 | head -1)"
}

download_genesis() {
  local dst="$MYTC_HOME/config/genesis.json"
  if [[ -s "$dst" ]]; then
    log "Genesis already present at $dst"
    return
  fi
  log "Downloading genesis.json…"
  curl -fsSL "$DOWNLOAD_BASE/genesis.json" -o "$dst.new"
  chown "$MYTC_USER:$MYTC_USER" "$dst.new"
  mv "$dst.new" "$dst"
  ok "Genesis installed."
}

download_addrbook() {
  local dst="$MYTC_HOME/config/addrbook.json"
  if [[ -s "$dst" ]]; then
    log "Addrbook already present at $dst"
    return
  fi
  log "Downloading addrbook.json…"
  curl -fsSL "$DOWNLOAD_BASE/addrbook.json" -o "$dst.new"
  chown "$MYTC_USER:$MYTC_USER" "$dst.new"
  mv "$dst.new" "$dst"
  ok "Addrbook installed."
}

# ── Node init + state-sync config ───────────────────────────────────────────
node_init() {
  local moniker="$1"
  if [[ -d "$MYTC_HOME/config" && -s "$MYTC_HOME/config/priv_validator_key.json" ]]; then
    log "Node already initialised at $MYTC_HOME — skipping init."
    return
  fi
  log "Initialising node (moniker=$moniker, chain-id=$CHAIN_ID)…"
  sudo -u "$MYTC_USER" "$BIN_PATH" init "$moniker" --chain-id "$CHAIN_ID" --home "$MYTC_HOME" >/dev/null 2>&1 || true
  ok "Node initialised."
}

configure_state_sync() {
  local cfg="$MYTC_HOME/config/config.toml"
  log "Fetching trust-block (current height − 1000) for state-sync…"
  local latest trust_h trust_hash
  latest=$(curl -fsSL "$RPC_PRIMARY/status" | jq -r '.result.sync_info.latest_block_height')
  if [[ -z "$latest" || "$latest" == "null" ]]; then
    die "Could not read latest height from $RPC_PRIMARY"
  fi
  trust_h=$((latest - 1000))
  trust_hash=$(curl -fsSL "$RPC_PRIMARY/block?height=$trust_h" | jq -r '.result.block_id.hash')
  [[ -n "$trust_hash" && "$trust_hash" != "null" ]] || die "Could not fetch trust-hash for block $trust_h"
  ok "Trust block: height=$trust_h hash=${trust_hash:0:16}…"

  log "Patching config.toml (state-sync + persistent peers)…"
  sed -i "s|^persistent_peers = .*|persistent_peers = \"$P2P_FOUNDATION_1,$P2P_FOUNDATION_2\"|" "$cfg"
  python3 - "$cfg" "$trust_h" "$trust_hash" "$RPC_PRIMARY" "$RPC_SECONDARY" <<'PYEOF'
import sys, re
cfg, h, hh, rpc1, rpc2 = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]
src = open(cfg).read()
def patch(key, val, qstr=True):
    global src
    v = f'"{val}"' if qstr else val
    src = re.sub(rf'^{key}\s*=.*$', f'{key} = {v}', src, flags=re.M, count=1)
patch('enable', 'true', qstr=False)
patch('rpc_servers', f'{rpc1},{rpc2}')
patch('trust_height', h, qstr=False)
patch('trust_hash', hh)
patch('trust_period', '168h0m0s')
open(cfg, 'w').write(src)
PYEOF
  chown "$MYTC_USER:$MYTC_USER" "$cfg"
  ok "config.toml patched."
}

# ── systemd service ─────────────────────────────────────────────────────────
install_service() {
  if systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then
    log "Service ${SERVICE_NAME}.service already installed."
    return
  fi
  log "Installing systemd service…"
  cat > "/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=MYTC Validator Node
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$MYTC_USER
ExecStart=$BIN_PATH start --home $MYTC_HOME
Restart=always
RestartSec=5
LimitNOFILE=65536
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF
  systemctl daemon-reload
  systemctl enable "$SERVICE_NAME" >/dev/null
  ok "Service installed + enabled."
}

start_service() {
  log "Starting $SERVICE_NAME.service…"
  systemctl restart "$SERVICE_NAME"
  sleep 3
  systemctl is-active --quiet "$SERVICE_NAME" \
    || die "Service failed to start. Check: journalctl -u $SERVICE_NAME -n 50"
  ok "Service running. Tail logs: journalctl -u $SERVICE_NAME -f"
}

wait_for_sync() {
  log "Waiting for state-sync + catchup (this is the slow bit, can take 10-30 min)…"
  local last_height=0
  local stuck_count=0
  while :; do
    local status
    status=$(sudo -u "$MYTC_USER" "$BIN_PATH" status --home "$MYTC_HOME" 2>/dev/null \
      || curl -fsSL "http://localhost:26657/status" 2>/dev/null) || true
    if [[ -z "$status" ]]; then
      sleep 5; continue
    fi
    local catching height
    catching=$(echo "$status" | jq -r '(.SyncInfo // .sync_info // .result.sync_info).catching_up')
    height=$(echo "$status" | jq -r '(.SyncInfo // .sync_info // .result.sync_info).latest_block_height')
    if [[ "$catching" == "false" ]]; then
      ok "Sync complete at block $height."
      return
    fi
    if [[ "$height" == "$last_height" ]]; then
      stuck_count=$((stuck_count+1))
    else
      stuck_count=0
    fi
    last_height="$height"
    log "  syncing… block $height (catching_up=$catching)"
    if (( stuck_count > 12 )); then
      warn "Sync has not advanced in ~2 min — peers may be slow. Still waiting; check 'journalctl -u $SERVICE_NAME' if it stays stuck."
      stuck_count=0
    fi
    sleep 10
  done
}

# ── Wallet ──────────────────────────────────────────────────────────────────
ensure_wallet() {
  log "Checking validator wallet…"
  local addr
  if addr=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys show validator -a --keyring-backend "$KEYRING" --home "$MYTC_HOME" 2>/dev/null); then
    ok "Wallet 'validator' already exists: $addr"
    echo "$addr"
    return
  fi
  log "Generating fresh wallet 'validator' (writing mnemonic to ${MYTC_HOME}/validator-mnemonic.txt — back this up!)…"
  local out
  out=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys add validator --keyring-backend "$KEYRING" --home "$MYTC_HOME" --output json 2>&1)
  echo "$out" | jq -r '.mnemonic' > "$MYTC_HOME/validator-mnemonic.txt"
  chmod 600 "$MYTC_HOME/validator-mnemonic.txt"
  chown "$MYTC_USER:$MYTC_USER" "$MYTC_HOME/validator-mnemonic.txt"
  addr=$(echo "$out" | jq -r '.address')
  ok "Wallet generated: $addr"
  echo "$addr"
}

# ── Phase 1: init ────────────────────────────────────────────────────────────
cmd_init() {
  local moniker=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --moniker) moniker="$2"; shift 2;;
      *) die "Unknown flag: $1";;
    esac
  done
  [[ -n "$moniker" ]] || die "--moniker required (e.g. --moniker \"MyValidator\")"

  need_root
  check_platform
  install_deps
  ensure_user
  download_binary

  install -d -o "$MYTC_USER" -g "$MYTC_USER" "$MYTC_HOME/config" "$MYTC_HOME/data"

  node_init "$moniker"
  download_genesis
  download_addrbook
  configure_state_sync
  install_service
  start_service
  wait_for_sync

  local addr
  addr=$(ensure_wallet)

  cp "$0" /usr/local/bin/mytc-bootstrap 2>/dev/null || \
    curl -fsSL "$DOWNLOAD_BASE/become-validator.sh" -o /usr/local/bin/mytc-bootstrap
  chmod +x /usr/local/bin/mytc-bootstrap

  # ── Auto-claim faucet + join ──────────────────────────────────────────────
  log "Claiming 1000 MYTC from Foundation faucet…"
  local faucet_ok=false
  local faucet_tx=""
  for attempt in 1 2 3; do
    local resp
    resp=$(curl -fsSL -X POST "$FAUCET_URL" \
      -H "Content-Type: application/json" \
      -d "{\"address\":\"$addr\"}" 2>/dev/null) || true
    if [[ -n "$resp" ]]; then
      local fcode
      fcode=$(echo "$resp" | jq -r '.error // empty')
      if [[ -z "$fcode" ]]; then
        faucet_tx=$(echo "$resp" | jq -r '.txhash // empty')
        ok "Faucet claimed: $faucet_tx"
        faucet_ok=true
        break
      elif [[ "$fcode" == *"already claimed"* ]]; then
        warn "Address already claimed faucet previously — continuing."
        faucet_ok=true
        break
      else
        warn "Faucet attempt $attempt failed: $fcode"
        sleep 2
      fi
    else
      warn "Faucet attempt $attempt: no response"
      sleep 2
    fi
  done

  if [[ "$faucet_ok" == "true" ]]; then
    log "Waiting for balance to arrive (polling, max 60s)…"
    local bal=0
    local waited=0
    while (( waited < 60 )); do
      bal=$(sudo -u "$MYTC_USER" "$BIN_PATH" query bank balances "$addr" --home "$MYTC_HOME" --output json 2>/dev/null \
        | jq -r '[.balances[] | select(.denom=="umytc") | .amount][0] // "0"')
      if (( bal >= 1000000000 )); then  # 1000 * 1_000_000 umytc
        ok "Balance arrived: $((bal / 1000000)) MYTC"
        break
      fi
      sleep 3
      waited=$((waited + 3))
      echo -n "."
    done
    echo

    if (( bal >= 1000000000 )); then
      log "Auto-submitting create-validator…"
      cmd_join --amount 1000
      return
    else
      warn "Balance not detected after 60s. You may need to wait longer or fund manually."
    fi
  else
    warn "Faucet claim failed. Fund $addr manually and run: sudo mytc-bootstrap join --amount 1000"
  fi

  cat <<EOF

${GREEN}════════════════════════════════════════════════════════════════════${NC}
  ${GREEN}✓ Node is synced and running.${NC}

  Validator wallet address:
    ${CYAN}$addr${NC}

  ${YELLOW}Next:${NC}
    Run: ${CYAN}sudo mytc-bootstrap join --amount 1000${NC}
    (requires 1000 MYTC on the address above)

  ${YELLOW}Useful commands:${NC}
    • Logs:        ${CYAN}journalctl -u $SERVICE_NAME -f${NC}
    • Status:      ${CYAN}sudo -u $MYTC_USER mytcd status --home $MYTC_HOME | jq${NC}
    • Balance:     ${CYAN}sudo -u $MYTC_USER mytcd query bank balances $addr --home $MYTC_HOME${NC}

  ${RED}IMPORTANT:${NC} back up ${CYAN}$MYTC_HOME/validator-mnemonic.txt${NC} somewhere offline.
  Lose it = lose the validator forever.
${GREEN}════════════════════════════════════════════════════════════════════${NC}

EOF
}

# ── Phase 2: join (create-validator) ────────────────────────────────────────
cmd_join() {
  local amount_mytc=1000
  local commission_rate="0.10"
  local commission_max="0.20"
  local commission_max_change="0.01"
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --amount) amount_mytc="$2"; shift 2;;
      --commission-rate) commission_rate="$2"; shift 2;;
      --commission-max-rate) commission_max="$2"; shift 2;;
      --commission-max-change-rate) commission_max_change="$2"; shift 2;;
      *) die "Unknown flag: $1";;
    esac
  done

  need_root
  [[ -x "$BIN_PATH" ]] || die "mytcd not installed. Run init first."

  local addr
  addr=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys show validator -a --keyring-backend "$KEYRING" --home "$MYTC_HOME" 2>/dev/null) \
    || die "No 'validator' key in keyring. Run init first."

  log "Checking balance for $addr…"
  local bal
  bal=$(sudo -u "$MYTC_USER" "$BIN_PATH" query bank balances "$addr" --home "$MYTC_HOME" --output json 2>/dev/null \
    | jq -r '[.balances[] | select(.denom=="umytc") | .amount][0] // "0"')
  local need_umytc=$((amount_mytc * 1000000))
  if (( bal < need_umytc )); then
    die "Balance is $((bal / 1000000)) MYTC, need at least $amount_mytc MYTC. Send funds to $addr and retry."
  fi
  ok "Balance OK ($((bal / 1000000)) MYTC)."

  log "Verifying node is fully synced…"
  local catching
  catching=$(sudo -u "$MYTC_USER" "$BIN_PATH" status --home "$MYTC_HOME" 2>/dev/null \
    | jq -r '(.SyncInfo // .sync_info).catching_up')
  [[ "$catching" == "false" ]] || die "Node still catching up. Wait until 'catching_up: false', then retry."
  ok "Node is in sync."

  local moniker pubkey
  moniker=$(jq -r '.moniker' "$MYTC_HOME/config/config.toml" 2>/dev/null \
    || sed -n 's/^moniker = "\(.*\)"/\1/p' "$MYTC_HOME/config/config.toml")
  pubkey=$(sudo -u "$MYTC_USER" "$BIN_PATH" tendermint show-validator --home "$MYTC_HOME")

  log "Submitting MsgCreateValidator (moniker=$moniker, self-bond=${amount_mytc} MYTC)…"
  local txout
  txout=$(sudo -u "$MYTC_USER" "$BIN_PATH" tx staking create-validator \
    --amount "${amount_mytc}000000umytc" \
    --pubkey "$pubkey" \
    --moniker "$moniker" \
    --chain-id "$CHAIN_ID" \
    --commission-rate "$commission_rate" \
    --commission-max-rate "$commission_max" \
    --commission-max-change-rate "$commission_max_change" \
    --min-self-delegation "1" \
    --from validator --keyring-backend "$KEYRING" --home "$MYTC_HOME" \
    --gas auto --gas-adjustment 1.4 --fees 5000umytc \
    -y --output json 2>&1) || die "create-validator failed:\n$txout"

  local code txhash
  code=$(echo "$txout" | jq -r '.code // empty')
  txhash=$(echo "$txout" | jq -r '.txhash // empty')
  [[ "$code" == "0" || -z "$code" ]] || die "TX rejected (code=$code):\n$txout"

  ok "create-validator TX submitted: $txhash"
  log "Waiting one block (~6s) for inclusion…"
  sleep 8

  local valoper
  valoper=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys show validator --bech val -a --keyring-backend "$KEYRING" --home "$MYTC_HOME")
  local status
  status=$(sudo -u "$MYTC_USER" "$BIN_PATH" query staking validator "$valoper" --home "$MYTC_HOME" --output json 2>/dev/null \
    | jq -r '.status' || echo "")
  if [[ "$status" == "BOND_STATUS_BONDED" ]]; then
    cat <<EOF

${GREEN}════════════════════════════════════════════════════════════════════${NC}
  ${GREEN}🎉  You are now a bonded MYTC validator.${NC}

  Operator address: ${CYAN}$valoper${NC}
  Account address:  ${CYAN}$addr${NC}
  TX hash:          ${CYAN}$txhash${NC}

  ${YELLOW}Watch your validator:${NC}
    • Sign rate:   ${CYAN}sudo -u $MYTC_USER mytcd query slashing signing-info \$(sudo -u $MYTC_USER mytcd tendermint show-address --home $MYTC_HOME) --home $MYTC_HOME${NC}
    • Stake:       ${CYAN}sudo -u $MYTC_USER mytcd query staking validator $valoper --home $MYTC_HOME${NC}
    • Logs:        ${CYAN}journalctl -u $SERVICE_NAME -f${NC}
${GREEN}════════════════════════════════════════════════════════════════════${NC}

EOF
  else
    warn "TX submitted but validator status is '${status:-unknown}'. May need a block to settle."
    warn "Check again in ~10s with: sudo -u $MYTC_USER mytcd query staking validator $valoper --home $MYTC_HOME"
  fi
}

# ── Status ──────────────────────────────────────────────────────────────────
cmd_status() {
  [[ -x "$BIN_PATH" ]] || die "mytcd not installed."
  local addr valoper
  addr=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys show validator -a --keyring-backend "$KEYRING" --home "$MYTC_HOME" 2>/dev/null || echo "")
  valoper=$(sudo -u "$MYTC_USER" "$BIN_PATH" keys show validator --bech val -a --keyring-backend "$KEYRING" --home "$MYTC_HOME" 2>/dev/null || echo "")
  echo "Account:  $addr"
  echo "Operator: $valoper"
  echo
  echo "── Sync ──"
  sudo -u "$MYTC_USER" "$BIN_PATH" status --home "$MYTC_HOME" 2>/dev/null \
    | jq '{height: (.SyncInfo // .sync_info).latest_block_height, catching_up: (.SyncInfo // .sync_info).catching_up}'
  echo
  if [[ -n "$valoper" ]]; then
    echo "── Validator ──"
    sudo -u "$MYTC_USER" "$BIN_PATH" query staking validator "$valoper" --home "$MYTC_HOME" --output json 2>/dev/null \
      | jq '{moniker: .description.moniker, status, jailed, tokens: (.tokens|tonumber/1e6)}' || echo "  (not yet a validator)"
  fi
}

# ── Entry point ──────────────────────────────────────────────────────────────
case "${1:-}" in
  init)   shift; cmd_init   "$@" ;;
  join)   shift; cmd_join   "$@" ;;
  status) shift; cmd_status "$@" ;;
  ""|help|--help|-h)
    cat <<'EOF'
MYTC validator bootstrap.

  init   --moniker "Name"               Install + sync + generate wallet
  join   [--amount 1000]                Submit create-validator (after funding)
  status                                Show node + validator state
EOF
    ;;
  *) die "Unknown command: $1 — try 'help'." ;;
esac
