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

STEP_ID="STEP_050M07R15C_ROUTER_MACHINE_CLOSE_CONTRACT_FIX_R02"
STEP_LABEL="step050m07r15c_router_machine_close_contract_fix_r02"
SOURCE_LABEL="vm130_router_ops_source_snapshot_r15c_contract_fix_r02"
EXPECTED_PUBLISHER_SHA256="e78430b57afbd0ae27fc575fc4de78bb267c76caf04ec935b01e9b2f89840e32"
EXPECTED_CURRENT_WRAPPER_SHA256="e025ae64f4376706d60c0a339d380f90f4a578c0ca0f5766750de29aacf77595"

BUNDLE_DIR="$(cd "$(dirname "$0")" && pwd -P)"
SELF="$(readlink -f "$0")"
BUNDLE_ZIP="${BUNDLE_ZIP:?BUNDLE_ZIP is required}"
EXPECTED_BUNDLE_SHA256="${EXPECTED_BUNDLE_SHA256:?EXPECTED_BUNDLE_SHA256 is required}"
EXPECTED_INSTALLER_SHA256="${EXPECTED_INSTALLER_SHA256:?EXPECTED_INSTALLER_SHA256 is required}"

source "$BUNDLE_DIR/plans/current-links.env"
LATEST_ROOT_URL="https://reports.secret-studio.ru/latest/"
OLD_ROOT_URL="https://reports.secret-studio.ru/old/"

TS="$(date -u +%Y%m%d-%H%M%S)"
BASE="/opt/router-ops"
STEP_DIR="$BASE/steps/${TS}_${STEP_ID}"
BIN="$BASE/bin"
LIB="$BASE/lib"
TARGET="$BIN/router-machine-close"
CONTRACT_LIB="$LIB/router-machine-close-contract.sh"
SELFTEST="$BIN/router-machine-close-contract-selftest"
PUBLISHER="$BIN/router-publish-report"
PUBLIC_TOKEN_FILE="$BASE/public/.router-public-token"

mkdir -p "$STEP_DIR"
chmod 700 "$STEP_DIR"
STEP_FILE="$STEP_DIR/step-code.sh"
cp -a "$SELF" "$STEP_FILE"
chmod 700 "$STEP_FILE"
BUNDLE_COPY="$STEP_DIR/$(basename "$BUNDLE_ZIP")"
cp -a "$BUNDLE_ZIP" "$BUNDLE_COPY"

REPORT="$STEP_DIR/report.txt"
FACTS="$STEP_DIR/facts.json"
VERIFY="$STEP_DIR/verify.txt"
ROLLBACK="$STEP_DIR/rollback.sh"
MAIN_LOG="$STEP_DIR/main.log"
PROGRESS_LOG="$STEP_DIR/progress.log"
TRANSFER_VERIFY="$STEP_DIR/transfer-verify.txt"
SYSTEM_MODEL="$STEP_DIR/system-model.txt"
METHODS="$STEP_DIR/methods-limitations.txt"
ACCESS_ROUTES="$STEP_DIR/access-routes.txt"
BEFORE_INFO="$STEP_DIR/before.txt"
AFTER_INFO="$STEP_DIR/after.txt"
DIFF_FILE="$STEP_DIR/router-machine-close.diff"
FIXTURE_LOG="$STEP_DIR/bundle-fixture.log"
INSTALLED_TEST_LOG="$STEP_DIR/installed-selftest.log"
SOURCE_PUBLISH_LOG="$STEP_DIR/source-publish.log"
STEP_PUBLISH_LOG="$STEP_DIR/step-publish.log"
HTTP_LOG="$STEP_DIR/http-verify.log"
PHASES="$STEP_DIR/phases.txt"
BACKUP_DIR="$STEP_DIR/rollback-files"
SOURCE_WORK="$STEP_DIR/vm130-source-build"
SAFE_PUBLISH="$STEP_DIR/publish-safe"
mkdir -p "$BACKUP_DIR" "$SOURCE_WORK" "$SAFE_PUBLISH"
chmod 700 "$BACKUP_DIR" "$SOURCE_WORK" "$SAFE_PUBLISH"

RESULT="STOP_NOT_STARTED"
STOP_REASON="none"
CURRENT_PHASE="initialization"
COPY_VERIFY="FAIL"
STEP_WAS_NOT_STARTED="true"
CORE_CHANGE_COMPLETE="false"
CORE_CHANGE_REPEATED="false"
TARGET_INSTALLER_RERUN="false"
MACHINE_GIT_COMPLETE="false"
ROUTER_MACHINE_CLOSE_RERUN="false"
VM130_SOURCE_PUBLICATION_COMPLETE="false"
STEP_REPORT_PUBLICATION_COMPLETE="false"
CORE_ROLLED_BACK="false"
SELFTEST_PASS="false"
HTTP_VERIFY_PASS="false"
RUNTIME_IMPACT="false"
PUBLIC_OBJECT_KIND=""
PREVIOUS_MOVED_COUNT=""
STEP_REPORT_URL=""
FACTS_URL=""
VERIFY_URL=""
ROLLBACK_URL=""
STEP_PUBLISHED_DIR=""
SOURCE_PUBLISHED_DIR=""
SOURCE_PUBLIC_OBJECT_KIND=""
SOURCE_PREVIOUS_MOVED_COUNT=""
INSTALLED="false"

