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

BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"
FINAL_ROOT="${BUNDLE_ROOT:?}"
INCOMING="${ROUTER_STEP_INCOMING:-/home/ops/incoming}"
RUN_DIR="${ROUTER_DETACHED_RUN_DIR:?}"
CHILD_RESULT="${ROUTER_DETACHED_CHILD_RESULT:?}"
SELFTEST="${ROUTER_EXACT_WORKER_SELFTEST:-false}"
STEP='STEP_050M07R20QW_R01_MULTI_PROTOCOL_READONLY_AUDIT'
REVISION='R01'

EXPECTED_PACKAGE_SHA="$(python3 - "$FINAL_ROOT/release-info.json" <<'PY'
import json,sys
print(json.load(open(sys.argv[1],encoding="utf-8"))["target_package_sha256"])
PY
)"
PACKAGE="$FINAL_ROOT/payload/multi-protocol-readonly-audit-reference-target-package.tar.gz"

WORK="$RUN_DIR/work"
EVIDENCE="$RUN_DIR/evidence"
REPORT="$RUN_DIR/report"
PAYLOAD="$RUN_DIR/public-payload"
CURRENT="$RUN_DIR/workflow-current.txt"
EVENTS="$RUN_DIR/workflow-events.tsv"
FINAL_ENV="$RUN_DIR/final-publication.env"

CORE_CHANGE_COMPLETE=false
ROLLBACK_STATUS=not_applicable_read_only
CURRENT_PHASE=initialization
STOP_HANDLED=false
LATEST_ARCHIVE=not_created
LATEST_ARCHIVE_SHA256=unknown
STOP_MACHINE=VM130
STOP_DETAIL=unclassified_diagnostic_failure
NEXT_DIAGNOSTIC_ACTION=inspect_retained_readonly_evidence

mkdir -p "$WORK" "$EVIDENCE" "$REPORT" "$PAYLOAD" "$INCOMING"
chmod 700 "$WORK" "$EVIDENCE" "$REPORT" "$PAYLOAD"

source "$BASE/lib/router-step-workflow.sh"
router_step_workflow_init "$CURRENT" "$EVENTS" preflight audit report_build report_publish archive

write_child() {
    local result="$1"
    local rc="$2"
    local tmp="${CHILD_RESULT}.tmp.$$"
    {
        echo "RESULT=$result"
        echo "WORKER_RC=$rc"
        echo "CORE_CHANGE_COMPLETE=false"
        echo "ROLLBACK_STATUS=$ROLLBACK_STATUS"
        echo "LATEST_ARCHIVE=$LATEST_ARCHIVE"
        echo "LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256"
    } > "$tmp"
    chmod 600 "$tmp"
    mv -f "$tmp" "$CHILD_RESULT"
}

archive_latest() {
    local log="$EVIDENCE/archive-latest.log"
    router_step_archive_latest_python "$BASE" "$INCOMING" "$(date -u +%Y%m%d-%H%M%S)" | tee "$log"
    LATEST_ARCHIVE="$(awk -F= '$1=="LATEST_ARCHIVE"{print substr($0,index($0,"=")+1)}' "$log" | tail -n 1)"
    LATEST_ARCHIVE_SHA256="$(awk -F= '$1=="LATEST_ARCHIVE_SHA256"{print $2}' "$log" | tail -n 1)"
}

selftest_publish_dir() {
    local label="$1"
    local src="$2"
    local dir="${ROUTER_PUBLIC_ROOT:?}/latest/$label"
    rm -rf "$dir"
    mkdir -p "$dir"
    cp -a "$src"/. "$dir"/
    chmod -R u+rwX,go+rX "$dir"
    printf 'selftest://%s/\n' "$label"
}

