#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

[ "$(id -un)" = "ops" ] || {
  echo "STOP: запускать на router-ops пользователем ops"
  exit 1
}

STEP="STEP_050M07C2_FRESH_HMN_REFRESH_LIVE_STREAM"
PASS_DECISION="PASS_${STEP}"
PLAN_ID="vm101-hmn-autonomous-egress-recovery"

TOKEN="e94a0859747d7b96f29c7fdafc2d0351ba603bb0a7e9e5a4"
PUBLIC_BASE="https://helena-background-beam-harry.trycloudflare.com/r/${TOKEN}"

PREVIOUS_ARCHITECTURE_PLAN="${PUBLIC_BASE}/20260711-181158_local_architecture_plan_vm101_autonomous_hmn_recovery/"
XS_MAP="${PUBLIC_BASE}/20260711-120734_xs_map_audit_repair_publish/"
GLOBAL_PROJECT_PLAN="${PUBLIC_BASE}/20260711-123348_global_project_plan_wg_paid/"

ROOT="/opt/router-ops"
STATE_ROOT="${ROOT}/state"
PUBROOT="${ROOT}/public/r/${TOKEN}"
PLAN_STATE_DIR="${STATE_ROOT}/local-plans/${PLAN_ID}"

M07B2_DIR="${PUBROOT}/20260711-191741_step050m07b2_normalize_commit_and_run_full_refresh"
M06A_DIR="${PUBROOT}/20260711-173308_step050m06a_compare_live_toolchain_to_frozen_map"

STATUS_TOOL="${ROOT}/bin/vm101-local-plan-status"
REPUBLISH_TOOL="${ROOT}/bin/vm101-local-plan-republish"

TS="$(date -u +%Y%m%d-%H%M%S)"
REPORT_SLUG="${TS}_step050m07c2_fresh_hmn_refresh_live_stream"
REPORT_DIR="${PUBROOT}/${REPORT_SLUG}"

TRYCF_REPORT="${PUBLIC_BASE}/${REPORT_SLUG}/"
REPORT_TXT="${TRYCF_REPORT}report.txt"
FACTS_JSON="${TRYCF_REPORT}facts.json"
ARCHITECTURE_PLAN="$PREVIOUS_ARCHITECTURE_PLAN"

mkdir -p \
  "$REPORT_DIR" \
  "$REPORT_DIR/sources"

# Сохраняем точный верхнеуровневый STEP до любых проверок.
cp -a "$0" "$REPORT_DIR/step.sh"
chmod 600 "$REPORT_DIR/step.sh"

PROGRESS_LOG="$REPORT_DIR/progress.log"
: > "$PROGRESS_LOG"

CURRENT_STAGE="initialization"
LAST_SUCCESS="step_saved"

HASH_CHECK_RC="NOT_RUN"
PRECHECK_RC="NOT_RUN"
VM101_RC="NOT_RUN"
POSTCHECK_RC="NOT_RUN"
ROLLBACK_RC="NOT_NEEDED"
PLAN_RESTORE_RC="NOT_NEEDED"

VM101_CHANGED=false
VM101_ROLLBACK=""
PRODUCTION_MODIFIED=false
PLAN_UPDATED=false

stage() {
  CURRENT_STAGE="$1"

  echo
  echo ">>> [$1] $2" | tee -a "$PROGRESS_LOG"

  date -u '+    utc=%Y-%m-%dT%H:%M:%SZ' |
    tee -a "$PROGRESS_LOG"
}

mark_success() {
  LAST_SUCCESS="$1"
  echo "last_success=$LAST_SUCCESS" >> "$PROGRESS_LOG"
}

print_links() {
  echo
  echo "TRYCF_REPORT=$TRYCF_REPORT"
  echo "REPORT_TXT=$REPORT_TXT"
  echo "FACTS_JSON=$FACTS_JSON"
  echo "ARCHITECTURE_PLAN=$ARCHITECTURE_PLAN"
  echo "XS_MAP=$XS_MAP"
  echo "GLOBAL_PROJECT_PLAN=$GLOBAL_PROJECT_PLAN"
}

remote_vm101() {
  ssh pve-mgts \
    "ssh \
      -o BatchMode=yes \
      -o ConnectTimeout=8 \
      -o StrictHostKeyChecking=no \
      -o UserKnownHostsFile=/dev/null \
      -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
      root@10.71.100.2 \
      '$1'"
}

rollback_vm101() {
  if [ "$VM101_CHANGED" != true ]; then
    ROLLBACK_RC="NOT_NEEDED"
    return 0
  fi

  if [ -z "$VM101_ROLLBACK" ]; then
    ROLLBACK_RC="ROLLBACK_PATH_MISSING"
    PRODUCTION_MODIFIED=unknown
    return 1
  fi

  set +e

  remote_vm101 "sh '$VM101_ROLLBACK'" \
    > >(tee "$REPORT_DIR/vm101-rollback.txt") \
    2> >(tee "$REPORT_DIR/vm101-rollback.stderr" >&2)

  ROLLBACK_RC=$?

  set -e

  if [ "$ROLLBACK_RC" -eq 0 ]; then
    VM101_CHANGED=false
    PRODUCTION_MODIFIED=false
    return 0
  fi

  PRODUCTION_MODIFIED=unknown
  return "$ROLLBACK_RC"
}

restore_plan_state() {
  if [ "$PLAN_UPDATED" != true ]; then
    PLAN_RESTORE_RC="NOT_NEEDED"
    return 0
  fi

  set +e

  "$STATUS_TOOL" \
    M08 pending \
    --note "Ожидает успешного завершения M07 после rollback." \
    > "$REPORT_DIR/plan-restore-m08.txt" \
    2> "$REPORT_DIR/plan-restore-m08.stderr"
  rc_m08=$?

  "$STATUS_TOOL" \
    M07 in_progress \
    --note "Результат M07 откачен; этап снова выполняется." \
    > "$REPORT_DIR/plan-restore-m07.txt" \
    2> "$REPORT_DIR/plan-restore-m07.stderr"
  rc_m07=$?

  restore_output="$(
    "$REPUBLISH_TOOL" \
      "ROLLBACK_${STEP}" \
      "$TRYCF_REPORT" \
      2> "$REPORT_DIR/plan-restore-republish.stderr"
  )"
  rc_publish=$?

  set -e

  restored_plan="$(
    printf '%s\n' "$restore_output" |
      sed -n 's/^ARCHITECTURE_PLAN=//p' |
      tail -n1
  )"

  [ -z "$restored_plan" ] ||
    ARCHITECTURE_PLAN="$restored_plan"

  if [ "$rc_m08" -eq 0 ] &&
     [ "$rc_m07" -eq 0 ] &&
     [ "$rc_publish" -eq 0 ]
  then
    PLAN_UPDATED=false
    PLAN_RESTORE_RC=0
    return 0
  fi

  PLAN_RESTORE_RC="M08:${rc_m08},M07:${rc_m07},PUBLISH:${rc_publish}"
  return 1
}

