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

STEP_ID="${STEP_ID:?}"
STEP_DIR="${STEP_DIR:?}"
STEP_SHA256="${STEP_SHA256:?}"

BASE="/opt/router-ops"
DOMAIN="reports.secret-studio.ru"
PUBLISHER="$BASE/bin/router-publish-report"
REINDEX="$BASE/bin/router-public-reindex"
TOKEN_FILE="$BASE/public/.router-public-token"

REPORT="$STEP_DIR/report.txt"
FACTS="$STEP_DIR/facts.json"
VERIFY="$STEP_DIR/verify.txt"
ROLLBACK="$STEP_DIR/rollback.sh"
LOG="$STEP_DIR/main.log"
PROGRESS="$STEP_DIR/progress.log"
MODEL="$STEP_DIR/system-model.txt"
METHODS="$STEP_DIR/methods.txt"
ACCESS="$STEP_DIR/access-routes.txt"
PUBLISH_OUT="$STEP_DIR/publisher-output.txt"
PUBLISH_ERR="$STEP_DIR/publisher-errors.txt"
BEFORE_LATEST="$STEP_DIR/before-latest-step-reports.txt"
BEFORE_OLD="$STEP_DIR/before-old-step-reports.txt"
AFTER_LATEST="$STEP_DIR/after-latest-step-reports.txt"
AFTER_OLD="$STEP_DIR/after-old-step-reports.txt"
MOVED_PREVIOUS="$STEP_DIR/moved-previous-step-reports.txt"
SAFE_DIR="/tmp/router-r05b2-safe-$(date +%s)-$$"

EXPECTED_PUBLISHER_SHA256="e78430b57afbd0ae27fc575fc4de78bb267c76caf04ec935b01e9b2f89840e32"

LOCAL_M07_PLAN_URL="https://$DOMAIN/latest/20260713-193942_local_architecture_plan_vm101_autonomous_hmn_recovery/"
GLOBAL_PROJECT_PLAN_URL="https://$DOMAIN/latest/20260711-123348_global_project_plan_wg_paid/"
ACCESS_MAP_URL="https://$DOMAIN/latest/20260714-092500_access_map_canonical_current/"
VM100_PUBLIC_URL="https://$DOMAIN/latest/20260713-182653_vm100_git_source_097755408853/"
VM101_PUBLIC_URL="https://$DOMAIN/latest/20260713-192042_vm101_git_source_027589515a26/"
VM121_PUBLIC_URL="https://$DOMAIN/latest/20260713-182700_vm121_git_source_93e0e5a31f09/"
VM101_MODEL_URL="https://$DOMAIN/latest/20260713-192030_vm101_model_hmn_download_selector_r13a/"
VM101_METHODS_URL="https://$DOMAIN/latest/20260713-193942_vm101_methods_machine_git_count_contract_r13b/"
VM130_SOURCE_URL="https://$DOMAIN/latest/20260714-085433_vm130_router_ops_source_snapshot_r13f/"
LATEST_ROOT_URL="https://$DOMAIN/latest/"
OLD_ROOT_URL="https://$DOMAIN/old/"

mkdir -p "$SAFE_DIR"
chmod 700 "$SAFE_DIR"
exec > >(tee -a "$LOG") 2>&1

progress() {
    printf '>>> [%s] %s\n' "$(date '+%F %T')" "$*" | tee -a "$PROGRESS"
}

stop_step() {
    local result="$1"
    local reason="$2"
    cat > "$REPORT" <<EOF_STOP
RESULT=$result
STEP_ID=$STEP_ID
STOP_REASON=$reason
STEP_REPORT_URL=PENDING_NOT_PUBLISHED
COPY_VERIFY=PASS
STEP_SHA256=$STEP_SHA256
STEP_WAS_NOT_STARTED=false
RUNTIME_IMPACT=false
EOF_STOP
    printf 'RESULT=%s\n' "$result"
    printf 'STOP_REASON=%s\n' "$reason"
    printf 'STEP_REPORT_URL=PENDING_NOT_PUBLISHED\n'
    printf 'COPY_VERIFY=PASS\n'
    printf 'STEP_SHA256=%s\n' "$STEP_SHA256"
    printf 'STEP_WAS_NOT_STARTED=false\n'
    printf 'RUNTIME_IMPACT=false\n'
    exit 20
}

