#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; BUNDLE_ROOT="${BUNDLE_ROOT:-$(cd "$SCRIPT_DIR/.." && pwd)}"; export BUNDLE_ROOT
BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"; INCOMING="${ROUTER_STEP_INCOMING:-/home/ops/incoming}"; WORKFLOW_LIB="${ROUTER_STEP_WORKFLOW_LIB:-$BASE/lib/router-step-workflow.sh}"; TRANSITION_LIB="${ROUTER_RUNTIME_TRANSITION_LIB:-$BASE/lib/router-runtime-transition.sh}"; FINALIZER="${ROUTER_STEP_FINALIZE_BIN:-$BASE/bin/router-step-finalize}"; SAFE_PAYLOAD="${ROUTER_PUBLIC_SAFE_PAYLOAD_BIN:-$BASE/bin/router-public-safe-payload}"; MACHINE_CLOSE="${ROUTER_MACHINE_CLOSE_SAFE_BIN:-$BASE/bin/router-machine-close-safe}"; RUN_TARGET="${ROUTER_P28R2_RUN_TARGET:-$BUNDLE_ROOT/scripts/run-target.sh}"
release_env="$("$BASE/bin/router-release-contract" env --root "$BUNDLE_ROOT")"; eval "$release_env"; STEP_ID="$ROUTER_RELEASE_STEP_ID"; TARGET_PACKAGE_SHA256="$ROUTER_RELEASE_TARGET_PACKAGE_SHA256"
RUN_ID="${ROUTER_P28R2_RUN_ID:-$(date -u +%Y%m%d-%H%M%S)-$$}"; [[ "$RUN_ID" =~ ^[A-Za-z0-9-]+$ ]]; RUN_DIR="${ROUTER_STEP_RUN_DIR:-$BASE/state/step-runs/$STEP_ID/$RUN_ID}"; EVIDENCE_DIR="$RUN_DIR/evidence"; REPORT_DIR="$RUN_DIR/report"; PUBLIC_PAYLOAD="$RUN_DIR/public-payload"; CURRENT_FILE="$RUN_DIR/workflow-current.txt"; EVENTS_FILE="$RUN_DIR/workflow-events.tsv"; TRANSITION_FILE="$RUN_DIR/runtime-transition.txt"; FINAL_ENV="$RUN_DIR/finalize.txt"; LOCK_FILE="${ROUTER_STEP_LOCK_FILE:-$BASE/state/locks/${STEP_ID}.lock}"
CURRENT_PHASE=preflight; BACKUP_READY=false; CORE_CHANGE_COMPLETE=false; ROLLBACK_STATUS=not_required; LATEST_ARCHIVE=not_created; STOP_COMMAND=none
source "$WORKFLOW_LIB"; source "$TRANSITION_LIB"; mkdir -p "$RUN_DIR" "$EVIDENCE_DIR" "$REPORT_DIR" "$(dirname "$LOCK_FILE")"; exec 9>"$LOCK_FILE"; flock -n 9 || { echo RESULT=STOP_P28R2_R01_STEP_ALREADY_RUNNING; echo STEP_WAS_NOT_STARTED=true; exit 75; }
router_step_workflow_init "$CURRENT_FILE" "$EVENTS_FILE" preflight backup apply postcheck source_publish report_build finalization latest; router_runtime_transition_init "$TRANSITION_FILE"; router_runtime_transition_set "$TRANSITION_FILE" TRANSFER_VERIFIED true
rollback_now(){ [ "$BACKUP_READY" = true ] || return 0; [ "$CORE_CHANGE_COMPLETE" = false ] || return 0; router_runtime_transition_rollback_allowed "$TRANSITION_FILE" || return 0; "$RUN_TARGET" rollback "$RUN_ID" "$TARGET_PACKAGE_SHA256" > "$EVIDENCE_DIR/rollback.txt" 2>&1 || return $?; grep -Fqx RESULT=PASS_P28R2_R01_ROLLBACK "$EVIDENCE_DIR/rollback.txt"; }
build_report(){ local result="$1" phase="$2" rc="$3" line="$4"; python3 "$BUNDLE_ROOT/scripts/build-report.py" --bundle "$BUNDLE_ROOT" --run-dir "$RUN_DIR" --result "$result" --phase "$phase" --rc "$rc" --line "$line" --core-complete "$CORE_CHANGE_COMPLETE" --rollback-status "$ROLLBACK_STATUS"; }
publish_report(){ local args=() file; for file in report.txt facts.json facts-public.html verify-public.html rollback-public.html release-info.json installer.sha256 bundle-manifest.sha256 executed-step.sh executed-worker.sh workflow-current.txt workflow-events.tsv; do [[ ! -f "$REPORT_DIR/$file" ]] || args+=("$REPORT_DIR/$file" "$file"); done; for file in preflight backup apply postcheck source-publish rollback; do [[ ! -f "$REPORT_DIR/$file.txt" ]] || args+=("$REPORT_DIR/$file.txt" "$file.txt"); done; "$SAFE_PAYLOAD" "$PUBLIC_PAYLOAD" "${args[@]}" || return $?; "$FINALIZER" --label step_vm101_p28r2_awg_remote_dnat_r01 --payload-dir "$PUBLIC_PAYLOAD" --workflow-current "$CURRENT_FILE" --workflow-events "$EVENTS_FILE" --output-env "$FINAL_ENV" --expect-kind step-report; }
archive_latest(){ router_step_archive_latest_python "$BASE" "$INCOMING" "$(date -u +%Y%m%d-%H%M%S)" > "$EVIDENCE_DIR/latest.txt" 2>&1 || return $?; cat "$EVIDENCE_DIR/latest.txt"; grep -Fqx RESULT=PASS_ROUTER_STEP_ARCHIVE_LATEST "$EVIDENCE_DIR/latest.txt" || return 1; LATEST_ARCHIVE="$(awk -F= '$1=="LATEST_ARCHIVE" {print substr($0,index($0,"=")+1)}' "$EVIDENCE_DIR/latest.txt" | tail -n 1)"; [[ -n "$LATEST_ARCHIVE" ]]; }
stop(){ local line="$1" rc="$2" command="$3" phase="$CURRENT_PHASE"; trap - ERR HUP INT TERM; set +e; STOP_COMMAND="$command"; router_step_phase_fail "$phase" "line=$line rc=$rc" >/dev/null 2>&1; if [[ "$BACKUP_READY" == true && "$CORE_CHANGE_COMPLETE" == false ]]; then if rollback_now; then ROLLBACK_STATUS=restored; else ROLLBACK_STATUS=failed; fi; elif [[ "$CORE_CHANGE_COMPLETE" == true ]]; then ROLLBACK_STATUS=preserved_accepted_core; fi; if router_step_should_publish_stop; then if build_report STOP "$phase" "$rc" "$line"; then publish_report || echo STOP_REPORT_FINALIZATION=FAILED; else echo STOP_REPORT_BUILD=FAILED; fi; else echo NO_SECOND_STOP_REPORT=true; fi; archive_latest || { echo STOP_LATEST_ARCHIVE=FAILED; cat "$EVIDENCE_DIR/latest.txt" 2>/dev/null; }; router_step_emit_stop_evidence STOP_P28R2_R01_VM101_AWG_REMOTE_DNAT "$phase" "$line" "$rc" "$command" VM101 "$CORE_CHANGE_COMPLETE" "$ROLLBACK_STATUS" "$LATEST_ARCHIVE" inspect_run_evidence_and_continue_from_first_unfinished_phase; [[ "$CORE_CHANGE_COMPLETE" != true ]] || echo CONTINUATION_REQUIRED=true; exit "$rc"; }
trap 'stop "$LINENO" "$?" "$BASH_COMMAND"' ERR; trap 'stop "$LINENO" 129 "signal HUP"' HUP; trap 'stop "$LINENO" 130 "signal INT"' INT; trap 'stop "$LINENO" 143 "signal TERM"' TERM
run_target_phase(){ local phase="$1" expected="$2"; CURRENT_PHASE="$phase"; router_step_phase_begin "$phase"; "$RUN_TARGET" "$phase" "$RUN_ID" "$TARGET_PACKAGE_SHA256" > "$EVIDENCE_DIR/$phase.txt" 2>&1; cat "$EVIDENCE_DIR/$phase.txt"; grep -Fqx "RESULT=$expected" "$EVIDENCE_DIR/$phase.txt"; }
run_target_phase preflight PASS_P28R2_R01_PREFLIGHT; router_runtime_transition_set "$TRANSITION_FILE" PREFLIGHT_COMPLETE true; router_step_phase_complete preflight vm101_source_exact_and_only_accepted_51831_firewall_drift_plus_free_51832_verified
run_target_phase backup PASS_P28R2_R01_BACKUP; BACKUP_READY=true; router_runtime_transition_set "$TRANSITION_FILE" BACKUP_READY true; router_step_phase_complete backup vm101_firewall_and_accepted_51831_semantics_backed_up
run_target_phase apply PASS_P28R2_R01_APPLY; router_runtime_transition_set "$TRANSITION_FILE" FILES_INSTALLED true; router_step_phase_complete apply public_udp_51832_dnat_to_vm100_awg_remote_installed
run_target_phase postcheck PASS_P28R2_R01_POSTCHECK; CORE_CHANGE_COMPLETE=true; router_runtime_transition_set "$TRANSITION_FILE" CORE_CHANGE_COMPLETE true; router_runtime_transition_set "$TRANSITION_FILE" ACTIVATION_COMPLETE true; router_step_phase_complete postcheck vm101_51832_dnat_reflection_and_vm100_listener_regression_accepted
CURRENT_PHASE=source_publish; router_step_phase_begin source_publish
"$MACHINE_CLOSE" vm101 "$STEP_ID canonicalize preexisting accepted P28C AWG paid 51831 DNAT and add AWG remote 51832 DNAT; no provider/egress changes" > "$EVIDENCE_DIR/source-publish.txt" 2>&1
cat "$EVIDENCE_DIR/source-publish.txt"; grep -Fqx RESULT=PASS_ROUTER_MACHINE_CLOSE "$EVIDENCE_DIR/source-publish.txt"; router_step_phase_complete source_publish vm101_firewall_source_closed_preexisting_51831_plus_new_51832_with_attribution_preserved
CURRENT_PHASE=report_build; router_step_phase_begin report_build; build_report PASS none 0 0; router_step_phase_complete report_build vm101_awg_remote_dnat_release_evidence_ready
CURRENT_PHASE=finalization; router_step_phase_begin finalization; publish_report; router_step_phase_complete finalization canonical_report_http_verified
CURRENT_PHASE=latest; router_step_phase_begin latest; archive_latest; router_step_phase_complete latest fresh_latest_archive_verified
router_step_workflow_mark_complete; trap - ERR HUP INT TERM; cat "$FINAL_ENV"; cat "$REPORT_DIR/report.txt"; echo RESULT=PASS_P28R2_R01_VM101_AWG_REMOTE_DNAT; echo "RUN_DIR=$RUN_DIR"; echo "LATEST_ARCHIVE=$LATEST_ARCHIVE"