write_stop() {
  local reason="$1"
  local rc="$2"
  local line="$3"

  python3 - \
    "$REPORT_DIR" \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$HASH_CHECK_RC" \
    "$PRECHECK_RC" \
    "$VM101_RC" \
    "$POSTCHECK_RC" \
    "$ROLLBACK_RC" \
    "$PLAN_RESTORE_RC" \
    "$PRODUCTION_MODIFIED" \
    > "$REPORT_DIR/diagnostic.json" <<'PY'
import json
import sys
from pathlib import Path

(
    report_dir,
    step,
    reason,
    rc,
    line,
    stage,
    last_success,
    hash_rc,
    precheck_rc,
    vm101_rc,
    postcheck_rc,
    rollback_rc,
    plan_restore_rc,
    modified,
) = sys.argv[1:]

root = Path(report_dir)


def read_tail(path: Path, limit: int = 60000):
    if not path.exists() or not path.is_file():
        return None

    return path.read_text(
        encoding="utf-8",
        errors="replace",
    )[-limit:]


streams = {}

for pattern in ("*.txt", "*.stderr", "*.log"):
    for path in sorted(root.glob(pattern)):
        if path.name in {"report.txt", "progress.log"}:
            continue

        streams[path.name] = {
            "size_bytes": path.stat().st_size,
            "tail": read_tail(path),
        }

combined = "\n".join(
    item["tail"] or ""
    for item in streams.values()
)

if "code_test_rc=" in combined and "code_test_rc=0" not in combined:
    classification = "HMN_CODE_TEST_FAILED"
elif "fresh_download_failed_old_pool_fallback" in combined:
    classification = "FRESH_DOWNLOAD_FAILED_OLD_POOL_FALLBACK"
elif "fresh_download_not_proven" in combined:
    classification = "FRESH_DOWNLOAD_NOT_PROVEN"
elif "runner_timeout" in combined:
    classification = "HMN_REFRESH_TIMEOUT"
elif "runner_decision_not_success" in combined:
    classification = "RUNNER_DECISION_NOT_SUCCESS"
elif "cooldown_not_active" in combined:
    classification = "SUCCESS_STATE_OR_COOLDOWN_NOT_WRITTEN"
elif "planner_not_converged" in combined:
    classification = "POST_REFRESH_PLANNER_NOT_CONVERGED"
elif rollback_rc not in {"NOT_NEEDED", "0", "REMOTE_AUTO_ROLLBACK_OK"}:
    classification = "ROLLBACK_VALIDATION_FAILED"
elif vm101_rc not in {"NOT_RUN", "0"}:
    classification = "VM101_CONTROLLED_REFRESH_FAILED"
elif postcheck_rc not in {"NOT_RUN", "0"}:
    classification = "PERSISTED_POSTCHECK_FAILED"
else:
    classification = "LOCAL_VALIDATION_OR_PLAN_UPDATE_FAILURE"

print(json.dumps({
    "schema": "router-step-inline-diagnostic-v6",
    "step": step,
    "failure": {
        "reason": reason,
        "rc": int(rc),
        "line": int(line),
        "stage": stage,
        "last_success": last_success,
    },
    "command_results": {
        "hash_check_rc": hash_rc,
        "precheck_rc": precheck_rc,
        "vm101_rc": vm101_rc,
        "postcheck_rc": postcheck_rc,
        "rollback_rc": rollback_rc,
        "plan_restore_rc": plan_restore_rc,
    },
    "automatic_classification": classification,
    "production_modified_after_rollback": modified,
    "live_streaming": {
        "runner_stdout": True,
        "runner_stderr": True,
        "emergency_log": True,
        "heartbeat_seconds": 15,
    },
    "captured_streams": streams,
    "recommended_next_step": (
        "Использовать automatic_classification и уже сохранённые "
        "live stdout/stderr. Отдельный диагностический STEP не требуется."
    ),
}, ensure_ascii=False, indent=2))
PY

  cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=STOP_${STEP}_${reason}
all_ok=false
mode=M07_FRESH_HMN_REFRESH_LIVE_STREAM
error_rc=${rc}
error_line=${line}
failed_stage=${CURRENT_STAGE}
last_success=${LAST_SUCCESS}

command_results:
  hash_check_rc=${HASH_CHECK_RC}
  precheck_rc=${PRECHECK_RC}
  vm101_rc=${VM101_RC}
  postcheck_rc=${POSTCHECK_RC}
  rollback_rc=${ROLLBACK_RC}
  plan_restore_rc=${PLAN_RESTORE_RC}

live_streaming:
  runner_stdout=true
  runner_stderr=true
  emergency_log=true
  heartbeat_seconds=15

safety:
  production_modified=${PRODUCTION_MODIFIED}
  rollback_vm101=${VM101_ROLLBACK:-UNAVAILABLE}
  direct_failopen_changed=false

inline_diagnostics:
  enabled=true
  diagnostic=diagnostic.json
  stdout_and_stderr_captured=true
  automatic_classification_present=true
  rollback_on_stop=true
  separate_diagnostic_step_required=false

plan:
  current_milestone=M07
  milestone_completed=false

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
EOF

  python3 - \
    "$REPORT_DIR/diagnostic.json" \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$PRODUCTION_MODIFIED" \
    "$VM101_ROLLBACK" \
    "$TRYCF_REPORT" \
    "$REPORT_TXT" \
    "$FACTS_JSON" \
    "$ARCHITECTURE_PLAN" \
    "$XS_MAP" \
    "$GLOBAL_PROJECT_PLAN" \
    > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    diagnostic_path,
    step,
    reason,
    rc,
    line,
    stage,
    last_success,
    modified,
    rollback,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

with open(diagnostic_path, encoding="utf-8") as source:
    diagnostic = json.load(source)

production_modified = {
    "true": True,
    "false": False,
}.get(modified, "unknown")

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "assessment": {
        "decision": f"STOP_{step}_{reason}",
        "all_ok": False,
        "error_rc": int(rc),
        "error_line": int(line),
        "failed_stage": stage,
        "last_success": last_success,
    },
    "inline_diagnostic": diagnostic,
    "safety": {
        "production_modified": production_modified,
        "rollback_vm101": rollback or None,
        "direct_failopen_changed": False,
    },
    "plan": {
        "current_milestone": "M07",
        "milestone_completed": False,
    },
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
    },
}, ensure_ascii=False, indent=2))
PY

  cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head><meta charset="utf-8"><title>${STEP}</title></head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto">
<h1>${STEP}</h1>
<ul>
<li><a href="step.sh">step.sh</a></li>
<li><a href="vm101-tool-hash-check.sh">vm101-tool-hash-check.sh</a></li>
<li><a href="vm101-precheck.sh">vm101-precheck.sh</a></li>
<li><a href="vm101-precheck.txt">vm101-precheck.txt</a></li>
<li><a href="vm101.sh">vm101.sh</a></li>
<li><a href="vm101.txt">vm101.txt — live stream</a></li>
<li><a href="vm101.stderr">vm101.stderr — live stderr</a></li>
<li><a href="vm101-postcheck.sh">vm101-postcheck.sh</a></li>
<li><a href="vm101-postcheck.txt">vm101-postcheck.txt</a></li>
<li><a href="vm101-rollback.txt">vm101-rollback.txt</a></li>
<li><a href="diagnostic.json">diagnostic.json</a></li>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
</ul>
</body>
</html>
EOF

  find "$REPORT_DIR" \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
    sort -z |
    xargs -0 sha256sum \
    > "$REPORT_DIR/SHA256SUMS"
}

fatal() {
  local reason="$1"
  local rc="${2:-1}"
  local line="${3:-$LINENO}"

  trap - ERR

  rollback_vm101 || true
  restore_plan_state || true
  write_stop "$reason" "$rc" "$line"

  print_links
  exit "$rc"
}

