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

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

if [[ -f .env ]]; then
  set -a
  # shellcheck source=/dev/null
  source .env
  set +a
fi

POOL_DB_NAME="${POOL_DB_NAME:-vexonpool}"
VEX_POOL_ROOT="${VEX_POOL_ROOT:-/opt/vexon-pool}"
VEX_BIN_DIR="${VEX_BIN_DIR:-$VEX_POOL_ROOT/bin}"
VEX_WEB_DIR="${VEX_WEB_DIR:-$VEX_POOL_ROOT/web}"
VEX_STRATUM_CONFIG_DIR="${VEX_STRATUM_CONFIG_DIR:-$VEX_POOL_ROOT/stratum-config}"
VEX_WALLET_SCREEN="${VEX_WALLET_SCREEN:-Vexon_Wallet}"
VEX_RPC_PORT="${VEX_RPC_PORT:-18556}"
VEX_RPC_USER="${VEX_RPC_USER:-}"
VEX_RPC_PASSWORD="${VEX_RPC_PASSWORD:-}"
VEX_WALLET_RPC_PORT="${VEX_WALLET_RPC_PORT:-18557}"
VEX_WALLET_RPC_USER="${VEX_WALLET_RPC_USER:-}"
VEX_WALLET_RPC_PASSWORD="${VEX_WALLET_RPC_PASSWORD:-}"
VEX_WALLET_PASSPHRASE="${VEX_WALLET_PASSPHRASE:-}"
VEX_START_WALLET="${VEX_START_WALLET:-0}"
VEX_MIN_PAYOUT="${VEX_MIN_PAYOUT:-0.001}"
VEX_PAYOUT_SCHEDULE_LABEL="${VEX_PAYOUT_SCHEDULE_LABEL:-Daily at 08:00 CST}"
VEX_BACKEND_CAN_STOP_NGINX="${VEX_BACKEND_CAN_STOP_NGINX:-0}"
STRATUM_PORT="${STRATUM_PORT:-4499}"

run_backend=0
if [[ "${1:-}" == "--run-backend" ]]; then
  run_backend=1
fi

failures=0
warnings=0

ok() { printf '[OK] %s\n' "$1"; }
warn() { printf '[WARN] %s\n' "$1"; warnings=$((warnings + 1)); }
fail() { printf '[FAIL] %s\n' "$1"; failures=$((failures + 1)); }
have() { command -v "$1" >/dev/null 2>&1; }

node_rpc() {
  "$VEX_BIN_DIR/vexonctl" --notls --rpcserver "127.0.0.1:${VEX_RPC_PORT}" \
    -u "$VEX_RPC_USER" -P "$VEX_RPC_PASSWORD" "$@"
}

wallet_rpc() {
  "$VEX_BIN_DIR/vexonctl" --wallet --notls --rpcserver "127.0.0.1:${VEX_WALLET_RPC_PORT}" \
    -u "$VEX_WALLET_RPC_USER" -P "$VEX_WALLET_RPC_PASSWORD" "$@"
}

mysql_scalar() {
  mysql -uroot "$POOL_DB_NAME" -Nse "$1" 2>/dev/null || true
}

mysql_table() {
  mysql -uroot "$POOL_DB_NAME" -e "$1" 2>/dev/null || true
}

check_port_listen() {
  local port="$1"
  local label="$2"
  if have ss && ss -lnt | awk '{print $4}' | grep -Eq "[:.]${port}$"; then
    ok "$label is listening on $port"
  else
    fail "$label is not listening on $port"
  fi
}

check_loop() {
  local screen_name="$1"
  local process_pattern="$2"
  if have screen && screen -ls 2>/dev/null | grep -q "$screen_name"; then
    ok "$screen_name screen is running"
  elif pgrep -f "$process_pattern" >/dev/null 2>&1; then
    ok "$screen_name process is running"
  else
    fail "$screen_name is not running"
  fi
}

echo "== Vexon payout closed-loop check =="
date
echo "Mode: $([[ "$run_backend" == "1" ]] && echo run-backend || echo dry-check)"

echo
echo "== required commands =="
for cmd in mysql ss pgrep php; do
  have "$cmd" && ok "command available: $cmd" || fail "missing command: $cmd"
done
[[ -x "$VEX_BIN_DIR/vexonctl" ]] && ok "vexonctl exists: $VEX_BIN_DIR/vexonctl" || fail "missing vexonctl: $VEX_BIN_DIR/vexonctl"

echo
echo "== payout policy =="
[[ "$VEX_MIN_PAYOUT" =~ ^[0-9]+([.][0-9]+)?$ ]] && ok "minimum payout is numeric: $VEX_MIN_PAYOUT VEX" || fail "VEX_MIN_PAYOUT must be numeric"
echo "Schedule: $VEX_PAYOUT_SCHEDULE_LABEL"
if [[ "$VEX_BACKEND_CAN_STOP_NGINX" == "0" ]]; then
  ok "backend payout run will not stop nginx"