safe_copy() {
    local src="$1"
    local dst="$2"
    [[ -r "$src" ]] || return 1
    cp -a "$src" "$SAFE_DIR/$dst"
    chmod 0644 "$SAFE_DIR/$dst"
}

progress "preflight"

for cmd in sha256sum python3 curl find awk sed grep comm systemctl; do
    command -v "$cmd" >/dev/null 2>&1 ||
        stop_step "STOP_R05B2_PREFLIGHT_FAILED" "missing_command_$cmd"
done

[[ -x "$PUBLISHER" ]] ||
    stop_step "STOP_R05B2_PREFLIGHT_FAILED" "publisher_missing"

[[ -x "$REINDEX" ]] ||
    stop_step "STOP_R05B2_PREFLIGHT_FAILED" "reindex_missing"

[[ -s "$TOKEN_FILE" ]] ||
    stop_step "STOP_R05B2_PREFLIGHT_FAILED" "token_missing"

PUBLISHER_SHA256="$(sha256sum "$PUBLISHER" | awk '{print $1}')"
[[ "$PUBLISHER_SHA256" == "$EXPECTED_PUBLISHER_SHA256" ]] ||
    stop_step "STOP_LIVE_PUBLISHER_CHANGED" "$PUBLISHER_SHA256"

TOKEN="$(cat "$TOKEN_FILE")"
ROOT="$BASE/public/r/$TOKEN"
LATEST="$ROOT/latest"
OLD="$ROOT/old"

[[ -d "$LATEST" && -d "$OLD" ]] ||
    stop_step "STOP_R05B2_PREFLIGHT_FAILED" "latest_or_old_missing"

progress "capturing exact active publication files"

declare -a SOURCES=(
    "$BASE/bin/router-publish-report"
    "$BASE/bin/router-public-reindex"
    "$BASE/bin/router-public-url"
    "$BASE/bin/router-vm100-git-source-publish"
    "$BASE/bin/router-vm101-git-source-publish"
    "$BASE/bin/router-vm121-git-source-publish"
    "$BASE/bin/router-machine-close"
)

: > "$SAFE_DIR/source-map.txt"
: > "$SAFE_DIR/active-sha256.txt"

for src in "${SOURCES[@]}"; do
    [[ -r "$src" ]] ||
        stop_step "STOP_R05B2_SOURCE_MISSING" "$src"
    name="source-$(basename "$src").txt"
    safe_copy "$src" "$name" ||
        stop_step "STOP_R05B2_SAFE_COPY_FAILED" "$src"
    printf '%s -> %s\n' "$src" "$name" >> "$SAFE_DIR/source-map.txt"
    printf '%s  %s\n' "$(sha256sum "$src" | awk '{print $1}')" "$src" \
        >> "$SAFE_DIR/active-sha256.txt"
done

if [[ -r /etc/caddy/Caddyfile ]]; then
    safe_copy /etc/caddy/Caddyfile "source-Caddyfile.txt"
    printf '%s -> %s\n' /etc/caddy/Caddyfile source-Caddyfile.txt \
        >> "$SAFE_DIR/source-map.txt"
    printf '%s  %s\n' "$(sha256sum /etc/caddy/Caddyfile | awk '{print $1}')" \
        /etc/caddy/Caddyfile >> "$SAFE_DIR/active-sha256.txt"
else
    printf 'MISSING_OR_UNREADABLE=/etc/caddy/Caddyfile\n' \
        > "$SAFE_DIR/caddyfile-status.txt"
fi

progress "capturing state references and service definitions"