on_error() {
  local rc="$?"
  local line="$1"

  fatal "UNEXPECTED_ERROR" "$rc" "$line"
}

trap 'on_error "$LINENO"' ERR

stage "01/09" "Проверяю M07B2 и текущую точку M07"

for required in \
  "$M07B2_DIR/report.txt" \
  "$M07B2_DIR/facts.json" \
  "$M07B2_DIR/diagnostic.json" \
  "$M07B2_DIR/vm101.txt" \
  "$M07B2_DIR/progress.log" \
  "$M07B2_DIR/step.sh" \
  "$M06A_DIR/vm101.sh" \
  "$STATUS_TOOL" \
  "$REPUBLISH_TOOL" \
  "$PLAN_STATE_DIR/milestones.json" \
  "$STATE_ROOT/current-local-architecture-plan-url.txt"
do
  [ -s "$required" ] || {
    echo "MISSING_REQUIRED=$required"
    fatal "REQUIRED_ARTIFACT_MISSING" 2 "$LINENO"
  }
done

grep -Fq "vm101_rc=34" \
  "$M07B2_DIR/progress.log" ||
  fatal "PREVIOUS_RC34_NOT_PROVEN" 3 "$LINENO"

grep -Fq "pool_source=old-after-download-fail" \
  "$M07B2_DIR/vm101.txt" ||
  fatal "OLD_POOL_FALLBACK_NOT_PROVEN" 4 "$LINENO"

grep -Fq '"decision": "commit_ok"' \
  "$M07B2_DIR/vm101.txt" ||
  fatal "PREVIOUS_REBALANCE_SUCCESS_NOT_PROVEN" 5 "$LINENO"

CURRENT_PLAN="$(
  tr -d '\r\n' \
    < "$STATE_ROOT/current-local-architecture-plan-url.txt"
)"

[ "$CURRENT_PLAN" = "$PREVIOUS_ARCHITECTURE_PLAN" ] ||
  fatal "CURRENT_PLAN_POINTER_MISMATCH" 6 "$LINENO"

python3 - "$PLAN_STATE_DIR/milestones.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

items = {
    item["id"]: item
    for item in data["milestones"]
}

assert data["current_milestone"] == "M07"
assert items["M06"]["status"] == "done"
assert items["M07"]["status"] == "in_progress"
assert items["M08"]["status"] == "pending"
PY

cp -a \
  "$M07B2_DIR/diagnostic.json" \
  "$REPORT_DIR/sources/step050m07b2-diagnostic.json"

cp -a \
  "$M07B2_DIR/vm101.txt" \
  "$REPORT_DIR/sources/step050m07b2-vm101.txt"

cp -a \
  "$M07B2_DIR/step.sh" \
  "$REPORT_DIR/sources/step050m07b2-step.sh"

mark_success "previous_failure_and_plan_verified"

stage "02/09" "Публикую все точные remote scripts до запуска"

cp -a \
  "$M06A_DIR/vm101.sh" \
  "$REPORT_DIR/vm101-tool-hash-check.sh"

cat > "$REPORT_DIR/vm101-precheck.sh" <<'VM101PRE'
#!/bin/sh
set -u
umask 077

CONF="/etc/router-egress-emergency-refresh.conf"
RUNNER="/usr/local/sbin/router-egress-emergency-refresh.sh"
PLANNER="/usr/local/sbin/router-egress-hmn-plan-top5.sh"
CODE_TEST="/root/hmn/hmn-code-test.sh"

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

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
}

for required in \
  "$CONF" \
  "$RUNNER" \
  "$PLANNER" \
  "$CODE_TEST"
do
  [ -e "$required" ] || {
    echo "__ERROR__ missing=$required"
    exit 21
  }
done

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

fact commit_raw "$RAW"
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
)"

STRICT_ALL=true

for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  if ping -I "$interface" -c 1 -W 3 1.1.1.1 >/dev/null 2>&1; then
    value=true
  else
    value=false
    STRICT_ALL=false
  fi

  fact "strict.${interface}" "$value"
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
    value=true
  else
    value=false
    ROUTES_ALL=false
  fi

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

fact routes_all "$ROUTES_ALL"

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

json_block runner "$RUNNER_JSON"
json_block planner "$PLANNER_JSON"

CODE_RAW="/tmp/step050m07c2-code-test.$$.raw"

set +e
"$CODE_TEST" > "$CODE_RAW" 2>&1
CODE_RC=$?
set -e

fact code_test_rc "$CODE_RC"
fact code_test_size "$(
  wc -c < "$CODE_RAW" |
    tr -d ' '
)"

CODE_SUMMARY="$(
  grep -Ei \
    'pass|success|valid|invalid|fail|error|http|serverlist|download' \
    "$CODE_RAW" |
    tail -n 50 ||
  true
)"

rm -f "$CODE_RAW"

echo "__BLOCK_BEGIN__ code_test_sanitized_summary"
printf '%s\n' "$CODE_SUMMARY" |
  sed \
    -e 's/[Cc][Oo][Dd][Ee]=[^ ]*/code=REDACTED/g' \
    -e 's/[Tt][Oo][Kk][Ee][Nn]=[^ ]*/token=REDACTED/g' \
    -e 's/[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd]=[^ ]*/password=REDACTED/g'
echo "__BLOCK_END__ code_test_sanitized_summary"

fact production_modified false

[ "$RAW" = "1" ]
[ "$CODE_RC" -eq 0 ]
[ "$STRICT_ALL" = true ]
[ "$ROUTES_ALL" = true ]
VM101PRE

cat > "$REPORT_DIR/vm101.sh" <<'VM101'
#!/bin/sh
set -u
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"
HELPER="/usr/local/lib/router-egress-recovery-state.sh"

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

CACHE_DIR="/root/hmn/cache"
POOL="${CACHE_DIR}/ok-awg1-strict-foreign-latest.tsv"
STATE_DIR="/var/lib/router-egress-recovery"

RUN_ID="$(date -u +%Y%m%d-%H%M%S)-$$"
BACKUP_ROOT="/root/step050m07c2-backup-${RUN_ID}"
ROLLBACK="/root/rollback-step050m07c2-${RUN_ID}.sh"

RUNNER_OUT="/tmp/step050m07c2-runner-${RUN_ID}.out"
RUNNER_ERR="/tmp/step050m07c2-runner-${RUN_ID}.err"
LOG_DELTA="/tmp/step050m07c2-log-${RUN_ID}.delta"

ROLLBACK_READY=false
ROLLBACK_DONE=false

HOOK_WAS_RUNNING=false
WATCHER_WAS_RUNNING=false

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

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

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

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_all() {
  for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
    ping -I "$interface" -c 1 -W 3 1.1.1.1 \
      >/dev/null 2>&1 ||
      return 1
  done

  return 0
}

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

  return 0
}

restore_services() {
  [ "$HOOK_WAS_RUNNING" != true ] ||
    "$HOOK_INIT" start >/dev/null 2>&1 ||
    true

  [ "$WATCHER_WAS_RUNNING" != true ] ||
    "$WATCHER_INIT" start >/dev/null 2>&1 ||
    true
}

