#!/bin/sh
set -eu
umask 077

CONF="/etc/router-egress-emergency-refresh.conf"
RUNNER="/usr/local/sbin/router-egress-emergency-refresh.sh"
HOOK="/usr/local/sbin/router-egress-emergency-decision-hook.sh"
PLANNER="/usr/local/sbin/router-egress-hmn-plan-top5.sh"
REFRESH="/root/hmn/hmn-refresh-pool-safe.sh"
APPLY="/usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh"
HELPER="/usr/local/lib/router-egress-recovery-state.sh"
POOL="/root/hmn/cache/ok-awg1-strict-foreign-latest.tsv"
STATE_DIR="/var/lib/router-egress-recovery"

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

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

block() {
  echo "__BLOCK_BEGIN__ $1"
  printf '%s\n' "$2"
  echo "__BLOCK_END__ $1"
}

json_block() {
  echo "__JSON_BEGIN__ $1"
  printf '%s\n' "$2"
  echo "__JSON_END__ $1"
}

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

config_bool() {
  name="$1"

  (
    . "$CONF"
    eval "value=\${$name:-false}"

    case "$value" in
      1|true|TRUE|yes|YES|on|ON)
        printf true
        ;;
      *)
        printf false
        ;;
    esac
  )
}

config_value() {
  name="$1"
  fallback="$2"

  (
    . "$CONF"
    eval "value=\${$name:-\$fallback}"
    printf '%s' "$value"
  )
}

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

endpoint_value() {
  interface="$1"

  wg show "$interface" endpoints 2>/dev/null |
    sed -n '
      1 {
        s/^[^	 ]*[	 ]*//
        p
      }
    '
}

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

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

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

  return 1
}

echo "__TRACE__ stage=required_files"

for path in \
  "$CONF" \
  "$RUNNER" \
  "$HOOK" \
  "$PLANNER" \
  "$REFRESH" \
  "$APPLY" \
  "$HELPER" \
  "$POOL" \
  "$HOOK_INIT" \
  "$WATCHER_INIT"
do
  [ -e "$path" ] || {
    echo "__ERROR__ missing=$path"
    exit 21
  }
done

echo "__TRACE__ stage=allowlisted_config"

fact emergency_commit_enabled "$(
  config_bool EMERGENCY_COMMIT_ENABLED
)"

fact direct_failopen_enabled "$(
  config_bool EMERGENCY_DIRECT_FAILOPEN_ENABLED
)"

fact daily_fail_threshold "$(
  config_value EMERGENCY_DAILY_FAIL_THRESHOLD UNSET
)"

fact refresh_cmd "$(
  config_value \
    EMERGENCY_REFRESH_CMD \
    /root/hmn/hmn-refresh-pool-safe.sh
)"

fact rebalance_apply_cmd "$(
  config_value \
    EMERGENCY_REBALANCE_APPLY_CMD \
    /usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh
)"

fact lock_dir "$(
  config_value \
    EMERGENCY_LOCK_DIR \
    /var/lock/router-egress-emergency-refresh.lock
)"

fact cooldown_seconds "$(
  config_value \
    EMERGENCY_COOLDOWN_SECONDS \
    UNSET
)"

echo "__TRACE__ stage=services_and_decisions"

fact repair_counter "$(repair_counter)"

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)"

RUNNER_JSON="$("$RUNNER" --dry-run)"
HOOK_JSON="$("$HOOK")"
PLANNER_JSON="$("$PLANNER")"

json_block runner "$RUNNER_JSON"
json_block hook "$HOOK_JSON"
json_block planner "$PLANNER_JSON"

echo "__TRACE__ stage=pool_state"

fact pool_rows "$(
  wc -l < "$POOL" |
    tr -d ' '
)"

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

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

STATE_FILES="$(
  find "$STATE_DIR" \
    -maxdepth 3 \
    -type f \
    2>/dev/null |
    sort ||
  true
)"

block recovery_state_files "$STATE_FILES"

STATE_METADATA=""

for path in $STATE_FILES; do
  size="$(
    wc -c < "$path" 2>/dev/null |
      tr -d ' ' ||
    echo UNKNOWN
  )"

  hash="$(
    sha256sum "$path" 2>/dev/null |
      sed 's/[[:space:]].*$//' ||
    echo UNKNOWN
  )"

  mtime="$(
    date -r "$path" +%s 2>/dev/null ||
    echo UNKNOWN
  )"

  STATE_METADATA="${STATE_METADATA}${path}	${size}	${hash}	${mtime}
"
done

block recovery_state_metadata "$STATE_METADATA"

echo "__TRACE__ stage=runtime_slots"

STRICT_ALL=true

for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  endpoint="$(endpoint_value "$interface")"

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

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

  if strict_ping "$interface"; then
    strict=true
  else
    strict=false
    STRICT_ALL=false
  fi

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

fact strict_all "$STRICT_ALL"

ROUTES_ALL=true

for table in 201 202 203 204 205; do
  if ip route show table "$table" 2>/dev/null |
    grep -q '^default '
  then
    route=true
  else
    route=false
    ROUTES_ALL=false
  fi

  fact "route.${table}" "$route"
done

fact routes_all "$ROUTES_ALL"

echo "__TRACE__ stage=process_and_lock_state"

PROCESSES="$(
  ps w 2>/dev/null |
    grep -E \
      'hmn-refresh-pool-safe|router-egress-hmn-rebalance-top5-apply|router-egress-emergency-refresh' |
    grep -v grep ||
  true
)"

block relevant_processes "$PROCESSES"

if [ -n "$PROCESSES" ]; then
  fact refresh_or_apply_process_seen true
else
  fact refresh_or_apply_process_seen false
fi

LOCK_DIR="$(
  config_value \
    EMERGENCY_LOCK_DIR \
    /var/lock/router-egress-emergency-refresh.lock
)"

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

echo "__TRACE__ stage=safety"

fact production_modified false
fact vm101_modified false
fact refresh_ran false
fact rebalance_apply_ran false
fact counter_changed false
fact watcher_invoked false
fact direct_failopen_changed false

echo "__TRACE__ stage=complete"