else
  warn "VEX_BACKEND_CAN_STOP_NGINX=$VEX_BACKEND_CAN_STOP_NGINX; payout cron may stop nginx during old maintenance flow"
fi

echo
echo "== services =="
check_port_listen "$STRATUM_PORT" "Stratum"
check_port_listen "$VEX_RPC_PORT" "Vexon node RPC"
check_loop "vexon-pool-main" "main.sh"
check_loop "vexon-pool-loop2" "loop2.sh"
check_loop "vexon-pool-blocks" "blocks.sh"

if have ss; then
  stratum_connections="$(ss -tn | awk -v port=":${STRATUM_PORT}" '$0 ~ port {count++} END {print count + 0}')"
  if [[ "$stratum_connections" =~ ^[0-9]+$ ]] && (( stratum_connections > 0 )); then
    ok "active Stratum TCP connections: $stratum_connections"
  else
    warn "no active Stratum TCP connections; this is expected while miners are off"
  fi
fi

echo
echo "== node template path =="
if [[ -n "$VEX_RPC_USER" && -n "$VEX_RPC_PASSWORD" ]]; then
  if block_count="$(node_rpc getblockcount 2>/tmp/vexon-node-rpc.err.$$)"; then
    ok "node RPC getblockcount: $block_count"
  else
    fail "node RPC getblockcount failed: $(cat /tmp/vexon-node-rpc.err.$$ 2>/dev/null)"
  fi
  if peers="$(node_rpc getconnectioncount 2>/dev/null)"; then
    if [[ "$peers" =~ ^[0-9]+$ ]] && (( peers > 0 )); then
      ok "node peer count: $peers"
    else
      warn "node peer count is $peers; keep local peer or seed nodes online"
    fi
  else
    warn "could not read node peer count"
  fi
  if node_rpc getwork >/dev/null 2>/tmp/vexon-getwork.err.$$; then
    ok "node can produce getwork templates"
  else
    fail "node getwork failed: $(cat /tmp/vexon-getwork.err.$$ 2>/dev/null)"
  fi
  rm -f /tmp/vexon-node-rpc.err.$$ /tmp/vexon-getwork.err.$$
else
  fail "missing VEX_RPC_USER or VEX_RPC_PASSWORD"
fi

echo
echo "== wallet payout path =="
if [[ "$VEX_START_WALLET" != "1" ]]; then
  fail "VEX_START_WALLET is not 1; automatic chain payouts are disabled"
else
  [[ -n "$VEX_WALLET_PASSPHRASE" ]] && ok "wallet passphrase is configured for restart automation" || fail "VEX_WALLET_PASSPHRASE is empty; wallet RPC cannot restart unattended"
  check_loop "$VEX_WALLET_SCREEN" "vexonwallet"
  check_port_listen "$VEX_WALLET_RPC_PORT" "Vexon wallet RPC"
  if [[ -n "$VEX_WALLET_RPC_USER" && -n "$VEX_WALLET_RPC_PASSWORD" ]]; then
    if balance="$(wallet_rpc getbalance 2>/tmp/vexon-wallet-rpc.err.$$)"; then
      ok "wallet RPC getbalance: $balance"
    else
      fail "wallet RPC getbalance failed: $(cat /tmp/vexon-wallet-rpc.err.$$ 2>/dev/null)"
    fi
    rm -f /tmp/vexon-wallet-rpc.err.$$
  else
    fail "missing VEX_WALLET_RPC_USER or VEX_WALLET_RPC_PASSWORD"
  fi
fi

echo
echo "== database accounting path =="
if mysql -uroot "$POOL_DB_NAME" -Nse "SELECT 1" >/dev/null 2>&1; then
  ok "database is reachable: $POOL_DB_NAME"
else
  fail "database is not reachable: $POOL_DB_NAME"
fi

coin_row="$(mysql_scalar "SELECT CONCAT_WS('|', id, symbol, COALESCE(enable,''), COALESCE(auto_ready,''), COALESCE(payout_min,''), COALESCE(mature_blocks,''), COALESCE(txfee,''), COALESCE(master_wallet,'')) FROM coins WHERE symbol='VEX' LIMIT 1")"
if [[ -n "$coin_row" ]]; then
  IFS='|' read -r coin_id coin_symbol coin_enable coin_auto_ready coin_payout_min coin_mature_blocks coin_txfee coin_master_wallet <<< "$coin_row"
  ok "VEX coin row: id=$coin_id enable=$coin_enable auto_ready=$coin_auto_ready payout_min=$coin_payout_min mature_blocks=$coin_mature_blocks txfee=$coin_txfee"
  [[ "$coin_enable" == "1" ]] || fail "VEX coin is not enabled"
  [[ "$coin_auto_ready" == "1" ]] || fail "VEX coin auto_ready is not enabled"
  [[ "$coin_payout_min" =~ ^[0-9]+([.][0-9]+)?$ ]] || fail "VEX coin payout_min is not numeric"
  [[ "$coin_mature_blocks" =~ ^[1-9][0-9]*$ ]] || fail "VEX coin mature_blocks is not a positive integer"
  [[ "$coin_txfee" =~ ^[0-9]+([.][0-9]+)?$ ]] || fail "VEX coin txfee is not numeric"