stream_delta() {
  file="$1"
  old_offset="$2"
  destination="$3"
  label="$4"

  if [ -f "$file" ]; then
    current_size="$(
      wc -c < "$file" 2>/dev/null |
        tr -d ' ' ||
      echo 0
    )"
  else
    current_size=0
  fi

  case "$current_size" in
    ''|*[!0-9]*)
      current_size=0
      ;;
  esac

  if [ "$current_size" -gt "$old_offset" ]; then
    count=$((current_size - old_offset))

    if [ "$destination" = stderr ]; then
      echo "__LIVE_CHUNK__ source=${label} bytes=${count}" >&2

      dd \
        if="$file" \
        bs=1 \
        skip="$old_offset" \
        count="$count" \
        2>/dev/null >&2
    else
      echo "__LIVE_CHUNK__ source=${label} bytes=${count}"

      dd \
        if="$file" \
        bs=1 \
        skip="$old_offset" \
        count="$count" \
        2>/dev/null
    fi
  fi

  printf '%s' "$current_size"
}

detect_stage() {
  log="$1"

  if [ ! -f "$log" ]; then
    echo "runner_starting"
    return
  fi

  tail_text="$(
    tail -n 120 "$log" 2>/dev/null ||
    true
  )"

  if printf '%s\n' "$tail_text" |
    grep -q '=== hmn-refresh-pool-safe done ==='
  then
    echo "refresh_finished_rebalance_running"

  elif printf '%s\n' "$tail_text" |
    grep -q '=== run manager once after validation ==='
  then
    echo "manager_after_validation"

  elif printf '%s\n' "$tail_text" |
    grep -q '=== done validate-current-pool ==='
  then
    echo "pool_validation_completed"

  elif printf '%s\n' "$tail_text" |
    grep -q 'strict foreign head'
  then
    echo "strict_foreign_pool_validation"

  elif printf '%s\n' "$tail_text" |
    grep -Eq 'download|serverlist|fresh_download'
  then
    echo "provider_download"

  elif printf '%s\n' "$tail_text" |
    grep -Eq 'validate|testing|strict'
  then
    echo "tunnel_validation"

  else
    echo "hmn_refresh_running"
  fi
}

auto_rollback() {
  rc="$?"
  trap - EXIT

  if [ "$rc" -ne 0 ] &&
     [ "$ROLLBACK_READY" = true ] &&
     [ "$ROLLBACK_DONE" != true ]
  then
    if sh "$ROLLBACK"; then
      ROLLBACK_DONE=true
      fact auto_rollback true
    else
      fact auto_rollback false
    fi
  elif [ "$rc" -ne 0 ]; then
    restore_services
  fi

  rm -f \
    "$RUNNER_OUT" \
    "$RUNNER_ERR" \
    "$LOG_DELTA"

  exit "$rc"
}

trap auto_rollback EXIT

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

for command_name in \
  sh \
  awk \
  sed \
  grep \
  find \
  sort \
  cp \
  mv \
  rm \
  mkdir \
  date \
  wc \
  sha256sum \
  dd \
  tail \
  kill \
  uci \
  wg \
  ip \
  ping
do
  command -v "$command_name" >/dev/null 2>&1 || {
    echo "__ERROR__ command_missing=$command_name"
    exit 22
  }
done

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

CONFIRM_TOKEN="$(
  (
    . "$CONF"
    printf '%s' "${EMERGENCY_CONFIRM_TOKEN:-}"
  )
)"

EMERGENCY_LOG="$(
  (
    . "$CONF"
    printf '%s' "${EMERGENCY_LOG:-/var/log/router-egress-emergency-refresh.log}"
  )
)"

fact commit_raw_pre "$RAW_PRE"
fact emergency_log "$EMERGENCY_LOG"

[ "$RAW_PRE" = "1" ] || {
  echo "__ERROR__ expected_commit_raw_1_actual=$RAW_PRE"
  exit 23
}

[ -n "$CONFIRM_TOKEN" ] || {
  echo "__ERROR__ confirm_token_empty"
  exit 24
}

RUNNER_PRE="$("$RUNNER" --dry-run)"
PLANNER_PRE="$("$PLANNER")"

COUNTER_PRE="$(repair_counter)"

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

NETWORK_FILE_HASH_PRE="$(
  sha256sum /etc/config/network |
    sed 's/[[:space:]].*$//'
)"

json_block runner_pre "$RUNNER_PRE"
json_block planner_pre "$PLANNER_PRE"

fact repair_counter_pre "$COUNTER_PRE"
fact pool_hash_pre "$POOL_HASH_PRE"
fact network_file_hash_pre "$NETWORK_FILE_HASH_PRE"

mkdir -p "$BACKUP_ROOT"

cp -a "$CONF" "$BACKUP_ROOT/config.before"
cp -a "$CACHE_DIR" "$BACKUP_ROOT/cache.before"
cp -a "$STATE_DIR" "$BACKUP_ROOT/state.before"
cp -a /etc/config/network "$BACKUP_ROOT/network.before"

find "$STATE_DIR" \
  -maxdepth 4 \
  -type f \
  -name 'rollback-egress*.sh' \
  2>/dev/null |
  sort \
  > "$BACKUP_ROOT/slot-rollbacks.before"

HOOK_WAS_RUNNING="$(bool_cmd "$HOOK_INIT" running)"
WATCHER_WAS_RUNNING="$(bool_cmd "$WATCHER_INIT" running)"

fact hook_was_running "$HOOK_WAS_RUNNING"
fact watcher_was_running "$WATCHER_WAS_RUNNING"

cat > "$ROLLBACK" <<EOF
#!/bin/sh
set -u
umask 077

CONF='$CONF'
CACHE_DIR='$CACHE_DIR'
STATE_DIR='$STATE_DIR'
BACKUP_ROOT='$BACKUP_ROOT'

HOOK_INIT='$HOOK_INIT'
WATCHER_INIT='$WATCHER_INIT'
SLOTS_INIT='$SLOTS_INIT'
MAPPER_INIT='$MAPPER_INIT'

HOOK_WAS_RUNNING='$HOOK_WAS_RUNNING'
WATCHER_WAS_RUNNING='$WATCHER_WAS_RUNNING'

command_errors=0

"\$HOOK_INIT" stop >/dev/null 2>&1 || true
"\$WATCHER_INIT" stop >/dev/null 2>&1 || true

find "\$STATE_DIR" \
  -maxdepth 4 \
  -type f \
  -name 'rollback-egress*.sh' \
  2>/dev/null |
  sort -r \
  > "\$BACKUP_ROOT/slot-rollbacks.after"

while IFS= read -r rollback_path; do
  [ -n "\$rollback_path" ] || continue

  if ! grep -Fxq \
    "\$rollback_path" \
    "\$BACKUP_ROOT/slot-rollbacks.before"
  then
    sh "\$rollback_path" ||
      command_errors=\$((command_errors + 1))
  fi
done < "\$BACKUP_ROOT/slot-rollbacks.after"

cp -a "\$BACKUP_ROOT/config.before" "\$CONF" ||
  command_errors=\$((command_errors + 1))

rm -rf "\$CACHE_DIR"
cp -a "\$BACKUP_ROOT/cache.before" "\$CACHE_DIR" ||
  command_errors=\$((command_errors + 1))

rm -rf "\$STATE_DIR"
cp -a "\$BACKUP_ROOT/state.before" "\$STATE_DIR" ||
  command_errors=\$((command_errors + 1))

cp -a \
  "\$BACKUP_ROOT/network.before" \
  /etc/config/network ||
  command_errors=\$((command_errors + 1))

rm -rf \
  /var/lock/router-egress-emergency-refresh.lock \
  /tmp/hmn-refresh-pool-safe.lock \
  2>/dev/null ||
  true