grep -RInE \
    'trycloudflare|cloudflared|TRYCF|QUICK_TUNNEL|reports\.secret-studio\.ru|PUBLIC_URL|SOURCE_URL' \
    "$BASE/bin" "$BASE/state" /etc/systemd/system 2>/dev/null \
    > "$SAFE_DIR/publication-reference-locations.txt" || true

grep -RInE \
    'trycloudflare|TRYCF|QUICK_TUNNEL|reports\.secret-studio\.ru|PUBLIC_URL|SOURCE_URL' \
    "$BASE/state" 2>/dev/null \
    > "$SAFE_DIR/state-url-references.txt" || true

{
    systemctl status caddy --no-pager 2>&1 || true
    echo
    systemctl cat caddy 2>&1 || true
} > "$SAFE_DIR/systemd-caddy.txt"

{
    systemctl status cloudflared-quick --no-pager 2>&1 || true
    echo
    systemctl cat cloudflared-quick 2>&1 || true
} > "$SAFE_DIR/systemd-cloudflared-quick.txt"

cp -a "$LATEST/index.html" "$SAFE_DIR/physical-latest-index.html"
cp -a "$OLD/index.html" "$SAFE_DIR/physical-old-index.html"
chmod 0644 "$SAFE_DIR/physical-latest-index.html" "$SAFE_DIR/physical-old-index.html"

curl -sS --connect-timeout 5 --max-time 20 \
    --resolve "$DOMAIN:443:10.71.100.84" \
    "https://$DOMAIN/latest/" > "$SAFE_DIR/served-latest-index.html" ||
    stop_step "STOP_R05B2_HTTP_CAPTURE_FAILED" "latest"

curl -sS --connect-timeout 5 --max-time 20 \
    --resolve "$DOMAIN:443:10.71.100.84" \
    "https://$DOMAIN/old/" > "$SAFE_DIR/served-old-index.html" ||
    stop_step "STOP_R05B2_HTTP_CAPTURE_FAILED" "old"

progress "preparing report artifacts"

find "$LATEST" -mindepth 1 -maxdepth 1 -type d -name '*_step*' -printf '%f\n' |
    LC_ALL=C sort > "$BEFORE_LATEST"

find "$OLD" -mindepth 1 -maxdepth 1 -type d -name '*_step*' -printf '%f\n' |
    LC_ALL=C sort > "$BEFORE_OLD"

cat > "$MODEL" <<EOF_MODEL
AFFECTED_SYSTEM=VM130 publication pipeline evidence
LIVE_SOURCE_CHANGE=false
CADDY_CHANGE=false
SERVICE_CHANGE=false
PUBLICATION_STATE_CHANGE=true
CAPTURE_SCOPE=seven active publication scripts, Caddy config/status, cloudflared status, state URL references, physical and served indexes
EOF_MODEL

cat > "$METHODS" <<EOF_METHODS
STEP_TYPE=targeted read-only source snapshot plus report publication
SOURCE_FILES=exact byte copies from live VM130
SECRETS_POLICY=token file not copied; state capture limited to URL/reference lines
LIMITATION=canonical VM130 source snapshot is not replaced by this targeted evidence report
EOF_METHODS

cat > "$ACCESS" <<EOF_ACCESS
VM130=192.168.30.84
MGTS_WG=10.250.100.4/32
PUBLIC_DOMAIN=https://$DOMAIN/
LATEST_ROOT_URL=$LATEST_ROOT_URL
OLD_ROOT_URL=$OLD_ROOT_URL
LOCAL_CADDY_RESOLVE=$DOMAIN:443:10.71.100.84
EOF_ACCESS

cat > "$ROLLBACK" <<'EOF_ROLLBACK_PRE'
#!/usr/bin/env bash
echo "ROLLBACK_NOT_FINALIZED=true"
exit 1
EOF_ROLLBACK_PRE
chmod 700 "$ROLLBACK"

