#!/usr/bin/env bash

set -Eeuo pipefail
export LANG=C
umask 077

EXPECTED_HOSTNAME="sqjcmqtt01"
EXPECTED_IPV4="10.2.203.108"
RUN_ID=${1:-}
CONFIRM=${2:-}
EVIDENCE_DIR="/var/backups/zhct-q081/evidence/${RUN_ID}"
TEMP_ROOT=
EMQX_PID=
SUB_PID=
ORIGINAL_CONF_STATE=ABSENT
CONF_BACKUP=
TARGET_PORT_RE=':(1883|8083|18083|4370|5370|8883|8084)([[:space:]]|$)'

die() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

cleanup() {
  [[ -z "${SUB_PID:-}" ]] || kill "${SUB_PID}" >/dev/null 2>&1 || true
  if [[ -n "${EMQX_PID:-}" ]]; then
    kill "${EMQX_PID}" >/dev/null 2>&1 || true
    for _ in {1..20}; do
      kill -0 "${EMQX_PID}" >/dev/null 2>&1 || break
      sleep 0.25
    done
    kill -KILL "${EMQX_PID}" >/dev/null 2>&1 || true
  fi
  systemctl disable --now emqx.service mosquitto.service >/dev/null 2>&1 || true
  if [[ "${ORIGINAL_CONF_STATE}" == "PRESENT" && -f "${CONF_BACKUP}" ]]; then
    install -m 0600 -o emqx -g emqx "${CONF_BACKUP}" /etc/emqx/emqx.conf
  elif [[ "${ORIGINAL_CONF_STATE}" == "ABSENT" ]]; then
    rm -f /etc/emqx/emqx.conf
  fi
  [[ -z "${TEMP_ROOT:-}" ]] || rm -rf "${TEMP_ROOT}"
}

[[ "${EUID}" -eq 0 ]] || die "must run as root"
[[ "${RUN_ID}" =~ ^q081-[0-9]{8}T[0-9]{6}[+]0800$ ]] || die "invalid Q081 run id"
[[ "${CONFIRM}" == "--execute-q081-loopback-pubsub" ]] || die "explicit loopback pubsub flag is required"
[[ "$(hostname -s)" == "${EXPECTED_HOSTNAME}" ]] || die "hostname mismatch"
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 |
  grep -Fxq "${EXPECTED_IPV4}" || die "expected IPv4 is not configured"
grep -Fxq 'install_execution=PASS' "${EVIDENCE_DIR}/install-result.env" || die "Q081 install gate is not PASS"
[[ -z "$(ss -lntupH | grep -E "${TARGET_PORT_RE}" || true)" ]] || die "an EMQX target port is occupied"
systemctl is-active --quiet emqx.service && die "emqx.service is active"
systemctl is-active --quiet mosquitto.service && die "mosquitto.service is active"
command -v mosquitto_pub >/dev/null || die "mosquitto_pub not found"
command -v mosquitto_sub >/dev/null || die "mosquitto_sub not found"
getent passwd emqx >/dev/null || die "emqx account not found"

exec 9>/run/lock/zhct-q081-loopback.lock
flock -n 9 || die "another Q081 loopback check is running"
TEMP_ROOT=$(mktemp -d /var/tmp/zhct-q081-emqx.XXXXXX)
install -d -m 0700 -o emqx -g emqx "${TEMP_ROOT}/data" "${TEMP_ROOT}/log"
CONF_BACKUP="/var/backups/zhct-q081/files/${RUN_ID}/etc/emqx/emqx.conf.before-temp"
if [[ -f /etc/emqx/emqx.conf ]]; then
  ORIGINAL_CONF_STATE=PRESENT
  install -d -m 0700 "$(dirname "${CONF_BACKUP}")"
  cp -a /etc/emqx/emqx.conf "${CONF_BACKUP}"
  chmod 0600 "${CONF_BACKUP}"
fi
trap cleanup EXIT
cookie=$(openssl rand -hex 32)
cat >"${TEMP_ROOT}/emqx.conf" <<EOF
node {
  name = "emqx-q081@127.0.0.1"
  cookie = "${cookie}"
  data_dir = "${TEMP_ROOT}/data"
}
cluster.discovery_strategy = manual
listeners.tcp.default {
  bind = "127.0.0.1:1883"
}
listeners.ssl.default.enable = false
listeners.ws.default.enable = false
listeners.wss.default.enable = false
dashboard.listeners.http.enable = false
log.file.default {
  enable = true
  path = "${TEMP_ROOT}/log/emqx.log"
}
EOF
chown emqx:emqx "${TEMP_ROOT}/emqx.conf"
chmod 0600 "${TEMP_ROOT}/emqx.conf"
install -m 0600 -o emqx -g emqx "${TEMP_ROOT}/emqx.conf" /etc/emqx/emqx.conf
runuser -u emqx -- emqx check_config >"${EVIDENCE_DIR}/temp-check-config.txt" 2>&1
runuser -u emqx -- emqx foreground >"${TEMP_ROOT}/foreground.log" 2>&1 &
EMQX_PID=$!
for _ in {1..60}; do
  ss -lntH | grep -Eq ':1883([[:space:]]|$)' && break
  kill -0 "${EMQX_PID}" >/dev/null 2>&1 || die "temporary EMQX exited before listening"
  sleep 0.5
