#!/usr/bin/env bash

set -Eeuo pipefail
umask 077

readonly TARGET_HOST=sqjcnginx01
readonly TARGET_IP=10.2.203.102
readonly TARGET_MANIFEST=/opt/zhct-deploy/roles/nginx/manifests/systemd-units.tsv
readonly OLD_SHA256=98bec522fafb6d91f6be7f2bffeb40353b5b07882a82982b67c400d05cc4bc34
readonly NEW_SHA256=24ce7c17d7a7cf8070d1cdd9013c54e49a445cd264a0ecafcae4ef1912811d61
readonly Q160_SCRIPT=/root/q160-nginx-role-readonly.sh
readonly Q160_SCRIPT_SHA256=cd6549666d97a77cb2d60c9d007479f6a034c54f7ce0c53a63d277ebbdab28b5

run_id="q160-nginx01-manifest-refresh-$(date -u +%Y%m%dT%H%M%SZ)"
backup_dir="/var/backups/zhct-q160/files/${run_id}/opt/zhct-deploy/roles/nginx/manifests"
backup_file="${backup_dir}/systemd-units.tsv"
payload_file=
target_tmp=
restore_tmp=
rollback_needed=0
backup_created=0

die() {
    printf 'Q160_REFRESH_ERROR=%s\n' "$*" >&2
    return 1
}

sha256_of() {
    sha256sum "$1" | awk '{print $1}'
}

finish() {
    local rc=$?
    local restored_sha=
    set +e
    if [[ "$rc" -ne 0 && "$rollback_needed" -eq 1 ]]; then
        printf 'Q160_REFRESH_ROLLBACK_BEGIN\n'
        restore_tmp="${TARGET_MANIFEST}.q160-restore-${run_id}"
        rm -f -- "$restore_tmp"
        cp -a -- "$backup_file" "$restore_tmp" &&
            mv -fT -- "$restore_tmp" "$TARGET_MANIFEST"
        restored_sha=$(sha256_of "$TARGET_MANIFEST" 2>/dev/null || true)
        if [[ "$restored_sha" == "$OLD_SHA256" ]]; then
            printf 'Q160_REFRESH_ROLLBACK=PASS RESTORED_SHA256=%s\n' "$restored_sha"
        else
            printf 'Q160_REFRESH_ROLLBACK=FAIL RESTORED_SHA256=%s\n' "${restored_sha:-UNREADABLE}"
        fi
    elif [[ "$rc" -eq 0 ]]; then
        printf 'Q160_REFRESH_ROLLBACK=NOT_REQUIRED\n'
    else
        printf 'Q160_REFRESH_ROLLBACK=NOT_REQUIRED_NO_TARGET_REPLACEMENT\n'
    fi
    [[ -z "$payload_file" ]] || rm -f -- "$payload_file"
    [[ -z "$target_tmp" ]] || rm -f -- "$target_tmp"
    [[ -z "$restore_tmp" ]] || rm -f -- "$restore_tmp"
    if [[ "$backup_created" -eq 1 ]]; then
        printf 'Q160_REFRESH_BACKUP=%s\n' "$backup_file"
    else
        printf 'Q160_REFRESH_BACKUP=NOT_CREATED\n'
    fi
    printf 'Q160_NGINX01_REFRESH_AND_RERUN_END RC=%s\n' "$rc"
    exit "$rc"
}
trap finish EXIT

printf 'Q160_NGINX01_REFRESH_AND_RERUN_BEGIN\n'
printf 'Q160_REFRESH_RUN_ID=%s\n' "$run_id"
printf 'Q160_TARGET_HOST=%s\n' "$TARGET_HOST"
printf 'Q160_TARGET_IP=%s\n' "$TARGET_IP"

[[ $(id -u) -eq 0 ]] || die 'root is required'
[[ "$(hostname -s)" == "$TARGET_HOST" ]] || die 'hostname mismatch'
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 |
    grep -Fxq "$TARGET_IP" || die 'target IP mismatch'
printf 'Q160_REFRESH_IDENTITY_GATE=PASS\n'

for command in awk chmod cp cut date grep hostname id install ip mkdir mktemp mv rm sha256sum stat; do
    command -v "$command" >/dev/null 2>&1 || die "missing command: $command"