exec 3>&1
exec >>"$MAIN_LOG" 2>&1

progress() {
    printf '>>> [%s] %s\n' "$(date '+%F %T')" "$*" | tee -a "$PROGRESS_LOG" >&3
}
phase() {
    CURRENT_PHASE="$1"
    printf '%s=started\n' "$CURRENT_PHASE" >> "$PHASES"
    progress "$CURRENT_PHASE"
}

write_docs() {
    cat > "$SYSTEM_MODEL" <<EOF
STEP_ID=$STEP_ID
HOST=$(hostname)
SCOPE=VM130 workflow infrastructure only
CHANGED_PATHS=$TARGET $CONTRACT_LIB $SELFTEST
UNCHANGED_TARGETS=VM100 VM101 VM121
LIVE_ROUTER_MACHINE_CLOSE_RUN=false
VM101_RUNTIME_CHANGE=false
SERVICE_RESTARTS=none
TRAFFIC_INTERRUPTION=false
RUNTIME_IMPACT=false
EOF
    cat > "$METHODS" <<EOF
Method: exact R14B2 hash preflight; standalone payload; synthetic fixtures; atomic install; installed fixtures; full VM130 source snapshot; canonical publication; permanent HTTPS verification.
VM101 note: VM101 is OpenWrt/BusyBox ash, but this STEP does not connect to it or execute any command there.
Limitations: real machine-close execution is intentionally deferred to the next changing machine STEP.
EOF
    cat > "$ACCESS_ROUTES" <<EOF
No SSH is used. No access routes, aliases, keys, IPs or jump hosts change.
ACCESS_MAP_URL=$ACCESS_MAP_URL
EOF
}

write_facts() {
    local step_sha target_after lib_after selftest_after
    step_sha="$(sha256sum "$STEP_FILE" 2>/dev/null | awk '{print $1}' || true)"
    target_after="$(sha256sum "$TARGET" 2>/dev/null | awk '{print $1}' || true)"
    lib_after="$(sha256sum "$CONTRACT_LIB" 2>/dev/null | awk '{print $1}' || true)"
    selftest_after="$(sha256sum "$SELFTEST" 2>/dev/null | awk '{print $1}' || true)"
    python3 - "$FACTS" <<PY
import json,sys
p=sys.argv[1]
data={
"step_id":"$STEP_ID","result":"$RESULT","stop_reason":"$STOP_REASON","current_phase":"$CURRENT_PHASE",
"copy_verify":"$COPY_VERIFY","step_sha256":"$step_sha","expected_step_sha256":"$EXPECTED_INSTALLER_SHA256",
"step_was_not_started":"$STEP_WAS_NOT_STARTED","core_change_complete":"$CORE_CHANGE_COMPLETE",
"core_change_repeated":"$CORE_CHANGE_REPEATED","target_installer_rerun":"$TARGET_INSTALLER_RERUN",
"machine_git_complete":"$MACHINE_GIT_COMPLETE","router_machine_close_rerun":"$ROUTER_MACHINE_CLOSE_RERUN",
"vm130_source_publication_complete":"$VM130_SOURCE_PUBLICATION_COMPLETE",
"step_report_publication_complete":"$STEP_REPORT_PUBLICATION_COMPLETE","core_rolled_back":"$CORE_ROLLED_BACK",
"selftest_pass":"$SELFTEST_PASS","http_verify_pass":"$HTTP_VERIFY_PASS","runtime_impact":"$RUNTIME_IMPACT",
"target_sha256_after":"$target_after","contract_library_sha256":"$lib_after","selftest_sha256":"$selftest_after",
"step_report_url":"$STEP_REPORT_URL","vm130_source_url":"$VM130_SOURCE_URL",
"local_m07_plan_url":"$LOCAL_M07_PLAN_URL","global_project_plan_url":"$GLOBAL_PROJECT_PLAN_URL",
"access_map_url":"$ACCESS_MAP_URL","vm100_public_url":"$VM100_PUBLIC_URL","vm101_public_url":"$VM101_PUBLIC_URL",
"vm121_public_url":"$VM121_PUBLIC_URL","vm101_model_url":"$VM101_MODEL_URL","vm101_methods_url":"$VM101_METHODS_URL"
}
with open(p,"w",encoding="utf-8") as f: json.dump(data,f,ensure_ascii=False,indent=2,sort_keys=True); f.write("\n")
PY
}