cat > "$REPORT" <<EOF_REPORT_PRE
RESULT=PENDING_PUBLICATION
STEP_ID=$STEP_ID
COPY_VERIFY=PASS
STEP_SHA256=$STEP_SHA256
RUNTIME_IMPACT=false
EOF_REPORT_PRE

cat > "$VERIFY" <<EOF_VERIFY_PRE
STEP_ID=$STEP_ID
RESULT=PENDING_PUBLICATION
PUBLISHER_SHA256=$PUBLISHER_SHA256
COPY_VERIFY=PASS
STEP_SHA256=$STEP_SHA256
EOF_VERIFY_PRE

python3 - "$FACTS" "$STEP_ID" "$STEP_SHA256" "$PUBLISHER_SHA256" <<'PY'
import json, sys
from pathlib import Path
output, step_id, step_sha, publisher_sha = sys.argv[1:]
Path(output).write_text(json.dumps({
    "step_id": step_id,
    "result": "PENDING_PUBLICATION",
    "copy_verify": "PASS",
    "step_sha256": step_sha,
    "publisher_sha256": publisher_sha,
    "runtime_impact": False,
    "source_change": False,
    "publication_state_change": True
}, indent=2) + "\n", encoding="utf-8")
PY

for file in \
    "$STEP_DIR/step-code.sh" "$STEP_DIR/transfer-verify.txt" \
    "$REPORT" "$FACTS" "$VERIFY" "$ROLLBACK" "$LOG" "$PROGRESS" \
    "$MODEL" "$METHODS" "$ACCESS"
do
    name="$(basename "$file")"
    safe_copy "$file" "$name" ||
        stop_step "STOP_R05B2_SAFE_COPY_FAILED" "$file"
done

find "$SAFE_DIR" -mindepth 1 -maxdepth 1 -type f \
    ! -name 'manifest.sha256' -printf '%f\n' |
LC_ALL=C sort |
while IFS= read -r name; do
    printf '%s  %s\n' "$(sha256sum "$SAFE_DIR/$name" | awk '{print $1}')" "$name"
done > "$SAFE_DIR/manifest.sha256"

progress "publishing targeted snapshot"

mapfile -t SAFE_FILES < <(
    find "$SAFE_DIR" -mindepth 1 -maxdepth 1 -type f -printf '%p\n' |
        LC_ALL=C sort
)

set +e
ROUTER_PUBLIC_BASE_URL="https://$DOMAIN" \
"$PUBLISHER" \
    "step_vm130_publication_pipeline_targeted_snapshot_r05b2" \
    "${SAFE_FILES[@]}" \
    > "$PUBLISH_OUT" 2> "$PUBLISH_ERR"
PUBLISH_RC=$?
set -e

[[ "$PUBLISH_RC" -eq 0 ]] ||
    stop_step "STOP_R05B2_PUBLISHER_FAILED" "$PUBLISH_ERR"

PUBLISHED_DIR="$(
    awk -F= '$1=="PUBLISHED_DIR" {print substr($0,index($0,"=")+1)}' \
        "$PUBLISH_OUT" | tail -n 1
)"
PUBLIC_OBJECT_KIND="$(
    awk -F= '$1=="PUBLIC_OBJECT_KIND" {print $2}' \
        "$PUBLISH_OUT" | tail -n 1
)"
PREVIOUS_MOVED_COUNT="$(
    awk -F= '$1=="PREVIOUS_MOVED_COUNT" {print $2}' \
        "$PUBLISH_OUT" | tail -n 1
)"

[[ -d "$PUBLISHED_DIR" ]] ||
    stop_step "STOP_R05B2_PUBLISHED_DIR_MISSING" "$PUBLISHED_DIR"

[[ "$PUBLIC_OBJECT_KIND" == "step-report" ]] ||
    stop_step "STOP_R05B2_KIND_INVALID" "$PUBLIC_OBJECT_KIND"

