#!/bin/sh
set -u
umask 077

RUNNER="/usr/local/sbin/router-egress-emergency-refresh.sh"
APPLY="/usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh"
PLANNER="/usr/local/sbin/router-egress-hmn-plan-top5.sh"
HELPER="/usr/local/lib/router-egress-recovery-state.sh"
CONF="/etc/router-egress-emergency-refresh.conf"

HOOK_INIT="/etc/init.d/router-egress-emergency-decision"
WATCHER_INIT="/etc/init.d/router-egress-health-repair"

POOL="/root/hmn/cache/ok-awg1-strict-foreign-latest.tsv"

fact() {
  printf '__FACT__ %s=%s\n' "$1" "$2"
}

block() {
  name="$1"
  shift

  echo "__BLOCK_BEGIN__ $name"
  "$@" 2>&1 || true
  echo "__BLOCK_END__ $name"
}

block_file() {
  name="$1"
  path="$2"

  echo "__BLOCK_BEGIN__ $name"

  if [ -f "$path" ]; then
    cat "$path"
  else
    echo "FILE_NOT_PRESENT=$path"
  fi

  echo "__BLOCK_END__ $name"
}

bool_cmd() {
  if "$@" >/dev/null 2>&1; then
    printf true
  else
    printf false
  fi
}

state_value() {
  key="$1"
  fallback="$2"

  (
    unset REG_STATE_DIR
    . "$HELPER"
    reg_get_state "$key" "$fallback"
  )
}

repair_counter() {
  (
    unset REG_STATE_DIR
    . "$HELPER"
    reg_daily_repair_get
  )
}

strict_iface() {
  interface="$1"
  attempt=1

  while [ "$attempt" -le 3 ]; do
    if ping \
      -I "$interface" \
      -c 1 \
      -W 3 \
      1.1.1.1 \
      >/dev/null 2>&1
    then
      return 0
    fi

    attempt=$((attempt + 1))
    sleep 1
  done

  return 1
}

routes_all() {
  for table in 201 202 203 204 205; do
    ip route show table "$table" 2>/dev/null |
      grep -q '^default ' ||
      return 1
  done

  return 0
}

for required in \
  "$RUNNER" \
  "$APPLY" \
  "$PLANNER" \
  "$HELPER" \
  "$CONF" \
  "$POOL"
do
  [ -f "$required" ] || {
    echo "__ERROR__ source_missing=$required"
    exit 21
  }
done

echo "__TRACE__ stage=clock_and_timezone"

fact snapshot_epoch "$(date +%s)"
fact vm101_local_time "$(date '+%Y-%m-%dT%H:%M:%S%z')"
fact vm101_utc_time "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
fact kernel "$(uname -a | tr ' ' '_')"

fact etc_tz "$(
  tr '\r\n ' '_' < /etc/TZ 2>/dev/null ||
  echo UNAVAILABLE
)"

fact uci_timezone "$(
  uci -q get system.@system[0].timezone 2>/dev/null ||
  echo UNAVAILABLE
)"

fact uci_zonename "$(
  uci -q get system.@system[0].zonename 2>/dev/null ||
  echo UNAVAILABLE
)"

block date_output date
block date_utc_output date -u
block uptime_output uptime

echo "__TRACE__ stage=scheduler_contract"

block_file root_crontab /etc/crontabs/root
block crontab_l crontab -l

block scheduler_processes sh -c '
  ps w |
    grep -E "[c]rond|[c]ron|[t]imer|hmn.*refresh|refresh.*hmn" ||
  true
'

block scheduler_search sh -c '
  for base in \
    /etc/crontabs \
    /etc/init.d \
    /etc/config \
    /etc/rc.local \
    /root/hmn \
    /usr/local/sbin
  do
    [ -e "$base" ] || continue

    if [ -f "$base" ]; then
      files="$base"
    else
      files="$(
        find "$base" \
          -maxdepth 4 \
          -type f \
          2>/dev/null |
        sort
      )"
    fi

    for path in $files; do
      case "$path" in
        *.sh|*/cron*|*/crontab*|*/rc.local|*refresh*|*timer*|*hmn*)
          matches="$(
            grep -nEi \
              "(^|[[:space:]])20[[:space:]]+4([[:space:]]|$)|04:20|4:20|hmn.*refresh|refresh.*hmn" \
              "$path" \
              2>/dev/null ||
            true
          )"

          if [ -n "$matches" ]; then
            echo "===== $path ====="
            printf "%s\n" "$matches"
          fi
          ;;
      esac
    done
  done
'

block cron_logs sh -c '
  logread 2>/dev/null |
    grep -Ei "cron|hmn.*refresh|refresh.*hmn" |
    tail -n 300 ||
  true