/etc/init.d/network reload >/dev/null 2>&1 ||
  command_errors=\$((command_errors + 1))

sleep 8

[ ! -x "\$SLOTS_INIT" ] ||
  "\$SLOTS_INIT" restart >/dev/null 2>&1 ||
  command_errors=\$((command_errors + 1))

[ ! -x "\$MAPPER_INIT" ] ||
  "\$MAPPER_INIT" restart >/dev/null 2>&1 ||
  command_errors=\$((command_errors + 1))

if [ "\$HOOK_WAS_RUNNING" = true ]; then
  "\$HOOK_INIT" start >/dev/null 2>&1 ||
    command_errors=\$((command_errors + 1))
fi

if [ "\$WATCHER_WAS_RUNNING" = true ]; then
  "\$WATCHER_INIT" start >/dev/null 2>&1 ||
    command_errors=\$((command_errors + 1))
fi

config_expected="\$(
  sha256sum "\$BACKUP_ROOT/config.before" |
    sed 's/[[:space:]].*\$//'
)"

config_live="\$(
  sha256sum "\$CONF" |
    sed 's/[[:space:]].*\$//'
)"

pool_expected="\$(
  sha256sum \
    "\$BACKUP_ROOT/cache.before/ok-awg1-strict-foreign-latest.tsv" |
    sed 's/[[:space:]].*\$//'
)"

pool_live="\$(
  sha256sum \
    "\$CACHE_DIR/ok-awg1-strict-foreign-latest.tsv" |
    sed 's/[[:space:]].*\$//'
)"

network_expected="\$(
  sha256sum "\$BACKUP_ROOT/network.before" |
    sed 's/[[:space:]].*\$//'
)"

network_live="\$(
  sha256sum /etc/config/network |
    sed 's/[[:space:]].*\$//'
)"

strict=true

for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  ping -I "\$interface" -c 1 -W 3 1.1.1.1 \
    >/dev/null 2>&1 ||
    strict=false
done

routes=true

for table in 201 202 203 204 205; do
  ip route show table "\$table" |
    grep -q '^default ' ||
    routes=false
done

hook_restored=true
watcher_restored=true

if [ "\$HOOK_WAS_RUNNING" = true ]; then
  "\$HOOK_INIT" running >/dev/null 2>&1 ||
    hook_restored=false
fi

if [ "\$WATCHER_WAS_RUNNING" = true ]; then
  "\$WATCHER_INIT" running >/dev/null 2>&1 ||
    watcher_restored=false
fi

config_match=false
pool_match=false
network_match=false

[ "\$config_expected" = "\$config_live" ] &&
  config_match=true

[ "\$pool_expected" = "\$pool_live" ] &&
  pool_match=true

[ "\$network_expected" = "\$network_live" ] &&
  network_match=true

echo "rollback_command_errors=\$command_errors"
echo "rollback_config_match=\$config_match"
echo "rollback_pool_match=\$pool_match"
echo "rollback_network_match=\$network_match"
echo "rollback_strict_all=\$strict"
echo "rollback_routes_all=\$routes"
echo "rollback_hook_restored=\$hook_restored"
echo "rollback_watcher_restored=\$watcher_restored"

if [ "\$config_match" = true ] &&
   [ "\$pool_match" = true ] &&
   [ "\$network_match" = true ] &&
   [ "\$strict" = true ] &&
   [ "\$routes" = true ] &&
   [ "\$hook_restored" = true ] &&
   [ "\$watcher_restored" = true ]
then
  echo "rollback_validated=true"
  exit 0
fi

echo "rollback_validated=false"
exit 1
EOF

chmod 700 "$ROLLBACK"
ROLLBACK_READY=true

fact rollback "$ROLLBACK"
fact rollback_exists "$(bool_cmd test -x "$ROLLBACK")"
fact backup_root "$BACKUP_ROOT"

"$WATCHER_INIT" stop >/dev/null 2>&1 || true
"$HOOK_INIT" stop >/dev/null 2>&1 || true

sleep 2

fact watcher_stopped "$(
  if "$WATCHER_INIT" running >/dev/null 2>&1; then
    echo false
  else
    echo true
  fi
)"

fact hook_stopped "$(
  if "$HOOK_INIT" running >/dev/null 2>&1; then
    echo false
  else
    echo true
  fi
)"

TEMP="${CONF}.step050m07c2.$$.tmp"

awk '
  BEGIN {
    count=0
  }

  /^[[:space:]]*EMERGENCY_COMMIT_ENABLED[[:space:]]*=/ {
    print "EMERGENCY_COMMIT_ENABLED=true"
    count++
    next
  }

  {
    print
  }

  END {
    if (count != 1) {
      exit 42
    }
  }
' "$CONF" > "$TEMP" || {
  rm -f "$TEMP"
  echo "__ERROR__ commit_boolean_patch_failed"
  exit 25
}

chmod 600 "$TEMP"
chown 0:0 "$TEMP"
mv "$TEMP" "$CONF"

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

LOG_SIZE_PRE="$(
  if [ -f "$EMERGENCY_LOG" ]; then
    wc -c < "$EMERGENCY_LOG" |
      tr -d ' '
  else
    echo 0
  fi
)"

fact emergency_log_size_pre "$LOG_SIZE_PRE"

: > "$RUNNER_OUT"
: > "$RUNNER_ERR"
: > "$LOG_DELTA"

"$RUNNER" \
  --commit \
  --confirm "$CONFIRM_TOKEN" \
  > "$RUNNER_OUT" \
  2> "$RUNNER_ERR" &

RUNNER_PID=$!

START_EPOCH="$(date +%s)"
LAST_HEARTBEAT=0

OUT_OFFSET=0
ERR_OFFSET=0
LOG_OFFSET="$LOG_SIZE_PRE"

echo
echo "=== LIVE HMN REFRESH START ==="
echo "__HEARTBEAT__ stage=runner_starting elapsed=0s runner_pid=$RUNNER_PID"
echo

while kill -0 "$RUNNER_PID" >/dev/null 2>&1; do
  new_offset="$(
    stream_delta \
      "$RUNNER_OUT" \
      "$OUT_OFFSET" \
      stdout \
      runner_stdout
  )"
  OUT_OFFSET="$new_offset"

  new_offset="$(
    stream_delta \
      "$RUNNER_ERR" \
      "$ERR_OFFSET" \
      stderr \
      runner_stderr
  )"
  ERR_OFFSET="$new_offset"

  new_offset="$(
    stream_delta \
      "$EMERGENCY_LOG" \
      "$LOG_OFFSET" \
      stdout \
      emergency_log
  )"

  if [ "$new_offset" -gt "$LOG_OFFSET" ]; then
    count=$((new_offset - LOG_OFFSET))

    dd \
      if="$EMERGENCY_LOG" \
      bs=1 \
      skip="$LOG_OFFSET" \
      count="$count" \
      2>/dev/null \
      >> "$LOG_DELTA"
  fi

  LOG_OFFSET="$new_offset"

  NOW_EPOCH="$(date +%s)"
  ELAPSED=$((NOW_EPOCH - START_EPOCH))

  if [ $((ELAPSED - LAST_HEARTBEAT)) -ge 15 ]; then
    CURRENT_REFRESH_STAGE="$(detect_stage "$EMERGENCY_LOG")"

    echo
    echo "__HEARTBEAT__ stage=${CURRENT_REFRESH_STAGE} elapsed=${ELAPSED}s runner_pid=${RUNNER_PID}"
    echo

    LAST_HEARTBEAT="$ELAPSED"
  fi

  if [ "$ELAPSED" -ge 1800 ]; then
    echo "__ERROR__ runner_timeout_after=${ELAPSED}s"

    kill "$RUNNER_PID" >/dev/null 2>&1 || true
    sleep 2
    kill -9 "$RUNNER_PID" >/dev/null 2>&1 || true
    wait "$RUNNER_PID" >/dev/null 2>&1 || true

    exit 30
  fi

  sleep 2