PUBLISHED_FOLDER="$(basename "$PUBLISHED_DIR")"
STEP_REPORT_URL="https://$DOMAIN/latest/$PUBLISHED_FOLDER/"
FACTS_URL="${STEP_REPORT_URL}facts.json"
VERIFY_URL="${STEP_REPORT_URL}verify.txt"
ROLLBACK_URL="${STEP_REPORT_URL}rollback.sh"

find "$LATEST" -mindepth 1 -maxdepth 1 -type d -name '*_step*' -printf '%f\n' |
    LC_ALL=C sort > "$AFTER_LATEST"

find "$OLD" -mindepth 1 -maxdepth 1 -type d -name '*_step*' -printf '%f\n' |
    LC_ALL=C sort > "$AFTER_OLD"

comm -13 "$BEFORE_OLD" "$AFTER_OLD" > "$MOVED_PREVIOUS"

CURRENT_STEP_REPORT_COUNT="$(wc -l < "$AFTER_LATEST" | tr -d ' ')"
ACTUAL_MOVED_COUNT="$(wc -l < "$MOVED_PREVIOUS" | tr -d ' ')"

cat > "$ROLLBACK" <<EOF_ROLLBACK
#!/usr/bin/env bash
set -Eeuo pipefail
PUBLISHED_DIR="$PUBLISHED_DIR"
LATEST="$LATEST"
OLD="$OLD"
REINDEX="$REINDEX"
ROLLBACK_TS="\$(date +%Y%m%d-%H%M%S)"

[[ -d "\$PUBLISHED_DIR" ]] || {
    echo "RESULT=STOP_ROLLBACK_PUBLICATION_MISSING"
    exit 20
}

mv "\$PUBLISHED_DIR" "\$OLD/\${ROLLBACK_TS}_rollback_removed_$PUBLISHED_FOLDER"

while IFS= read -r name; do
    [[ -n "\$name" ]] || continue
    [[ -d "\$OLD/\$name" ]] || {
        echo "RESULT=STOP_ROLLBACK_PREVIOUS_MISSING"
        exit 21
    }
    mv "\$OLD/\$name" "\$LATEST/\$name"
done <<'EOF_MOVED'
$(cat "$MOVED_PREVIOUS")
EOF_MOVED

"\$REINDEX"
echo "RESULT=PASS_PUBLICATION_ROLLBACK"
echo "RUNTIME_IMPACT=false"
EOF_ROLLBACK
chmod 700 "$ROLLBACK"

FOLDER_CODE="$(
    curl -sS --connect-timeout 5 --max-time 20 \
        --resolve "$DOMAIN:443:10.71.100.84" \
        -o /dev/null -w '%{http_code}' "$STEP_REPORT_URL" 2>/dev/null || true
)"
REPORT_CODE="$(
    curl -sS --connect-timeout 5 --max-time 20 \
        --resolve "$DOMAIN:443:10.71.100.84" \
        -o /dev/null -w '%{http_code}' "${STEP_REPORT_URL}report.txt" 2>/dev/null || true
)"
LATEST_INDEX_CONTAINS_FOLDER=false
if grep -q "$PUBLISHED_FOLDER" "$LATEST/index.html"; then
    LATEST_INDEX_CONTAINS_FOLDER=true
fi

RESULT="PASS_VM130_PUBLICATION_PIPELINE_TARGETED_SNAPSHOT"
FINAL_POSTCHECK=PASS

if [[ "$FOLDER_CODE" != "200" ||
      "$REPORT_CODE" != "200" ||
      "$CURRENT_STEP_REPORT_COUNT" -ne 1 ||
      "$ACTUAL_MOVED_COUNT" -ne "$PREVIOUS_MOVED_COUNT" ]]; then
    RESULT="STOP_R05B2_POSTCHECK_FAILED"
    FINAL_POSTCHECK=FAIL
fi