'

echo "__TRACE__ stage=services_and_locks"

fact hook_running "$(bool_cmd "$HOOK_INIT" running)"
fact hook_enabled "$(bool_cmd "$HOOK_INIT" enabled)"
fact watcher_running "$(bool_cmd "$WATCHER_INIT" running)"
fact watcher_enabled "$(bool_cmd "$WATCHER_INIT" enabled)"

fact emergency_lock_present "$(
  bool_cmd test -e /var/lock/router-egress-emergency-refresh.lock
)"

fact refresh_lock_present "$(
  bool_cmd test -e /tmp/hmn-refresh-pool-safe.lock
)"

block relevant_processes sh -c '
  ps w |
    grep -E \
      "[h]mn-refresh|[r]outer-egress-emergency-refresh|[r]ebalance-top5|[h]ealth-repair-watch" ||
  true
'

echo "__TRACE__ stage=recovery_state"

fact state_mode "$(state_value mode UNKNOWN)"
fact state_status "$(
  state_value last_emergency_refresh_status UNKNOWN
)"
fact state_epoch "$(
  state_value last_emergency_refresh_epoch 0
)"
fact repair_counter "$(repair_counter)"

fact commit_raw "$(
  (
    . "$CONF"
    printf '%s' "${EMERGENCY_COMMIT_ENABLED:-UNSET}"
  )
)"

block safe_emergency_config sh -c "
  grep -E \
    '^(EMERGENCY_(COMMIT_ENABLED|DAILY_FAIL_THRESHOLD|COOLDOWN_SECONDS|REFRESH_CMD|PLANNER_CMD|REBALANCE_APPLY_CMD|WATCHER_CMD|DIRECT_FAILOPEN_ENABLED|LOG))=' \
    '$CONF' ||
  true
"

block state_files sh -c '
  find /var/lib/router-egress-recovery \
    -maxdepth 3 \
    -type f \
    2>/dev/null |
  sort |
  while IFS= read -r path; do
    printf "%s  " "$path"
    sha256sum "$path" 2>/dev/null |
      sed "s/[[:space:]].*$//"
  done
'

echo "__TRACE__ stage=current_endpoints"

HEALTHY_COUNT=0

for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  if strict_iface "$interface"; then
    strict=true
    HEALTHY_COUNT=$((HEALTHY_COUNT + 1))
  else
    strict=false
  fi

  fact "strict.${interface}" "$strict"

  endpoint="$(
    wg show "$interface" dump 2>/dev/null |
      awk '
        NR > 1 && $3 != "(none)" {
          print $3
          exit
        }
      '
  )"

  [ -n "$endpoint" ] ||
    endpoint="UNRESOLVED"

  fact "endpoint.${interface}" "$endpoint"

  peer_runtime="$(
    wg show "$interface" dump 2>/dev/null |
      awk '
        NR > 1 {
          printf(
            "endpoint=%s latest_handshake=%s rx=%s tx=%s keepalive=%s\n",
            $3,
            $5,
            $6,
            $7,
            $8
          )
        }
      '
  )"

  echo "__BLOCK_BEGIN__ runtime_${interface}"
  printf '%s\n' "$peer_runtime"
  echo "__BLOCK_END__ runtime_${interface}"
done

fact healthy_vpn_slots "$HEALTHY_COUNT"
fact routes_201_205 "$(bool_cmd routes_all)"

block table_200 ip route show table 200

block routes_201_205 sh -c '
  for table in 201 202 203 204 205; do
    echo "===== table $table ====="
    ip route show table "$table"
  done
'

block safe_network_sections sh -c '
  uci show network 2>/dev/null |
    grep -E \
      "^network\.vpn[1-5]\.(proto|device|ifname|addresses|address|endpoint_host|endpoint_port|route_allowed_ips|metric|mtu|listen_port)=" |
    sed \
      -e "/private_key/d" \
      -e "/preshared_key/d" ||
  true
'

echo "__TRACE__ stage=runner_and_planner"

block runner_dry_run "$RUNNER" --dry-run
block current_planner "$PLANNER"

echo "__TRACE__ stage=pool_and_generation"

fact pool_sha256 "$(
  sha256sum "$POOL" |
    sed 's/[[:space:]].*$//'
)"

fact pool_rows "$(
  awk 'NR > 1 {count++} END {print count + 0}' "$POOL"
)"

fact pool_mtime_epoch "$(date -r "$POOL" +%s)"

block pool_head head -n 20 "$POOL"
block pool_tail tail -n 20 "$POOL"