prepare_public_evidence() {
    local file
    : > "$REPORT/evidence-summary.txt"
    while IFS= read -r file; do
        [[ -f "$file" ]] || continue
        printf '===== %s =====\n' "$(basename "$file")" >> "$REPORT/evidence-summary.txt"
        cat "$file" >> "$REPORT/evidence-summary.txt" 2>/dev/null || true
        printf '\n' >> "$REPORT/evidence-summary.txt"
    done < <(find "$EVIDENCE" -maxdepth 1 -type f -print | sort)
    cp "$EVIDENCE"/*.txt "$REPORT/" 2>/dev/null || true
}

build_stop_report() {
    local result="$1"
    local line="$2"
    local rc="$3"
    local command="$4"
    {
        echo "RESULT=$result"
        echo "REVISION=$REVISION"
        echo "STOP_PHASE=$CURRENT_PHASE"
        echo "STOP_LINE=$line"
        echo "STOP_RC=$rc"
        printf 'STOP_COMMAND=%q\n' "$command"
        echo "STOP_MACHINE=$STOP_MACHINE"
        echo "STOP_DETAIL=$STOP_DETAIL"
        echo "NEXT_DIAGNOSTIC_ACTION=$NEXT_DIAGNOSTIC_ACTION"
        echo "RETAINED_RUN_DIR=$RUN_DIR"
        echo "CORE_CHANGE_COMPLETE=false"
        echo "RUNTIME_IMPACT=false"
        echo "ROLLBACK_STATUS=$ROLLBACK_STATUS"
    } > "$REPORT/report.txt"
    python3 - "$REPORT/facts.json" "$result" "$CURRENT_PHASE" "$STOP_MACHINE" "$STOP_DETAIL" "$RUN_DIR" <<'PY'
import json,sys
p,result,phase,machine,detail,run_dir=sys.argv[1:]
json.dump({
  "result":result,
  "phase":phase,
  "machine":machine,
  "detail":detail,
  "retained_run_dir":run_dir,
  "core_change_complete":False,
  "runtime_impact":False
},open(p,"w"),indent=2)
open(p,"a").write("\n")
PY
    cp "$REPORT/report.txt" "$REPORT/verify.txt"
    printf 'Read-only STEP. Rollback is not applicable.\n' > "$REPORT/rollback.txt"
    cp "$CURRENT" "$REPORT/workflow-current.txt"
    cp "$EVENTS" "$REPORT/workflow-events.tsv"
    cp "$FINAL_ROOT/scripts/run-step.sh" "$REPORT/executed-step.sh"
    prepare_public_evidence
}

publish_stop() {
    if [[ "$SELFTEST" == true ]]; then
        selftest_publish_dir r20qw-r01-stop "$REPORT" >/dev/null
    else
        router_step_publish_payload \
            step050m07r20qw_r01_multi_protocol_readonly_audit_stop \
            "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" \
            "$REPORT/report.txt" report.txt \
            "$REPORT/facts.json" facts.json \
            "$REPORT/verify.txt" verify.txt \
            "$REPORT/rollback.txt" rollback.txt \
            "$REPORT/executed-step.sh" executed-step.sh \
            "$REPORT/workflow-current.txt" workflow-current.txt \
            "$REPORT/workflow-events.tsv" workflow-events.tsv \
            "$REPORT/evidence-summary.txt" evidence-summary.txt
    fi
    set +e
    archive_latest
    set -e
}

stop_handler() {
    local rc="$1"
    local line="$2"
    local command="$3"
    trap - ERR
    [[ "$STOP_HANDLED" == false ]] || exit "$rc"
    STOP_HANDLED=true
    set +e
    router_step_phase_fail "$CURRENT_PHASE" "rc=$rc" 2>/dev/null || true
    set -e
    local result='STOP_R20QW_MULTI_PROTOCOL_READONLY_AUDIT'
    build_stop_report "$result" "$line" "$rc" "$command"
    publish_stop
    write_child "$result" "$rc"
    cat "$REPORT/report.txt"
    exit "$rc"
}
trap 'rc=$?; stop_handler "$rc" "$LINENO" "$BASH_COMMAND"' ERR

capture_local() {
    local out="$1"
    local err="$2"
    local rcfile="$3"
    shift 3
    local rc
    if "$@" >"$out" 2>"$err"; then
        rc=0
    else
        rc=$?
    fi
    printf 'LOCAL_RC=%s\n' "$rc" >"$rcfile"
    return "$rc"
}

vm121_script() {
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 'bash -s'
}
vm100_script() {
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 pve-mgts \
        "ssh -T -i /root/.ssh/pve_to_openwrt_mgts_ed25519 -o BatchMode=yes -o ConnectTimeout=20 root@10.71.100.1 'sh -s'"
}
vm101_script() {
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 pve-mgts \
        "ssh -T -i /root/.ssh/pve_to_openwrt_mgts_ed25519 -o BatchMode=yes -o ConnectTimeout=20 root@10.71.100.2 'sh -s'"
}

capture_remote() {
    local machine="$1"
    local input="$2"
    local out="$3"
    local err="$4"
    local rcfile="$5"
    local rc
    case "$machine" in
        vm121)
            if vm121_script <"$input" >"$out" 2>"$err"; then rc=0; else rc=$?; fi
            ;;
        vm100)
            if vm100_script <"$input" >"$out" 2>"$err"; then rc=0; else rc=$?; fi
            ;;
        vm101)
            if vm101_script <"$input" >"$out" 2>"$err"; then rc=0; else rc=$?; fi
            ;;
        *)
            return 99
            ;;
    esac
    printf 'REMOTE_RC=%s\nMACHINE=%s\n' "$rc" "$machine" >"$rcfile"
    return "$rc"
}

CURRENT_PHASE=preflight
router_step_phase_begin preflight
"$FINAL_ROOT/scripts/readonly-package-apply.sh" "$EXPECTED_PACKAGE_SHA" "$PACKAGE" \
    >"$EVIDENCE/package-verify.stdout.txt" 2>"$EVIDENCE/package-verify.stderr.txt"
echo 'LOCAL_RC=0' >"$EVIDENCE/package-verify.rc.txt"
if [[ "$SELFTEST" == true ]]; then
    if [[ -e "$INCOMING/selftest-force-stop" ]]; then
        STOP_MACHINE=VM130
        STOP_DETAIL=forced_preflight_stop_fixture
        NEXT_DIAGNOSTIC_ACTION=remove_selftest_force_stop
        false
    fi
else
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 true
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 pve-mgts true
fi
router_step_phase_complete preflight read_only_connectivity_and_package_verified

CURRENT_PHASE=audit
router_step_phase_begin audit
if [[ "$SELFTEST" == true ]]; then
    capture_local \
        "$EVIDENCE/vm121-audit.stdout.txt" "$EVIDENCE/vm121-audit.stderr.txt" "$EVIDENCE/vm121-audit.rc.txt" \
        env ROUTER_AUDIT_SELFTEST=true bash "$FINAL_ROOT/scripts/audit-vm121.sh"
    capture_local \
        "$EVIDENCE/vm100-audit.stdout.txt" "$EVIDENCE/vm100-audit.stderr.txt" "$EVIDENCE/vm100-audit.rc.txt" \
        env ROUTER_AUDIT_SELFTEST=true sh "$FINAL_ROOT/scripts/audit-vm100.sh"
    capture_local \
        "$EVIDENCE/vm101-audit.stdout.txt" "$EVIDENCE/vm101-audit.stderr.txt" "$EVIDENCE/vm101-audit.rc.txt" \
        env ROUTER_AUDIT_SELFTEST=true sh "$FINAL_ROOT/scripts/audit-vm101.sh"
else
    capture_remote vm121 "$FINAL_ROOT/scripts/audit-vm121.sh" \
        "$EVIDENCE/vm121-audit.stdout.txt" "$EVIDENCE/vm121-audit.stderr.txt" "$EVIDENCE/vm121-audit.rc.txt"
    capture_remote vm100 "$FINAL_ROOT/scripts/audit-vm100.sh" \
        "$EVIDENCE/vm100-audit.stdout.txt" "$EVIDENCE/vm100-audit.stderr.txt" "$EVIDENCE/vm100-audit.rc.txt"
    capture_remote vm101 "$FINAL_ROOT/scripts/audit-vm101.sh" \
        "$EVIDENCE/vm101-audit.stdout.txt" "$EVIDENCE/vm101-audit.stderr.txt" "$EVIDENCE/vm101-audit.rc.txt"
fi
grep -Fqx 'RESULT=PASS_R20QW_VM121_READONLY_AUDIT' "$EVIDENCE/vm121-audit.stdout.txt"
grep -Fqx 'RESULT=PASS_R20QW_VM100_READONLY_AUDIT' "$EVIDENCE/vm100-audit.stdout.txt"
grep -Fqx 'RESULT=PASS_R20QW_VM101_READONLY_AUDIT' "$EVIDENCE/vm101-audit.stdout.txt"
router_step_phase_complete audit vm121_vm100_vm101_safe_evidence_collected

CURRENT_PHASE=report_build
router_step_phase_begin report_build
prepare_public_evidence
cp "$FINAL_ROOT/scripts/run-step.sh" "$REPORT/executed-step.sh"
cp "$FINAL_ROOT/release-info.json" "$REPORT/release-info.json"
cp "$FINAL_ROOT/manifest.sha256" "$REPORT/bundle-manifest.sha256"
cp "$CURRENT" "$REPORT/workflow-current.txt"
cp "$EVENTS" "$REPORT/workflow-events.tsv"
cp -a "$FINAL_ROOT/reference/architecture-v2" "$REPORT/architecture-v2-draft"

python3 - "$REPORT/facts.json" \
    "$EVIDENCE/vm121-audit.stdout.txt" \
    "$EVIDENCE/vm100-audit.stdout.txt" \
    "$EVIDENCE/vm101-audit.stdout.txt" <<'PY'
import json,sys
def load(path):
    d={}
    for raw in open(path,encoding="utf-8",errors="replace"):
        line=raw.rstrip("\n")
        if "=" in line and not line.startswith((" ", "\t")):
            k,v=line.split("=",1)
            if k and " " not in k and k.replace("_","").isalnum():
                d[k]=v
    return d
out={
  "result":"PASS_R20QW_MULTI_PROTOCOL_READONLY_AUDIT",
  "core_change_complete":False,
  "runtime_impact":False,
  "project_source_published":False,
  "vm121":load(sys.argv[2]),
  "vm100":load(sys.argv[3]),
  "vm101":load(sys.argv[4]),
}
json.dump(out,open(sys.argv[1],"w"),indent=2,sort_keys=True)
open(sys.argv[1],"a").write("\n")
PY

python3 - \
    "$EVIDENCE/vm121-audit.stdout.txt" \
    "$EVIDENCE/vm100-audit.stdout.txt" \
    "$EVIDENCE/vm101-audit.stdout.txt" \
    "$REPORT/current-state-gap-register.txt" <<'PY'
import sys
def load(path):
    d={}
    for raw in open(path,encoding="utf-8",errors="replace"):
        s=raw.strip()
        if "=" in s:
            k,v=s.split("=",1)
            if k and " " not in k:
                d[k]=v
    return d
v121,v100,v101=map(load,sys.argv[1:4])
lines=[
"WG Paid multi-protocol read-only current-state register",
"",
"VM121:",
f"- backend health: {v121.get('BACKEND_HEALTH','unknown')}",
f"- DB health: {v121.get('DB_HEALTH','unknown')}",
f"- Alembic: {v121.get('ALEMBIC_VERSION','unknown')}",
f"- users/subscriptions/peers: {v121.get('USER_COUNT','unknown')}/{v121.get('SUBSCRIPTION_COUNT','unknown')}/{v121.get('PEER_COUNT','unknown')}",
f"- pending/failed jobs: {v121.get('PENDING_JOB_COUNT','unknown')}/{v121.get('FAILED_JOB_COUNT','unknown')}",
f"- active selector helper: {v121.get('SELECTOR_HELPER_ACTIVE','unknown')}",
"",
"VM100:",
f"- wg_paid present/peers: {v100.get('WG_PAID_PRESENT','unknown')}/{v100.get('WG_PAID_PEER_COUNT','unknown')}",
f"- selector entries: {v100.get('SELECTOR_ENTRY_COUNT','unknown')}",
f"- AmneziaWG CLI/packages: {v100.get('AMNEZIAWG_CLI_PRESENT','unknown')}/{v100.get('AMNEZIAWG_PACKAGE_COUNT','unknown')}",
f"- awg_paid present: {v100.get('AWG_PAID_INTERFACE_PRESENT','unknown')}",
f"- candidate port collision: {v100.get('CANDIDATE_AWG_PORT_COLLISION','unknown')}",
f"- candidate pool conflict: {v100.get('CANDIDATE_AWG_POOL_CONFLICT','unknown')}",
"",
"VM101:",
f"- existing WG DNAT: {v101.get('WG_PAID_DNAT_PRESENT','unknown')}",
f"- candidate AWG public port collision: {v101.get('CANDIDATE_AWG_PUBLIC_PORT_COLLISION','unknown')}",
f"- candidate AWG DNAT already present: {v101.get('CANDIDATE_AWG_DNAT_PRESENT','unknown')}",
"",
"This file records facts only. Architectural conclusions are made after review."
]
open(sys.argv[4],"w",encoding="utf-8").write("\n".join(lines)+"\n")
PY

cat >"$REPORT/report.txt" <<'EOF'
RESULT=PASS_R20QW_MULTI_PROTOCOL_READONLY_AUDIT
REVISION=R01
WORKFLOW_CONTRACT_VERSION=2
CLASSIFICATION=READ_ONLY_DIAGNOSTIC
CORE_CHANGE_COMPLETE=false
RUNTIME_IMPACT=false
ROLLBACK_STATUS=not_applicable_read_only
SNAPSHOT_CREATED=false
MACHINE_GIT_COMMIT_CREATED=false
PROJECT_SOURCE_PUBLISHED=false
ARCHITECTURE_V2_STATUS=draft_pending_live_review
AUDIT_SCOPE=VM121,VM100,VM101
VM100_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260801-190522_vm100_git_source_a8b7337674b9/
VM101_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260801-095331_vm101_git_source_ac678d1b3164/
VM121_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260713-182700_vm121_git_source_93e0e5a31f09/
GLOBAL_PLAN_URL=https://reports.secret-studio.ru/latest/20260711-123348_global_project_plan_wg_paid/
ACCESS_MAP_URL=https://reports.secret-studio.ru/latest/20260715-210236_access_map_canonical_current/
LOCAL_PLAN_URL=https://reports.secret-studio.ru/latest/20260719-080444_local_architecture_plan_vm101_autonomous_hmn_recovery_r19/
NEXT_ACTION=review audit and publish canonical VM121 multi-protocol Project Sources
EOF
cat >"$REPORT/verify.txt" <<'EOF'
RESULT=PASS_R20QW_VERIFY
VM121_AUDIT=PASS
VM100_AUDIT=PASS
VM101_AUDIT=PASS
SECRET_MATERIAL_REQUESTED=false
RUNTIME_MUTATION=false
PROJECT_SOURCE_PUBLICATION=false
EOF
printf 'Read-only STEP. Rollback is not applicable.\n' >"$REPORT/rollback.txt"
router_step_phase_complete report_build audit_report_and_draft_architecture_attached

CURRENT_PHASE=report_publish
router_step_phase_begin report_publish
if [[ "$SELFTEST" == true ]]; then
    STEP_REPORT_URL="$(selftest_publish_dir r20qw-r01-pass "$REPORT")"
else
    args=(
        "$REPORT/report.txt" report.txt
        "$REPORT/facts.json" facts.json
        "$REPORT/verify.txt" verify.txt
        "$REPORT/rollback.txt" rollback.txt
        "$REPORT/executed-step.sh" executed-step.sh
        "$REPORT/release-info.json" release-info.json
        "$REPORT/bundle-manifest.sha256" bundle-manifest.sha256
        "$REPORT/workflow-current.txt" workflow-current.txt
        "$REPORT/workflow-events.tsv" workflow-events.tsv
        "$REPORT/evidence-summary.txt" evidence-summary.txt
        "$REPORT/current-state-gap-register.txt" current-state-gap-register.txt
    )
    while IFS= read -r file; do
        args+=("$file" "$(basename "$file")")
    done < <(find "$REPORT" -maxdepth 1 -type f -name '*audit*.txt' -print | sort)
    while IFS= read -r file; do
        args+=("$file" "architecture-v2-draft/$(basename "$file")")
    done < <(find "$REPORT/architecture-v2-draft" -maxdepth 1 -type f -print | sort)
    router_step_publish_payload \
        step050m07r20qw_r01_multi_protocol_readonly_audit \
        "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" \
        "${args[@]}"
    STEP_REPORT_URL="$(awk -F= '$1=="PUBLIC_URL"{print substr($0,index($0,"=")+1)}' "$FINAL_ENV" | tail -n 1)"
fi
router_step_phase_complete report_publish step_report_published_and_verified

CURRENT_PHASE=archive
router_step_phase_begin archive
archive_latest
[[ -f "$LATEST_ARCHIVE" ]]
router_step_phase_complete archive one_final_latest_archive_created
router_step_workflow_mark_complete

trap - ERR
write_child PASS_R20QW_MULTI_PROTOCOL_READONLY_AUDIT 0
cat "$REPORT/report.txt"
echo "STEP_REPORT_URL=$STEP_REPORT_URL"
echo "LATEST_ARCHIVE=$LATEST_ARCHIVE"
echo "LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256"