else
  fail "missing VEX coin row"
  coin_id=""
fi

shares_24h="$(mysql_scalar "SELECT COUNT(*) FROM shares WHERE valid=1 AND algo='decred' AND time>UNIX_TIMESTAMP()-86400")"
if [[ "$shares_24h" =~ ^[0-9]+$ ]] && (( shares_24h > 0 )); then
  ok "accepted shares in last 24 hours: $shares_24h"
else
  warn "no accepted shares in last 24 hours; expected while miners are off"
fi

echo
echo "Recent share summary:"
mysql_table "
SELECT valid,error,COUNT(*) AS rows_count,SUM(difficulty) AS sumdiff,
FROM_UNIXTIME(MIN(time)) AS first_t,FROM_UNIXTIME(MAX(time)) AS last_t
FROM shares
WHERE algo='decred' AND time>UNIX_TIMESTAMP()-86400
GROUP BY valid,error
ORDER BY rows_count DESC;
"

if [[ -n "$coin_id" ]]; then
  echo
  echo "Block categories:"
  mysql_table "
SELECT category,COUNT(*) AS rows_count,FROM_UNIXTIME(MAX(time)) AS latest
FROM blocks
WHERE coin_id=${coin_id}
GROUP BY category
ORDER BY rows_count DESC;
"

  echo
  echo "Earnings lifecycle:"
  mysql_table "
SELECT status,COUNT(*) AS rows_count,COALESCE(SUM(amount),0) AS amount,
FROM_UNIXTIME(MAX(mature_time)) AS latest_mature
FROM earnings
WHERE coinid=${coin_id}
GROUP BY status
ORDER BY status;
"
fi

payable="$(mysql_scalar "SELECT COUNT(*) FROM accounts A JOIN coins C ON C.id=A.coinid WHERE C.symbol='VEX' AND A.balance >= ${VEX_MIN_PAYOUT}")"
if [[ "$payable" =~ ^[0-9]+$ ]] && (( payable > 0 )); then
  ok "accounts ready for payout: $payable"
else
  ok "accounts ready for payout: 0"
fi

failed_payouts="$(mysql_scalar "SELECT COUNT(*) FROM payouts P JOIN accounts A ON A.id=P.account_id JOIN coins C ON C.id=A.coinid WHERE C.symbol='VEX' AND P.completed=0 AND IFNULL(P.errmsg,'')<>''")"
if [[ "$failed_payouts" =~ ^[0-9]+$ ]] && (( failed_payouts > 0 )); then
  fail "failed payout rows need manual review: $failed_payouts"
else
  ok "no failed payout rows"
fi

open_payouts="$(mysql_scalar "SELECT COUNT(*) FROM payouts P JOIN accounts A ON A.id=P.account_id JOIN coins C ON C.id=A.coinid WHERE C.symbol='VEX' AND P.completed=0 AND IFNULL(P.tx,'')=''")"
if [[ "$open_payouts" =~ ^[0-9]+$ ]] && (( open_payouts > 0 )); then
  warn "open payout rows without tx: $open_payouts"
else
  ok "no open payout rows without tx"
fi

echo
echo "Recent payouts:"
mysql_table "
SELECT P.id,A.username AS address,P.amount,P.completed,P.tx,P.errmsg,FROM_UNIXTIME(P.time) AS t
FROM payouts P
JOIN accounts A ON A.id=P.account_id
JOIN coins C ON C.id=A.coinid
WHERE C.symbol='VEX'
ORDER BY P.id DESC
LIMIT 10;
"

echo
echo "== backend payout evaluator =="
if [[ ! -f "$VEX_WEB_DIR/runconsole.php" ]]; then
  fail "missing $VEX_WEB_DIR/runconsole.php"
elif [[ "$run_backend" == "1" ]]; then
  if (( failures > 0 )); then
    warn "skipped backend payout evaluator because blocking failures are already present"
  else
    ok "running backend payout evaluator now"
    (cd "$VEX_WEB_DIR" && php -d max_execution_time=300 runconsole.php cronjob/run)
  fi
else
  ok "dry check only; use scripts/payout-closed-loop-check.sh --run-backend to let cronjob/run evaluate the payout window"
fi

echo
echo "== result =="
if (( failures > 0 )); then
  echo "Payout closed-loop check failed with $failures failure(s) and $warnings warning(s)."
  exit 1
fi

echo "Payout closed-loop check passed with $warnings warning(s)."