block quarantine_files sh -c '
  find /root/hmn/cache /var/lib/router-egress-recovery \
    -maxdepth 4 \
    -type f \
    \( \
      -name "*quarantine*" \
      -o -name "*bad*" \
      -o -name "*retry*" \
    \) \
    2>/dev/null |
  sort |
  while IFS= read -r path; do
    echo "===== $path ====="
    ls -l "$path"
    sha256sum "$path" 2>/dev/null || true
    sed -n "1,200p" "$path" 2>/dev/null || true
  done
'

LATEST_TARGET="$(
  readlink -f /root/hmn/configs/awg1/latest 2>/dev/null ||
  true
)"

fact latest_generation "$(
  printf '%s' "${LATEST_TARGET:-UNRESOLVED}" |
    tr ' ' '_'
)"

block latest_generation_listing sh -c '
  latest="$(
    readlink -f /root/hmn/configs/awg1/latest 2>/dev/null ||
    true
  )"

  echo "latest=$latest"

  if [ -n "$latest" ] && [ -d "$latest" ]; then
    find "$latest" \
      -maxdepth 1 \
      -type f \
      -name "*.conf" \
      2>/dev/null |
    sort |
    while IFS= read -r path; do
      printf "%s  " "$path"
      sha256sum "$path" |
        sed "s/[[:space:]].*$//"
    done
  fi
'

echo "__TRACE__ stage=sources"

for source_path in \
  "$RUNNER" \
  "$APPLY" \
  "$PLANNER" \
  /usr/local/sbin/router-egress-hmn-rebalance-top5.sh \
  /usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh \
  /usr/local/sbin/router-egress-health-repair-watch.sh \
  /usr/local/sbin/router-egress-emergency-decision-hook.sh \
  /root/hmn/hmn-refresh-pool-safe.sh \
  /root/hmn/hmn-code-test.sh
do
  if [ -f "$source_path" ]; then
    fact "source_sha256.$(
      printf '%s' "$source_path" |
        sed 's#[^A-Za-z0-9]#_#g'
    )" "$(
      sha256sum "$source_path" |
        sed 's/[[:space:]].*$//'
    )"
  fi
done

block apply_failure_contract sh -c "
  grep -nE \
    'commit_ok|commit_failed|slot_apply_failed|apply_ok|exit|return|adapter|rollback|strict' \
    '$APPLY' ||
  true
"

block runner_exit_contract sh -c "
  grep -nE \
    'REBALANCE_APPLY|refresh_ok_rebalance_ok|refresh_ok_rebalance_failed|apply_ok|commit_failed|exit|return' \
    '$RUNNER' ||
  true
"

echo "__TRACE__ stage=logs_and_failure_artifacts"

block emergency_log_tail sh -c '
  tail -n 500 \
    /var/log/router-egress-emergency-refresh.log \
    2>/dev/null ||
  true
'

block recent_hmn_logs sh -c '
  find /root/hmn/logs \
    -maxdepth 2 \
    -type f \
    -mmin -1440 \
    2>/dev/null |
  sort |
  while IFS= read -r path; do
    echo "===== $path ====="
    ls -l "$path"
    sha256sum "$path" 2>/dev/null || true

    grep -nEi \
      "download|serverlist|commit_failed|slot_apply_failed|egress1|vpn1|rollback|strict|error|failed" \
      "$path" \
      2>/dev/null |
    tail -n 300 ||
    true
  done
'

block recent_recovery_artifacts sh -c '
  find /var/lib/router-egress-recovery \
    -maxdepth 5 \
    -type f \
    -mmin -1440 \
    2>/dev/null |
  sort |
  while IFS= read -r path; do
    echo "===== $path ====="
    ls -l "$path"
    sha256sum "$path" 2>/dev/null || true

    case "$path" in
      *.log|*.txt|*.json|*.status|*.kv)
        sed -n "1,500p" "$path" 2>/dev/null || true
        ;;
      *.sh)
        grep -nE \
          "egress1|vpn1|rollback|strict|endpoint|route|uci" \
          "$path" \
          2>/dev/null |
        head -n 300 ||
        true
        ;;
    esac
  done
'

echo "__TRACE__ stage=storage"

block filesystem_usage df -Pk

block relevant_sizes sh -c '
  du -sk \
    /root/hmn/cache \
    /root/hmn/configs/awg1 \
    /root/hmn/logs \
    /var/lib/router-egress-recovery \
    /tmp/step050m07* \
    2>/dev/null |
  sort -n
'

fact read_only true
fact refresh_ran false
fact rebalance_ran false
fact network_changed false
fact services_changed false
fact state_changed false
fact timer_changed false
fact plan_changed false
fact direct_failopen_changed false

echo "__TRACE__ stage=complete"
exit 0