done
[[ -f "$TARGET_MANIFEST" && ! -L "$TARGET_MANIFEST" ]] || die 'target manifest is not a regular file'
[[ -f "$Q160_SCRIPT" && ! -L "$Q160_SCRIPT" ]] || die 'Q160 entry is not a regular file'
[[ $(sha256_of "$Q160_SCRIPT") == "$Q160_SCRIPT_SHA256" ]] || die 'Q160 entry SHA256 mismatch'
[[ $(stat -c '%U:%G:%a' "$Q160_SCRIPT") == root:root:750 ]] || die 'Q160 entry metadata mismatch'
printf 'Q160_REFRESH_Q160_ENTRY_GATE=PASS SHA256=%s OWNER_MODE=root:root:750\n' "$Q160_SCRIPT_SHA256"

payload_file=$(mktemp /tmp/q160-systemd-units.XXXXXX)
cat >"$payload_file" <<'MANIFEST'
unit	template_state	node_states	purpose
haproxy.service	disabled,inactive	nginx01=enabled,active;nginx02=enabled,active	MySQL,Redis,MQTT proxy
nginx.service	disabled,inactive	nginx01=enabled,active;nginx02=enabled,active	front HTTP reverse proxy
orchestrator.service	disabled,inactive	nginx01=enabled,active;nginx02=enabled,active	MySQL HA Raft control
sentinel5.service	disabled,inactive	nginx01=disabled,inactive;nginx02=disabled,inactive	third Redis5 Sentinel; Q-230 enables explicitly after network and Redis gates
sentinel7.service	disabled,inactive	nginx01=disabled,inactive;nginx02=disabled,inactive	third Redis7 Sentinel; Q-230 enables explicitly after network and Redis gates
keepalived.service	disabled,inactive	nginx01=disabled,inactive;nginx02=disabled,inactive	front,mqtt,db-proxy VIP election; Q-251 enables explicitly after all HA gates
MANIFEST
[[ $(sha256_of "$payload_file") == "$NEW_SHA256" ]] || die 'embedded authoritative manifest SHA256 mismatch'
printf 'Q160_REFRESH_EMBEDDED_MANIFEST_GATE=PASS SHA256=%s\n' "$NEW_SHA256"

current_sha=$(sha256_of "$TARGET_MANIFEST")
printf 'Q160_REFRESH_CURRENT_SHA256=%s\n' "$current_sha"
case "$current_sha" in
    "$OLD_SHA256")
        mkdir -p -- "$backup_dir"
        chmod 0750 "$backup_dir"
        cp -a -- "$TARGET_MANIFEST" "$backup_file"
        [[ $(sha256_of "$backup_file") == "$OLD_SHA256" ]] || die 'backup SHA256 mismatch'
        backup_created=1
        printf 'Q160_REFRESH_BACKUP_GATE=PASS PATH=%s\n' "$backup_file"

        target_tmp="${TARGET_MANIFEST}.q160-new-${run_id}"
        rm -f -- "$target_tmp"
        install -m 0644 -o root -g root -- "$payload_file" "$target_tmp"
        [[ $(sha256_of "$target_tmp") == "$NEW_SHA256" ]] || die 'staged target SHA256 mismatch'
        mv -fT -- "$target_tmp" "$TARGET_MANIFEST"
        target_tmp=
        rollback_needed=1
        printf 'Q160_REFRESH_ATOMIC_REPLACE=PASS\n'
        ;;
    "$NEW_SHA256")
        printf 'Q160_REFRESH_ATOMIC_REPLACE=SKIPPED_ALREADY_CURRENT\n'
        ;;
    *)
        die "unexpected current manifest SHA256: $current_sha"
        ;;
esac

[[ $(sha256_of "$TARGET_MANIFEST") == "$NEW_SHA256" ]] || die 'post-replace manifest SHA256 mismatch'
[[ $(stat -c '%U:%G:%a' "$TARGET_MANIFEST") == root:root:644 ]] || die 'post-replace manifest metadata mismatch'
printf 'Q160_REFRESH_POST_REPLACE_GATE=PASS SHA256=%s OWNER_MODE=root:root:644\n' "$NEW_SHA256"

q160_run_id="q160-20260806-nginx01-rerun-$(date -u +%Y%m%dT%H%M%SZ)"
printf 'Q160_REFRESH_RERUN_BEGIN Q160_RUN_ID=%s\n' "$q160_run_id"
env \
    Q160_RUN_ID="$q160_run_id" \
    Q160_REMOTE_LOCK_GRANTED=1 \
    Q160_REMOTE_LOCK_OWNER=NGINX_Q160 \
    Q160_DEP_Q101=PASS \
    Q160_DEP_Q102=PASS \
    Q160_DEP_Q143=PASS \
    "$Q160_SCRIPT" run --node nginx01
printf 'Q160_REFRESH_RERUN_END RC=0\n'

rollback_needed=0
printf 'Q160_NGINX01_REFRESH_AND_RERUN_PASS\n'