cat > "$REPORT" <<EOF_REPORT
RESULT=$RESULT
STEP_ID=$STEP_ID
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=PASS
STEP_SHA256=$STEP_SHA256
PUBLISHER_SHA256=$PUBLISHER_SHA256
SOURCE_CODE_CHANGE=false
PUBLICATION_STATE_CHANGE=true
CURRENT_STEP_REPORT_COUNT=$CURRENT_STEP_REPORT_COUNT
LATEST_INDEX_CONTAINS_FOLDER=$LATEST_INDEX_CONTAINS_FOLDER
FINAL_POSTCHECK=$FINAL_POSTCHECK
EXTERNAL_POSTCHECK=PENDING_ASSISTANT
RUNTIME_IMPACT=false
TRAFFIC_INTERRUPTION=none
ROLLBACK_REQUIRED=true
EOF_REPORT

python3 - "$FACTS" <<PY
import json
from pathlib import Path
Path("$FACTS").write_text(json.dumps({
    "step_id": "$STEP_ID",
    "result": "$RESULT",
    "step_report_url": "$STEP_REPORT_URL",
    "copy_verify": "PASS",
    "step_sha256": "$STEP_SHA256",
    "publisher_sha256": "$PUBLISHER_SHA256",
    "public_object_kind": "$PUBLIC_OBJECT_KIND",
    "previous_moved_count": int("$PREVIOUS_MOVED_COUNT"),
    "actual_moved_count": int("$ACTUAL_MOVED_COUNT"),
    "current_step_report_count": int("$CURRENT_STEP_REPORT_COUNT"),
    "latest_index_contains_folder": "$LATEST_INDEX_CONTAINS_FOLDER" == "true",
    "source_code_change": False,
    "publication_state_change": True,
    "runtime_impact": False,
    "final_postcheck": "$FINAL_POSTCHECK",
    "external_postcheck": "PENDING_ASSISTANT"
}, indent=2) + "\n", encoding="utf-8")
PY

cat > "$VERIFY" <<EOF_VERIFY
STEP_ID=$STEP_ID
RESULT=$RESULT
PUBLISHER_SHA256=$PUBLISHER_SHA256
PUBLIC_OBJECT_KIND=$PUBLIC_OBJECT_KIND
PREVIOUS_MOVED_COUNT=$PREVIOUS_MOVED_COUNT
ACTUAL_MOVED_COUNT=$ACTUAL_MOVED_COUNT
CURRENT_STEP_REPORT_COUNT=$CURRENT_STEP_REPORT_COUNT
FOLDER_CODE=$FOLDER_CODE
REPORT_CODE=$REPORT_CODE
LATEST_INDEX_CONTAINS_FOLDER=$LATEST_INDEX_CONTAINS_FOLDER
COPY_VERIFY=PASS
STEP_SHA256=$STEP_SHA256
FINAL_POSTCHECK=$FINAL_POSTCHECK
EXTERNAL_POSTCHECK=PENDING_ASSISTANT
RUNTIME_IMPACT=false
EOF_VERIFY

cp -a "$REPORT" "$FACTS" "$VERIFY" "$ROLLBACK" "$PUBLISH_OUT" "$PUBLISH_ERR" \
    "$PUBLISHED_DIR/"
chmod 0644 "$PUBLISHED_DIR/report.txt" "$PUBLISHED_DIR/facts.json" \
    "$PUBLISHED_DIR/verify.txt" "$PUBLISHED_DIR/publisher-output.txt" \
    "$PUBLISHED_DIR/publisher-errors.txt"
chmod 0755 "$PUBLISHED_DIR/rollback.sh"

if [[ "$FINAL_POSTCHECK" != "PASS" ]]; then
    stop_step "$RESULT" "$VERIFY"
fi

progress "targeted snapshot published and verified"

printf 'RESULT=%s\n' "$RESULT"
printf 'STEP_REPORT_URL=%s\n' "$STEP_REPORT_URL"
printf 'COPY_VERIFY=PASS\n'
printf 'STEP_SHA256=%s\n' "$STEP_SHA256"
printf 'RUNTIME_IMPACT=false\n'
printf 'EXTERNAL_POSTCHECK=PENDING_ASSISTANT\n'