write_report() {
    cat > "$REPORT" <<EOF
RESULT=$RESULT
STEP_ID=$STEP_ID
STOP_REASON=$STOP_REASON
CURRENT_PHASE=$CURRENT_PHASE
SCOPE=VM130 workflow infrastructure only
CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE
CORE_CHANGE_REPEATED=$CORE_CHANGE_REPEATED
TARGET_INSTALLER_RERUN=$TARGET_INSTALLER_RERUN
MACHINE_GIT_COMPLETE=$MACHINE_GIT_COMPLETE
ROUTER_MACHINE_CLOSE_RERUN=$ROUTER_MACHINE_CLOSE_RERUN
VM130_SOURCE_PUBLICATION_COMPLETE=$VM130_SOURCE_PUBLICATION_COMPLETE
STEP_REPORT_PUBLICATION_COMPLETE=$STEP_REPORT_PUBLICATION_COMPLETE
CORE_ROLLED_BACK=$CORE_ROLLED_BACK
SELFTEST_PASS=$SELFTEST_PASS
HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS
LIVE_ROUTER_MACHINE_CLOSE_RUN=false
VM101_RUNTIME_CHANGE=false
RUNTIME_IMPACT=false
STEP_REPORT_URL=$STEP_REPORT_URL
LOCAL_M07_PLAN_URL=$LOCAL_M07_PLAN_URL
GLOBAL_PROJECT_PLAN_URL=$GLOBAL_PROJECT_PLAN_URL
ACCESS_MAP_URL=$ACCESS_MAP_URL
VM100_PUBLIC_URL=$VM100_PUBLIC_URL
VM101_PUBLIC_URL=$VM101_PUBLIC_URL
VM121_PUBLIC_URL=$VM121_PUBLIC_URL
VM101_MODEL_URL=$VM101_MODEL_URL
VM101_METHODS_URL=$VM101_METHODS_URL
VM130_SOURCE_URL=$VM130_SOURCE_URL
LATEST_ROOT_URL=$LATEST_ROOT_URL
OLD_ROOT_URL=$OLD_ROOT_URL
FACTS_URL=$FACTS_URL
VERIFY_URL=$VERIFY_URL
ROLLBACK_URL=$ROLLBACK_URL
PUBLIC_OBJECT_KIND=$PUBLIC_OBJECT_KIND
PREVIOUS_MOVED_COUNT=$PREVIOUS_MOVED_COUNT
COPY_VERIFY=$COPY_VERIFY
STEP_SHA256=$(sha256sum "$STEP_FILE" | awk '{print $1}')
EOF
}

write_verify() {
    {
        echo "BUNDLE_SHA256=$(sha256sum "$BUNDLE_COPY" | awk '{print $1}')"
        echo "INSTALLER_SHA256=$(sha256sum "$STEP_FILE" | awk '{print $1}')"
        echo "COPY_VERIFY=$COPY_VERIFY"
        echo "CURRENT_PHASE=$CURRENT_PHASE"
        echo "CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE"
        echo "SELFTEST_PASS=$SELFTEST_PASS"
        echo "VM130_SOURCE_PUBLICATION_COMPLETE=$VM130_SOURCE_PUBLICATION_COMPLETE"
        echo "HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS"
        [[ ! -f "$AFTER_INFO" ]] || cat "$AFTER_INFO"
    } > "$VERIFY"
}

print_final() {
    write_facts
    write_verify
    write_report
    {
        echo "RESULT=$RESULT"
        echo "STEP_REPORT_URL=${STEP_REPORT_URL:-PENDING_NOT_PUBLISHED}"
        echo "LOCAL_M07_PLAN_URL=$LOCAL_M07_PLAN_URL"
        echo "GLOBAL_PROJECT_PLAN_URL=$GLOBAL_PROJECT_PLAN_URL"
        echo "ACCESS_MAP_URL=$ACCESS_MAP_URL"
        echo "VM100_PUBLIC_URL=$VM100_PUBLIC_URL"
        echo "VM101_PUBLIC_URL=$VM101_PUBLIC_URL"
        echo "VM121_PUBLIC_URL=$VM121_PUBLIC_URL"
        echo "VM101_MODEL_URL=$VM101_MODEL_URL"
        echo "VM101_METHODS_URL=$VM101_METHODS_URL"
        echo "VM130_SOURCE_URL=$VM130_SOURCE_URL"
        echo "LATEST_ROOT_URL=$LATEST_ROOT_URL"
        echo "OLD_ROOT_URL=$OLD_ROOT_URL"
        echo "FACTS_URL=${FACTS_URL:-PENDING_NOT_PUBLISHED}"
        echo "VERIFY_URL=${VERIFY_URL:-PENDING_NOT_PUBLISHED}"
        echo "ROLLBACK_URL=${ROLLBACK_URL:-PENDING_NOT_PUBLISHED}"
        echo "PUBLIC_OBJECT_KIND=${PUBLIC_OBJECT_KIND:-step-report}"
        echo "PREVIOUS_MOVED_COUNT=${PREVIOUS_MOVED_COUNT:-unknown}"
        echo "COPY_VERIFY=$COPY_VERIFY"
        echo "STEP_SHA256=$(sha256sum "$STEP_FILE" | awk '{print $1}')"
        echo "RUNTIME_IMPACT=false"
    } >&3
}