done
ss -lntH | grep -Eq '127\\.0\\.0\\.1:1883([[:space:]]|$)' || die "temporary EMQX did not bind loopback 1883"
topic="q081/${RUN_ID}/$(openssl rand -hex 8)"
payload="Q081_${RUN_ID}_$(openssl rand -hex 16)"
timeout 15 mosquitto_sub -h 127.0.0.1 -p 1883 -t "${topic}" -C 1 \
  >"${EVIDENCE_DIR}/pubsub-received.txt" 2>"${EVIDENCE_DIR}/mosquitto-sub.err" &
SUB_PID=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t "${topic}" -m "${payload}" \
  >"${EVIDENCE_DIR}/mosquitto-pub.txt" 2>&1
wait "${SUB_PID}" || die "mosquitto_sub did not receive the test payload"
SUB_PID=
[[ "$(cat "${EVIDENCE_DIR}/pubsub-received.txt")" == "${payload}" ]] || die "pubsub payload mismatch"
runuser -u emqx -- emqx ctl status >"${EVIDENCE_DIR}/temp-emqx-status.txt" 2>&1
ss -lntup >"${EVIDENCE_DIR}/listeners-during-temp.txt"
find "${TEMP_ROOT}" -printf '%m\t%u\t%g\t%s\t%p\n' >"${EVIDENCE_DIR}/temp-path-ownership.txt"
cp "${TEMP_ROOT}/foreground.log" "${EVIDENCE_DIR}/temp-emqx-foreground.log"
[[ ! -f "${TEMP_ROOT}/log/emqx.log" ]] || cp "${TEMP_ROOT}/log/emqx.log" "${EVIDENCE_DIR}/temp-emqx.log"
cleanup
trap - EXIT
sleep 1
[[ -z "$(ss -lntupH | grep -E "${TARGET_PORT_RE}" || true)" ]] || die "an EMQX target listener remains after cleanup"
pgrep -fa 'emqx-q081@127.0.0.1' >"${EVIDENCE_DIR}/process-residue.txt" || true
[[ ! -s "${EVIDENCE_DIR}/process-residue.txt" ]] || die "temporary EMQX process remains"
[[ ! -e "${TEMP_ROOT}" ]] || die "temporary data/log root remains"
grep -RIlF "${cookie}" /etc/emqx /var/lib/emqx /var/log/emqx 2>/dev/null \
  >"${EVIDENCE_DIR}/cookie-residue-paths.txt" || true
[[ ! -s "${EVIDENCE_DIR}/cookie-residue-paths.txt" ]] || die "temporary cookie residue remains"
grep -RIlF "${cookie}" "${EVIDENCE_DIR}" >"${EVIDENCE_DIR}/cookie-evidence-residue-paths.txt" || true
[[ ! -s "${EVIDENCE_DIR}/cookie-evidence-residue-paths.txt" ]] ||
  die "temporary cookie was copied into the evidence directory"
for unit in emqx.service mosquitto.service; do
  systemctl is-active --quiet "${unit}" && die "${unit} is active after cleanup"
  enabled=$(systemctl is-enabled "${unit}" 2>/dev/null || true)
  [[ "${enabled}" == "disabled" || "${enabled}" == "masked" ]] || die "${unit} is not disabled"
done
{
  printf 'run_id=%s\n' "${RUN_ID}"
  printf 'emqx_check_config=PASS\n'
  printf 'loopback_bind=127.0.0.1:1883\n'
  printf 'loopback_pubsub=PASS\n'
  printf 'temporary_data_log_cleanup=PASS\n'
  printf 'temporary_cookie_cleanup=PASS\n'
  printf 'target_listener_count_after_cleanup=0\n'
  printf 'target_units_disabled_inactive=PASS\n'
} >"${EVIDENCE_DIR}/loopback-pubsub-result.env"
chmod -R go-rwx "${EVIDENCE_DIR}"
printf 'EMQX01_Q081_LOOPBACK_PUBSUB_OK\n'
cat "${EVIDENCE_DIR}/loopback-pubsub-result.env"