done

set +e
wait "$RUNNER_PID"
RUNNER_RC=$?
set -e

OUT_OFFSET="$(
  stream_delta \
    "$RUNNER_OUT" \
    "$OUT_OFFSET" \
    stdout \
    runner_stdout_final
)"

ERR_OFFSET="$(
  stream_delta \
    "$RUNNER_ERR" \
    "$ERR_OFFSET" \
    stderr \
    runner_stderr_final
)"

FINAL_LOG_OFFSET="$(
  stream_delta \
    "$EMERGENCY_LOG" \
    "$LOG_OFFSET" \
    stdout \
    emergency_log_final
)"

if [ "$FINAL_LOG_OFFSET" -gt "$LOG_OFFSET" ]; then
  count=$((FINAL_LOG_OFFSET - LOG_OFFSET))

  dd \
    if="$EMERGENCY_LOG" \
    bs=1 \
    skip="$LOG_OFFSET" \
    count="$count" \
    2>/dev/null \
    >> "$LOG_DELTA"
fi

LOG_OFFSET="$FINAL_LOG_OFFSET"

FINISH_EPOCH="$(date +%s)"
TOTAL_ELAPSED=$((FINISH_EPOCH - START_EPOCH))

echo
echo "=== LIVE HMN REFRESH END ==="
echo "__HEARTBEAT__ stage=runner_finished elapsed=${TOTAL_ELAPSED}s runner_pid=${RUNNER_PID}"
echo

RUNNER_OUTPUT="$(
  cat "$RUNNER_OUT" 2>/dev/null ||
  true
)"

RUNNER_STDERR="$(
  cat "$RUNNER_ERR" 2>/dev/null ||
  true
)"

fact runner_commit_rc "$RUNNER_RC"
fact runner_elapsed_seconds "$TOTAL_ELAPSED"

json_block runner_commit "$RUNNER_OUTPUT"
block runner_commit_stderr_final "$RUNNER_STDERR"

OLD_POOL_FALLBACK=false
FRESH_DOWNLOAD_PROVEN=false

if grep -q \
  'pool_source=old-after-download-fail' \
  "$LOG_DELTA"
then
  OLD_POOL_FALLBACK=true
fi

if grep -Eq \
  'pool_source=fresh|last_fresh_download_rc=0' \
  "$LOG_DELTA"
then
  FRESH_DOWNLOAD_PROVEN=true
fi

fact old_pool_fallback "$OLD_POOL_FALLBACK"
fact fresh_download_proven "$FRESH_DOWNLOAD_PROVEN"

restore_services
sleep 2

RUNNER_POST="$("$RUNNER" --dry-run)"
HOOK_POST="$("$HOOK")"
PLANNER_POST="$("$PLANNER")"

json_block runner_post "$RUNNER_POST"
json_block hook_post "$HOOK_POST"
json_block planner_post "$PLANNER_POST"

fact state_mode_post "$(state_value mode UNKNOWN)"
fact state_status_post "$(
  state_value last_emergency_refresh_status UNKNOWN
)"
fact state_epoch_post "$(
  state_value last_emergency_refresh_epoch 0
)"
fact repair_counter_post "$(repair_counter)"

fact hook_running_post "$(bool_cmd "$HOOK_INIT" running)"
fact watcher_running_post "$(bool_cmd "$WATCHER_INIT" running)"
fact strict_all_post "$(bool_cmd strict_all)"
fact routes_all_post "$(bool_cmd routes_all)"

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

fact direct_failopen_changed false

[ "$RUNNER_RC" -eq 0 ] || {
  echo "__ERROR__ runner_rc=$RUNNER_RC"
  exit 31
}

printf '%s\n' "$RUNNER_OUTPUT" |
  grep -q \
    '"decision"[[:space:]]*:[[:space:]]*"refresh_ok_rebalance_ok"' || {
  echo "__ERROR__ runner_decision_not_success"
  exit 32
}

[ "$OLD_POOL_FALLBACK" = false ] || {
  echo "__ERROR__ fresh_download_failed_old_pool_fallback"
  exit 33
}

[ "$FRESH_DOWNLOAD_PROVEN" = true ] || {
  echo "__ERROR__ fresh_download_not_proven"
  exit 34
}

printf '%s\n' "$RUNNER_POST" |
  grep -q \
    '"decision"[[:space:]]*:[[:space:]]*"cooldown_active"' || {
  echo "__ERROR__ cooldown_not_active"
  exit 35
}

printf '%s\n' "$PLANNER_POST" |
  grep -q \
    '"changes_count"[[:space:]]*:[[:space:]]*0' || {
  echo "__ERROR__ planner_not_converged"
  exit 36
}

[ "$(state_value mode UNKNOWN)" = NORMAL ] || {
  echo "__ERROR__ state_not_normal"
  exit 37
}

[ "$(state_value last_emergency_refresh_status UNKNOWN)" = refresh_ok_rebalance_ok ] || {
  echo "__ERROR__ state_status_not_success"
  exit 38
}

[ "$(bool_cmd strict_all)" = true ] || {
  echo "__ERROR__ strict_not_all"
  exit 39
}

[ "$(bool_cmd routes_all)" = true ] || {
  echo "__ERROR__ routes_not_all"
  exit 40
}

[ "$(bool_cmd "$HOOK_INIT" running)" = true ] || {
  echo "__ERROR__ hook_not_restored"
  exit 41
}

[ "$(bool_cmd "$WATCHER_INIT" running)" = true ] || {
  echo "__ERROR__ watcher_not_restored"
  exit 42
}

[ "$(bool_cmd test -e /var/lock/router-egress-emergency-refresh.lock)" = false ] || {
  echo "__ERROR__ emergency_lock_remains"
  exit 43
}

[ "$(bool_cmd test -e /tmp/hmn-refresh-pool-safe.lock)" = false ] || {
  echo "__ERROR__ refresh_lock_remains"
  exit 44
}

echo "__TRACE__ stage=complete"

trap - EXIT

rm -f \
  "$RUNNER_OUT" \
  "$RUNNER_ERR" \
  "$LOG_DELTA"

exit 0
VM101

cat > "$REPORT_DIR/vm101-postcheck.sh" <<'VM101POST'
#!/bin/sh
set -eu
umask 077

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

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

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
}

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

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

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

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

fact commit_raw "$RAW"
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 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
)"

json_block runner "$RUNNER_JSON"
json_block planner "$PLANNER_JSON"

fact production_modified false
VM101POST

chmod 600 \
  "$REPORT_DIR/vm101-tool-hash-check.sh" \
  "$REPORT_DIR/vm101-precheck.sh" \
  "$REPORT_DIR/vm101.sh" \
  "$REPORT_DIR/vm101-postcheck.sh"