restore_code() {
    set +e
    [[ -f "$BACKUP_DIR/router-machine-close" ]] && cp -a "$BACKUP_DIR/router-machine-close" "$TARGET.tmp.rollback" && mv -f "$TARGET.tmp.rollback" "$TARGET"
    if [[ -f "$BACKUP_DIR/router-machine-close-contract.sh" ]]; then cp -a "$BACKUP_DIR/router-machine-close-contract.sh" "$CONTRACT_LIB.tmp.rollback" && mv -f "$CONTRACT_LIB.tmp.rollback" "$CONTRACT_LIB"; else rm -f "$CONTRACT_LIB"; fi
    if [[ -f "$BACKUP_DIR/router-machine-close-contract-selftest" ]]; then cp -a "$BACKUP_DIR/router-machine-close-contract-selftest" "$SELFTEST.tmp.rollback" && mv -f "$SELFTEST.tmp.rollback" "$SELFTEST"; else rm -f "$SELFTEST"; fi
    CORE_ROLLED_BACK="true"
    set -e
}

publish_stop_best_effort() {
    set +e
    write_facts; write_verify; write_report
    if [[ -x "$PUBLISHER" ]]; then
        rm -rf "$SAFE_PUBLISH"; mkdir -p "$SAFE_PUBLISH"
        for f in "$STEP_FILE" "$REPORT" "$FACTS" "$VERIFY" "$ROLLBACK" "$MAIN_LOG" "$PROGRESS_LOG" "$TRANSFER_VERIFY" "$SYSTEM_MODEL" "$METHODS" "$ACCESS_ROUTES" "$BEFORE_INFO" "$AFTER_INFO" "$FIXTURE_LOG" "$INSTALLED_TEST_LOG" "$SOURCE_PUBLISH_LOG" "$PHASES"; do [[ -f "$f" ]] && cp -a "$f" "$SAFE_PUBLISH/$(basename "$f")"; done
        "$PUBLISHER" "${STEP_LABEL}_stop" "$SAFE_PUBLISH"/* > "$STEP_PUBLISH_LOG" 2>&1
        if [[ $? -eq 0 ]]; then
            STEP_REPORT_URL="$(awk -F= '$1=="STEP_REPORT_URL"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"
            PUBLIC_OBJECT_KIND="$(awk -F= '$1=="PUBLIC_OBJECT_KIND"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"
            PREVIOUS_MOVED_COUNT="$(awk -F= '$1=="PREVIOUS_MOVED_COUNT"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"
            FACTS_URL="${STEP_REPORT_URL}facts.json"; VERIFY_URL="${STEP_REPORT_URL}verify.txt"; ROLLBACK_URL="${STEP_REPORT_URL}rollback.sh"
        fi
    fi
    set -e
}

stop_step() {
    local result="$1" reason="$2"
    trap - ERR
    RESULT="$result"; STOP_REASON="$reason"
    if [[ "$INSTALLED" == true && "$VM130_SOURCE_PUBLICATION_COMPLETE" == false ]]; then restore_code; fi
    publish_stop_best_effort
    print_final
    exit 1
}
trap 'stop_step "STOP_R15C_UNEXPECTED_ERROR" "phase=${CURRENT_PHASE};line=${LINENO};rc=$?"' ERR

write_docs

phase transfer_verification
ACTUAL_BUNDLE_SHA256="$(sha256sum "$BUNDLE_COPY" | awk '{print $1}')"
ACTUAL_INSTALLER_SHA256="$(sha256sum "$STEP_FILE" | awk '{print $1}')"
[[ "$ACTUAL_BUNDLE_SHA256" == "$EXPECTED_BUNDLE_SHA256" ]] || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "bundle_sha256_mismatch"
[[ "$ACTUAL_INSTALLER_SHA256" == "$EXPECTED_INSTALLER_SHA256" ]] || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "installer_sha256_mismatch"
( cd "$BUNDLE_DIR" && sha256sum -c manifest.sha256 ) > "$STEP_DIR/manifest-check.log" 2>&1 || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "manifest_failed"
bash -n "$STEP_FILE" || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "installer_syntax"
bash "$BUNDLE_DIR/tests/test-bundle-layout.sh" > "$STEP_DIR/layout-test.log" 2>&1 || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "layout_fixture"
bash "$BUNDLE_DIR/tests/test-contract.sh" > "$FIXTURE_LOG" 2>&1 || stop_step "STOP_COPY_OR_TRANSFER_ERROR" "contract_fixture"
COPY_VERIFY="PASS"; STEP_WAS_NOT_STARTED="false"
cat > "$TRANSFER_VERIFY" <<EOF
EXPECTED_BUNDLE_SHA256=$EXPECTED_BUNDLE_SHA256
ACTUAL_BUNDLE_SHA256=$ACTUAL_BUNDLE_SHA256
EXPECTED_INSTALLER_SHA256=$EXPECTED_INSTALLER_SHA256
ACTUAL_INSTALLER_SHA256=$ACTUAL_INSTALLER_SHA256
MANIFEST_VERIFY=PASS
SYNTAX_VERIFY=PASS
FIXTURE_VERIFY=PASS
COPY_VERIFY=PASS
STEP_SHA256=$ACTUAL_INSTALLER_SHA256
EOF

phase target_preflight
for cmd in bash awk sed grep find tar gzip base64 sha256sum cmp diff mktemp stat curl flock python3 tee sort xargs readlink dirname basename cp mv rm chmod mkdir date hostname systemctl install; do command -v "$cmd" >/dev/null 2>&1 || stop_step "STOP_PREFLIGHT_REQUIRED_COMMAND_MISSING" "missing_command=$cmd"; done
[[ "$(hostname)" == "router-ops" ]] || stop_step "STOP_PREFLIGHT_WRONG_HOST" "hostname=$(hostname)"
[[ -x "$PUBLISHER" ]] || stop_step "STOP_PREFLIGHT_PUBLISHER_MISSING" "$PUBLISHER"
[[ "$(sha256sum "$PUBLISHER" | awk '{print $1}')" == "$EXPECTED_PUBLISHER_SHA256" ]] || stop_step "STOP_PREFLIGHT_PUBLISHER_SHA_MISMATCH" "publisher"
[[ -r "$PUBLIC_TOKEN_FILE" ]] || stop_step "STOP_PREFLIGHT_PUBLIC_TOKEN_MISSING" "$PUBLIC_TOKEN_FILE"
systemctl is-active --quiet caddy || stop_step "STOP_PREFLIGHT_CADDY_INACTIVE" "caddy"
[[ -w "$BIN" ]] || stop_step "STOP_PREFLIGHT_BIN_NOT_WRITABLE" "$BIN"
mkdir -p "$LIB"; [[ -w "$LIB" ]] || stop_step "STOP_PREFLIGHT_LIB_NOT_WRITABLE" "$LIB"
[[ "$(readlink -f /usr/local/bin/router-machine-close 2>/dev/null || true)" == "$TARGET" ]] || stop_step "STOP_PREFLIGHT_ENTRYPOINT_MISMATCH" "/usr/local/bin/router-machine-close"
[[ "$(sha256sum "$TARGET" | awk '{print $1}')" == "$EXPECTED_CURRENT_WRAPPER_SHA256" ]] || stop_step "STOP_PREFLIGHT_CURRENT_WRAPPER_SHA_MISMATCH" "unexpected_live_version"
while read -r sha rel; do live="/${rel#./}"; [[ -f "$live" ]] || stop_step "STOP_PREFLIGHT_R14B2_SOURCE_MISSING" "$live"; [[ "$(sha256sum "$live" | awk '{print $1}')" == "$sha" ]] || stop_step "STOP_PREFLIGHT_R14B2_SOURCE_SHA_MISMATCH" "$live"; done < "$BUNDLE_DIR/reference/vm130-r14b2-source-manifest.sha256"

TARGET_SHA_BEFORE="$(sha256sum "$TARGET" | awk '{print $1}')"
{
 echo "TARGET_SHA256_BEFORE=$TARGET_SHA_BEFORE"; echo "PUBLISHER_SHA256=$(sha256sum "$PUBLISHER" | awk '{print $1}')"; echo "ENTRYPOINT=$(readlink -f /usr/local/bin/router-machine-close)"; echo "VM130_SOURCE_URL_BEFORE=$VM130_SOURCE_URL";
} > "$BEFORE_INFO"
cp -a "$TARGET" "$BACKUP_DIR/router-machine-close"
[[ ! -e "$CONTRACT_LIB" ]] || cp -a "$CONTRACT_LIB" "$BACKUP_DIR/router-machine-close-contract.sh"
[[ ! -e "$SELFTEST" ]] || cp -a "$SELFTEST" "$BACKUP_DIR/router-machine-close-contract-selftest"

TOKEN="$(cat "$PUBLIC_TOKEN_FILE")"
LATEST_LOCAL="$BASE/public/r/$TOKEN/latest"
OLD_LOCAL="$BASE/public/r/$TOKEN/old"
find "$LATEST_LOCAL" -mindepth 1 -maxdepth 1 -type d -name '*_vm130_router_ops_source_snapshot*' -printf '%f\n' | sort > "$STEP_DIR/previous-vm130-source-folders.txt"

cat > "$ROLLBACK" <<EOF
#!/usr/bin/env bash
set -Eeuo pipefail
TARGET='$TARGET'; CONTRACT_LIB='$CONTRACT_LIB'; SELFTEST='$SELFTEST'; BACKUP_DIR='$BACKUP_DIR'
LATEST_LOCAL='$LATEST_LOCAL'; OLD_LOCAL='$OLD_LOCAL'; NEW_FILE='$STEP_DIR/new-source-folder.txt'; PREV_FILE='$STEP_DIR/previous-vm130-source-folders.txt'; REINDEX='$BIN/router-public-reindex'
cp -a "\$BACKUP_DIR/router-machine-close" "\$TARGET.tmp.rollback"; mv -f "\$TARGET.tmp.rollback" "\$TARGET"
if [[ -f "\$BACKUP_DIR/router-machine-close-contract.sh" ]]; then cp -a "\$BACKUP_DIR/router-machine-close-contract.sh" "\$CONTRACT_LIB.tmp.rollback"; mv -f "\$CONTRACT_LIB.tmp.rollback" "\$CONTRACT_LIB"; else rm -f "\$CONTRACT_LIB"; fi
if [[ -f "\$BACKUP_DIR/router-machine-close-contract-selftest" ]]; then cp -a "\$BACKUP_DIR/router-machine-close-contract-selftest" "\$SELFTEST.tmp.rollback"; mv -f "\$SELFTEST.tmp.rollback" "\$SELFTEST"; else rm -f "\$SELFTEST"; fi
if [[ -s "\$NEW_FILE" ]]; then NEW="\$(cat "\$NEW_FILE")"; CURRENT="\$(find "\$LATEST_LOCAL" -mindepth 1 -maxdepth 1 -type d -name '*_vm130_router_ops_source_snapshot*' -printf '%f\n')"; if [[ "\$CURRENT" == "\$NEW" ]]; then mv "\$LATEST_LOCAL/\$NEW" "\$OLD_LOCAL/\$NEW"; while IFS= read -r P; do [[ -n "\$P" && -d "\$OLD_LOCAL/\$P" ]] && mv "\$OLD_LOCAL/\$P" "\$LATEST_LOCAL/\$P"; done < "\$PREV_FILE"; "\$REINDEX"; else echo PUBLICATION_ROLLBACK=SKIPPED_NEWER_SOURCE_PRESENT; fi; fi
echo RESULT=PASS_R15C_ROLLBACK
EOF
chmod 700 "$ROLLBACK"

phase target_core
for rel in opt/router-ops/bin/router-machine-close opt/router-ops/lib/router-machine-close-contract.sh opt/router-ops/bin/router-machine-close-contract-selftest; do src="$BUNDLE_DIR/payload/$rel"; dst="/$rel"; install -d -m 0755 "$(dirname "$dst")"; mode=0644; [[ "$rel" == opt/router-ops/bin/* ]] && mode=0755; install -m "$mode" "$src" "$dst.tmp.$STEP_ID"; bash -n "$dst.tmp.$STEP_ID"; mv -f "$dst.tmp.$STEP_ID" "$dst"; done
INSTALLED="true"; CORE_CHANGE_COMPLETE="true"

phase target_postcheck
bash -n "$TARGET"; bash -n "$CONTRACT_LIB"; bash -n "$SELFTEST"
"$SELFTEST" > "$INSTALLED_TEST_LOG" 2>&1 || stop_step "STOP_R15C_INSTALLED_FIXTURE_FAILED" "selftest"
grep -qx 'RESULT=PASS_ROUTER_MACHINE_CLOSE_CONTRACT_SELFTEST' "$INSTALLED_TEST_LOG" || stop_step "STOP_R15C_INSTALLED_FIXTURE_FAILED" "pass_marker"
SELFTEST_PASS="true"
[[ "$(readlink -f /usr/local/bin/router-machine-close)" == "$TARGET" ]] || stop_step "STOP_R15C_ENTRYPOINT_CHANGED" "entrypoint"
TARGET_SHA_AFTER="$(sha256sum "$TARGET" | awk '{print $1}')"; [[ "$TARGET_SHA_AFTER" != "$TARGET_SHA_BEFORE" ]] || stop_step "STOP_R15C_NO_EFFECT" "wrapper_unchanged"
{
 echo "TARGET_SHA256_AFTER=$TARGET_SHA_AFTER"; echo "CONTRACT_LIB_SHA256_AFTER=$(sha256sum "$CONTRACT_LIB" | awk '{print $1}')"; echo "SELFTEST_SHA256_AFTER=$(sha256sum "$SELFTEST" | awk '{print $1}')"; echo "CANDIDATE_SELFTEST=PASS"; echo "INSTALLED_SELFTEST=PASS"; echo "LIVE_ROUTER_MACHINE_CLOSE_RUN=false";
} > "$AFTER_INFO"
diff -u "$BACKUP_DIR/router-machine-close" "$TARGET" > "$DIFF_FILE" || true

phase source_build
SOURCE_ROOT="$SOURCE_WORK/root"; mkdir -p "$SOURCE_ROOT"
for live in /etc/caddy/Caddyfile "$BIN/router-public-reindex" "$TARGET" "$BIN/router-vm100-git-source-publish" "$BIN/router-vm101-git-source-publish" "$PUBLISHER" "$BIN/router-vm121-git-source-publish" "$CONTRACT_LIB" "$SELFTEST"; do dst="$SOURCE_ROOT$live"; mkdir -p "$(dirname "$dst")"; cp -a "$live" "$dst"; done
SOURCE_MANIFEST="$SOURCE_WORK/vm130-source-manifest.sha256"
( cd "$SOURCE_ROOT" && find . -type f -print0 | sort -z | xargs -0 sha256sum ) > "$SOURCE_MANIFEST"
SOURCE_ARCHIVE="$SOURCE_WORK/vm130-router-ops-r15c-contract-fix.tar.gz"; SOURCE_B64="$SOURCE_ARCHIVE.b64.txt"; SOURCE_SHA_FILE="$SOURCE_ARCHIVE.sha256"
tar -C "$SOURCE_ROOT" -czf "$SOURCE_ARCHIVE" .
SOURCE_ARCHIVE_SHA="$(sha256sum "$SOURCE_ARCHIVE" | awk '{print $1}')"; printf '%s  %s\n' "$SOURCE_ARCHIVE_SHA" "$(basename "$SOURCE_ARCHIVE")" > "$SOURCE_SHA_FILE"; base64 -w 76 "$SOURCE_ARCHIVE" > "$SOURCE_B64"
ROUND="$SOURCE_WORK/roundtrip"; mkdir -p "$ROUND"; base64 -d "$SOURCE_B64" > "$ROUND/archive.tar.gz"; gzip -t "$ROUND/archive.tar.gz"; mkdir "$ROUND/extract"; tar -xzf "$ROUND/archive.tar.gz" -C "$ROUND/extract"; ( cd "$ROUND/extract" && sha256sum -c "$SOURCE_MANIFEST" ) > "$SOURCE_WORK/roundtrip-manifest.log" 2>&1
while IFS= read -r f; do case "$(head -n1 "$f" 2>/dev/null || true)" in '#!/usr/bin/env bash'|'#!/bin/bash') bash -n "$f";; '#!/bin/sh') sh -n "$f";; esac; done < <(find "$ROUND/extract" -type f | sort)
cat > "$SOURCE_WORK/report.txt" <<EOF
RESULT=PASS_VM130_SOURCE_BUILT
STEP_ID=$STEP_ID
ARCHIVE=$(basename "$SOURCE_ARCHIVE")
ARCHIVE_SHA256=$SOURCE_ARCHIVE_SHA
FILE_COUNT=$(wc -l < "$SOURCE_MANIFEST" | tr -d ' ')
ROUNDTRIP_VERIFY=PASS
SYNTAX_VERIFY=PASS
RUNTIME_IMPACT=false
EOF
cat > "$SOURCE_WORK/facts.json" <<EOF
{"result":"PASS_VM130_SOURCE_BUILT","step_id":"$STEP_ID","archive":"$(basename "$SOURCE_ARCHIVE")","archive_sha256":"$SOURCE_ARCHIVE_SHA","file_count":$(wc -l < "$SOURCE_MANIFEST" | tr -d ' '),"roundtrip_verify":true,"syntax_verify":true,"runtime_impact":false}
EOF
cat > "$SOURCE_WORK/verify.txt" <<EOF
ARCHIVE_SHA256=$SOURCE_ARCHIVE_SHA
GZIP_TEST=PASS
BASE64_DECODE=PASS
MANIFEST_CHECK=PASS
SYNTAX_CHECK=PASS
EOF

phase source_publication
"$PUBLISHER" "$SOURCE_LABEL" "$SOURCE_WORK/report.txt" "$SOURCE_WORK/facts.json" "$SOURCE_WORK/verify.txt" "$SOURCE_ARCHIVE" "$SOURCE_B64" "$SOURCE_SHA_FILE" "$SOURCE_MANIFEST" > "$SOURCE_PUBLISH_LOG" 2>&1 || stop_step "STOP_R15C_VM130_SOURCE_PUBLICATION_FAILED" "publisher_rc"
SOURCE_PUBLISHED_DIR="$(awk -F= '$1=="PUBLISHED_DIR"{print $2}' "$SOURCE_PUBLISH_LOG" | tail -1)"; SOURCE_PUBLIC_OBJECT_KIND="$(awk -F= '$1=="PUBLIC_OBJECT_KIND"{print $2}' "$SOURCE_PUBLISH_LOG" | tail -1)"; SOURCE_PREVIOUS_MOVED_COUNT="$(awk -F= '$1=="PREVIOUS_MOVED_COUNT"{print $2}' "$SOURCE_PUBLISH_LOG" | tail -1)"; VM130_SOURCE_URL="$(awk -F= '$1=="VM130_SOURCE_URL"{print $2}' "$SOURCE_PUBLISH_LOG" | tail -1)"
[[ -d "$SOURCE_PUBLISHED_DIR" && "$SOURCE_PUBLIC_OBJECT_KIND" == "vm130-source" && "$SOURCE_PREVIOUS_MOVED_COUNT" == "1" ]] || stop_step "STOP_R15C_VM130_SOURCE_PUBLICATION_CONTRACT" "kind_or_count"
basename "$SOURCE_PUBLISHED_DIR" > "$STEP_DIR/new-source-folder.txt"
[[ "$(find "$LATEST_LOCAL" -mindepth 1 -maxdepth 1 -type d -name '*_vm130_router_ops_source_snapshot*' -printf '.' | wc -c)" -eq 1 ]] || stop_step "STOP_R15C_VM130_SOURCE_CURRENT_COUNT" "not_one"
VM130_SOURCE_PUBLICATION_COMPLETE="true"

phase source_http_verification
SOURCE_INDEX_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$VM130_SOURCE_URL")"; SOURCE_ARCHIVE_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o "$STEP_DIR/http-source.tar.gz" -w '%{http_code}' "${VM130_SOURCE_URL}$(basename "$SOURCE_ARCHIVE")")"
[[ "$SOURCE_INDEX_CODE" == 200 && "$SOURCE_ARCHIVE_CODE" == 200 && "$(sha256sum "$STEP_DIR/http-source.tar.gz" | awk '{print $1}')" == "$SOURCE_ARCHIVE_SHA" ]] || stop_step "STOP_R15C_VM130_SOURCE_HTTP_FAILED" "http_or_sha"

phase step_report_preparation
RESULT="PASS_R15C_ROUTER_MACHINE_CLOSE_CONTRACT_FIXED"; STOP_REASON="none"; write_facts; write_verify; write_report
rm -rf "$SAFE_PUBLISH"; mkdir -p "$SAFE_PUBLISH"
for f in "$STEP_FILE" "$REPORT" "$FACTS" "$VERIFY" "$ROLLBACK" "$MAIN_LOG" "$PROGRESS_LOG" "$TRANSFER_VERIFY" "$SYSTEM_MODEL" "$METHODS" "$ACCESS_ROUTES" "$BEFORE_INFO" "$AFTER_INFO" "$DIFF_FILE" "$FIXTURE_LOG" "$INSTALLED_TEST_LOG" "$SOURCE_PUBLISH_LOG" "$PHASES"; do [[ -f "$f" ]] && cp -a "$f" "$SAFE_PUBLISH/$(basename "$f")"; done

phase step_report_publication
"$PUBLISHER" "$STEP_LABEL" "$SAFE_PUBLISH"/* > "$STEP_PUBLISH_LOG" 2>&1 || stop_step "STOP_R15C_STEP_REPORT_PUBLICATION_FAILED" "publisher_rc"
STEP_PUBLISHED_DIR="$(awk -F= '$1=="PUBLISHED_DIR"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"; STEP_REPORT_URL="$(awk -F= '$1=="STEP_REPORT_URL"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"; PUBLIC_OBJECT_KIND="$(awk -F= '$1=="PUBLIC_OBJECT_KIND"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"; PREVIOUS_MOVED_COUNT="$(awk -F= '$1=="PREVIOUS_MOVED_COUNT"{print $2}' "$STEP_PUBLISH_LOG" | tail -1)"
[[ -d "$STEP_PUBLISHED_DIR" && "$PUBLIC_OBJECT_KIND" == step-report ]] || stop_step "STOP_R15C_STEP_REPORT_CONTRACT" "kind_or_dir"
FACTS_URL="${STEP_REPORT_URL}facts.json"; VERIFY_URL="${STEP_REPORT_URL}verify.txt"; ROLLBACK_URL="${STEP_REPORT_URL}rollback.sh"; STEP_REPORT_PUBLICATION_COMPLETE="true"

phase external_http_verification
ROOT_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' https://reports.secret-studio.ru/)"; LATEST_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$LATEST_ROOT_URL")"; OLD_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$OLD_ROOT_URL")"; STEP_CODE_HTTP="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o "$STEP_DIR/http-step-code.sh" -w '%{http_code}' "${STEP_REPORT_URL}step-code.sh")"; FACTS_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$FACTS_URL")"; VERIFY_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$VERIFY_URL")"; ROLLBACK_CODE="$(curl --resolve reports.secret-studio.ru:443:10.71.100.84 -sS -o /dev/null -w '%{http_code}' "$ROLLBACK_URL")"
{
 echo "ROOT_CODE=$ROOT_CODE"; echo "LATEST_CODE=$LATEST_CODE"; echo "OLD_CODE=$OLD_CODE"; echo "STEP_CODE_HTTP=$STEP_CODE_HTTP"; echo "FACTS_CODE=$FACTS_CODE"; echo "VERIFY_CODE=$VERIFY_CODE"; echo "ROLLBACK_CODE=$ROLLBACK_CODE";
} > "$HTTP_LOG"
[[ "$ROOT_CODE" == 302 || "$ROOT_CODE" == 200 ]]; [[ "$LATEST_CODE" == 200 && "$OLD_CODE" == 200 && "$STEP_CODE_HTTP" == 200 && "$FACTS_CODE" == 200 && "$VERIFY_CODE" == 200 && "$ROLLBACK_CODE" == 200 ]] || stop_step "STOP_R15C_HTTP_FAILED" "codes"
[[ "$(sha256sum "$STEP_DIR/http-step-code.sh" | awk '{print $1}')" == "$EXPECTED_INSTALLER_SHA256" ]] || stop_step "STOP_R15C_PUBLISHED_STEP_SHA_MISMATCH" "step-code"
HTTP_VERIFY_PASS="true"

phase final_artifact_sync
write_facts; write_verify; write_report
cp -a "$REPORT" "$FACTS" "$VERIFY" "$HTTP_LOG" "$STEP_PUBLISHED_DIR/"; chmod 644 "$STEP_PUBLISHED_DIR/report.txt" "$STEP_PUBLISHED_DIR/facts.json" "$STEP_PUBLISHED_DIR/verify.txt" "$STEP_PUBLISHED_DIR/http-verify.log"
RESULT="PASS_R15C_ROUTER_MACHINE_CLOSE_CONTRACT_FIXED"
phase complete
print_final