sh -n "$REPORT_DIR/vm101-tool-hash-check.sh"
sh -n "$REPORT_DIR/vm101-precheck.sh"
sh -n "$REPORT_DIR/vm101.sh"
sh -n "$REPORT_DIR/vm101-postcheck.sh"

mark_success "all_remote_scripts_published"

stage "03/09" "Проверяю frozen toolchain и HMN code"

if ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101-tool-hash-check.sh" \
  > "$REPORT_DIR/vm101-tool-hash-check.txt" \
  2> "$REPORT_DIR/vm101-tool-hash-check.stderr"
then
  HASH_CHECK_RC=0
else
  HASH_CHECK_RC=$?
fi

[ "$HASH_CHECK_RC" -eq 0 ] ||
  fatal "FROZEN_TOOLCHAIN_CHECK_FAILED" "$HASH_CHECK_RC" "$LINENO"

grep -Fq \
  "__SUMMARY__ checked=10 errors=0" \
  "$REPORT_DIR/vm101-tool-hash-check.txt" ||
  fatal "LIVE_TOOLCHAIN_DRIFT_DETECTED" 7 "$LINENO"

set +e

ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101-precheck.sh" \
  > >(tee "$REPORT_DIR/vm101-precheck.txt") \
  2> >(tee "$REPORT_DIR/vm101-precheck.stderr" >&2)

PRECHECK_RC=$?

set -e

[ "$PRECHECK_RC" -eq 0 ] ||
  fatal "HMN_CODE_OR_LIVE_PRECHECK_FAILED" "$PRECHECK_RC" "$LINENO"

grep -Fq '__FACT__ code_test_rc=0' \
  "$REPORT_DIR/vm101-precheck.txt" ||
  fatal "HMN_CODE_TEST_FAILED" 8 "$LINENO"

mark_success "hmn_code_and_live_health_passed"

stage "04/09" "Запускаю HMN refresh с полным live-stream и heartbeat"

echo
echo "Во время этой стадии нормальная продолжительность — около 15 минут."
echo "Вывод HMN refresh будет появляться в терминале по мере поступления."
echo

set +e

ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o ServerAliveInterval=20 \
    -o ServerAliveCountMax=6 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101.sh" \
  > >(tee "$REPORT_DIR/vm101.txt") \
  2> >(tee "$REPORT_DIR/vm101.stderr" >&2)

VM101_RC=$?

set -e

echo "vm101_rc=$VM101_RC" |
  tee -a "$PROGRESS_LOG"

VM101_ROLLBACK="$(
  grep '^__FACT__ rollback=' \
    "$REPORT_DIR/vm101.txt" |
    tail -n1 |
    cut -d= -f2- ||
    true
)"

if grep -Fq \
  '__FACT__ mutation_started=true' \
  "$REPORT_DIR/vm101.txt"
then
  VM101_CHANGED=true
  PRODUCTION_MODIFIED=true
fi

if grep -Fq \
  '__FACT__ auto_rollback=true' \
  "$REPORT_DIR/vm101.txt"
then
  VM101_CHANGED=false
  PRODUCTION_MODIFIED=false
  ROLLBACK_RC="REMOTE_AUTO_ROLLBACK_OK"
fi

[ "$VM101_RC" -eq 0 ] ||
  fatal "VM101_FRESH_REFRESH_FAILED" "$VM101_RC" "$LINENO"

[ -n "$VM101_ROLLBACK" ] ||
  fatal "ROLLBACK_PATH_MISSING" 9 "$LINENO"

mark_success "fresh_refresh_remote_passed"

stage "05/09" "Проверяю persisted NORMAL, cooldown и convergence"

set +e

ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101-postcheck.sh" \
  > >(tee "$REPORT_DIR/vm101-postcheck.txt") \
  2> >(tee "$REPORT_DIR/vm101-postcheck.stderr" >&2)

POSTCHECK_RC=$?

set -e

[ "$POSTCHECK_RC" -eq 0 ] ||
  fatal "PERSISTED_POSTCHECK_REMOTE_FAILED" "$POSTCHECK_RC" "$LINENO"

python3 - "$REPORT_DIR/vm101-postcheck.txt" <<'PY'
import json
import sys
from pathlib import Path

facts = {}
blocks = {}
current = None
lines = []

for line in Path(sys.argv[1]).read_text(
    encoding="utf-8",
    errors="replace",
).splitlines():
    if line.startswith("__FACT__ "):
        key, value = line[len("__FACT__ "):].split("=", 1)
        facts[key] = value

    elif line.startswith("__JSON_BEGIN__ "):
        current = line[len("__JSON_BEGIN__ "):]
        lines = []

    elif line.startswith("__JSON_END__ "):
        name = line[len("__JSON_END__ "):]

        if name == current:
            blocks[name] = json.loads("\n".join(lines))

        current = None

    elif current is not None:
        lines.append(line)

runner = blocks["runner"]
planner = blocks["planner"]

assert facts["commit_raw"] == "true"

assert facts["state_mode"] == "NORMAL"
assert facts["state_status"] == "refresh_ok_rebalance_ok"
assert int(facts["state_epoch"]) > 0

assert facts["hook_running"] == "true"
assert facts["hook_enabled"] == "true"
assert facts["watcher_running"] == "true"
assert facts["watcher_enabled"] == "true"

assert facts["emergency_lock_present"] == "false"
assert facts["refresh_lock_present"] == "false"

assert runner["decision"] == "cooldown_active"
assert runner["cooldown_remaining"] > 0
assert runner["last_emergency_refresh_status"] == "refresh_ok_rebalance_ok"
assert runner["direct_failopen_enabled"] is False

assert planner["decision"] == "plan_ok"
assert planner["changes_count"] == 0
assert len(planner["plan"]) == 5

assert facts["production_modified"] == "false"
PY

mark_success "persisted_postcheck_passed"

stage "06/09" "Закрываю M07 и переиздаю локальный план"

"$STATUS_TOOL" \
  M07 done \
  --evidence "$TRYCF_REPORT" \
  --note "Fresh HMN download доказан. Полный HMN refresh выводился live в терминал и завершился успешно; top-5 rebalance применён, state NORMAL, cooldown активен, planner converged, пять VPN-слотов и маршруты 201–205 исправны, Direct не использовался." \
  > "$REPORT_DIR/plan-status-m07.txt" \
  2> "$REPORT_DIR/plan-status-m07.stderr"

PLAN_UPDATED=true

REPUBLISH_OUTPUT="$(
  "$REPUBLISH_TOOL" \
    "$STEP" \
    "$TRYCF_REPORT"
)"

printf '%s\n' "$REPUBLISH_OUTPUT" \
  > "$REPORT_DIR/plan-republish.txt"

NEW_ARCHITECTURE_PLAN="$(
  printf '%s\n' "$REPUBLISH_OUTPUT" |
    sed -n 's/^ARCHITECTURE_PLAN=//p' |
    tail -n1
)"

[ -n "$NEW_ARCHITECTURE_PLAN" ] ||
  fatal "PLAN_REPUBLISH_URL_MISSING" 10 "$LINENO"

ARCHITECTURE_PLAN="$NEW_ARCHITECTURE_PLAN"

python3 - "$PLAN_STATE_DIR/milestones.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

items = {
    item["id"]: item
    for item in data["milestones"]
}

assert items["M07"]["status"] == "done"
assert items["M08"]["status"] == "in_progress"
assert data["current_milestone"] == "M08"
PY

mark_success "plan_updated_to_m08"

stage "07/09" "Извлекаю итоговые факты операции"

RUNNER_ELAPSED="$(
  sed -n \
    's/^__FACT__ runner_elapsed_seconds=//p' \
    "$REPORT_DIR/vm101.txt" |
    tail -n1
)"

REPAIR_COUNTER="$(
  sed -n \
    's/^__FACT__ repair_counter_post=//p' \
    "$REPORT_DIR/vm101.txt" |
    tail -n1
)"

FRESH_DOWNLOAD="$(
  sed -n \
    's/^__FACT__ fresh_download_proven=//p' \
    "$REPORT_DIR/vm101.txt" |
    tail -n1
)"

OLD_POOL_FALLBACK="$(
  sed -n \
    's/^__FACT__ old_pool_fallback=//p' \
    "$REPORT_DIR/vm101.txt" |
    tail -n1
)"

[ "$FRESH_DOWNLOAD" = true ] ||
  fatal "FRESH_DOWNLOAD_FACT_NOT_TRUE" 11 "$LINENO"

[ "$OLD_POOL_FALLBACK" = false ] ||
  fatal "OLD_POOL_FALLBACK_FACT_TRUE" 12 "$LINENO"

mark_success "operation_facts_extracted"

stage "08/09" "Публикую PASS report и facts"

cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=${PASS_DECISION}
all_ok=true
mode=M07_FRESH_HMN_REFRESH_LIVE_STREAM

operation:
  hmn_code_test_passed=true
  fresh_download_proven=true
  old_pool_fallback=false
  runner_decision=refresh_ok_rebalance_ok
  runner_elapsed_seconds=${RUNNER_ELAPSED}
  real_refresh_ran=true
  rebalance_apply_ran=true
  repair_counter=${REPAIR_COUNTER}
  state_mode=NORMAL
  state_status=refresh_ok_rebalance_ok
  cooldown_active=true
  planner_converged=true

live_streaming:
  runner_stdout=true
  runner_stderr=true
  emergency_log=true
  heartbeat_seconds=15
  terminal_output_complete=true
  captured_in_vm101_txt=true
  captured_in_vm101_stderr=true

validation:
  five_vpn_slots=true
  routes_201_205=true
  services_restored=true
  locks_released=true
  persisted_postcheck=true

safety:
  production_modified=true
  direct_failopen_changed=false
  rollback_vm101=${VM101_ROLLBACK}
  rollback_available=true

inline_diagnostics:
  enabled=true
  live_stream_captured=true
  automatic_classification_present=true
  rollback_on_stop=true
  separate_diagnostic_step_required=false

plan:
  milestone_completed=M07
  current_milestone=M08
  plan_republished=true

next_step:
  M08_DEGRADED_POOL_CONTROLLED_SIMULATION

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
EOF

python3 - \
  "$STEP" \
  "$TS" \
  "$RUNNER_ELAPSED" \
  "$REPAIR_COUNTER" \
  "$VM101_ROLLBACK" \
  "$TRYCF_REPORT" \
  "$REPORT_TXT" \
  "$FACTS_JSON" \
  "$ARCHITECTURE_PLAN" \
  "$XS_MAP" \
  "$GLOBAL_PROJECT_PLAN" \
  > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    step,
    timestamp,
    elapsed,
    repair_counter,
    rollback,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "generated_at_utc": timestamp,
    "assessment": {
        "decision":
            "PASS_STEP_050M07C2_FRESH_HMN_REFRESH_LIVE_STREAM",
        "all_ok": True,
    },
    "operation": {
        "hmn_code_test_passed": True,
        "fresh_download_proven": True,
        "old_pool_fallback": False,
        "runner_decision": "refresh_ok_rebalance_ok",
        "runner_elapsed_seconds": int(elapsed),
        "real_refresh_ran": True,
        "rebalance_apply_ran": True,
        "repair_counter": int(repair_counter),
        "state_mode": "NORMAL",
        "state_status": "refresh_ok_rebalance_ok",
        "cooldown_active": True,
        "planner_converged": True,
    },
    "live_streaming": {
        "runner_stdout": True,
        "runner_stderr": True,
        "emergency_log": True,
        "heartbeat_seconds": 15,
        "terminal_output_complete": True,
        "captured_in_vm101_txt": True,
        "captured_in_vm101_stderr": True,
    },
    "safety": {
        "production_modified": True,
        "direct_failopen_changed": False,
        "rollback_vm101": rollback,
        "rollback_available": True,
    },
    "inline_diagnostics": {
        "enabled": True,
        "live_stream_captured": True,
        "automatic_classification_present": True,
        "rollback_on_stop": True,
        "separate_diagnostic_step_required": False,
    },
    "plan": {
        "milestone_completed": "M07",
        "current_milestone": "M08",
        "plan_republished": True,
    },
    "next_step": "M08_DEGRADED_POOL_CONTROLLED_SIMULATION",
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
    },
}, ensure_ascii=False, indent=2))
PY

cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head><meta charset="utf-8"><title>${STEP}</title></head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto">
<h1>${STEP}</h1>

<h2>Live-stream</h2>
<ul>
<li><a href="vm101.txt">Полный stdout и emergency log</a></li>
<li><a href="vm101.stderr">Полный stderr</a></li>
</ul>

<h2>Скрипты</h2>
<ul>
<li><a href="step.sh">step.sh</a></li>
<li><a href="vm101-tool-hash-check.sh">vm101-tool-hash-check.sh</a></li>
<li><a href="vm101-precheck.sh">vm101-precheck.sh</a></li>
<li><a href="vm101.sh">vm101.sh</a></li>
<li><a href="vm101-postcheck.sh">vm101-postcheck.sh</a></li>
</ul>

<h2>Результаты</h2>
<ul>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
<li><a href="vm101-postcheck.txt">vm101-postcheck.txt</a></li>
<li><a href="plan-status-m07.txt">plan-status-m07.txt</a></li>
<li><a href="plan-republish.txt">plan-republish.txt</a></li>
</ul>
</body>
</html>
EOF

find "$REPORT_DIR" \
  -type f \
  ! -name SHA256SUMS \
  -print0 |
  sort -z |
  xargs -0 sha256sum \
  > "$REPORT_DIR/SHA256SUMS"

cat > "$STATE_ROOT/current-project-links.env" <<EOF
UPDATED_AT_UTC=${TS}
SOURCE_STEP=${STEP}
CURRENT_REPORT=${TRYCF_REPORT}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
EOF

stage "09/09" "Завершаю M07"

VM101_CHANGED=false
PLAN_UPDATED=false

mark_success "report_published"
trap - ERR

echo "decision=$PASS_DECISION" |
  tee -a "$PROGRESS_LOG"

echo "fresh_download_proven=true" |
  tee -a "$PROGRESS_LOG"

echo "old_pool_fallback=false" |
  tee -a "$PROGRESS_LOG"

echo "runner_elapsed_seconds=$RUNNER_ELAPSED" |
  tee -a "$PROGRESS_LOG"

echo "milestone_completed=M07" |
  tee -a "$PROGRESS_LOG"

echo "current_milestone=M08" |
  tee -a "$PROGRESS_LOG"

echo "state_mode=NORMAL" |
  tee -a "$PROGRESS_LOG"

echo "cooldown_active=true" |
  tee -a "$PROGRESS_LOG"

echo "live_streaming=true" |
  tee -a "$PROGRESS_LOG"

echo "inline_diagnostics=true" |
  tee -a "$PROGRESS_LOG"

print_links
