#!/usr/bin/env bash
echo Q200_APP_IP_READONLY_SCRIPT=CANCELLED_DO_NOT_EXECUTE >&2
exit 125
set -Eeuo pipefail
umask 077

bad=0
node=''
expected_host=''
expected_ip=''

finish() {
  local rc=$?
  set +e
  echo "Q200_APP_IP_READONLY_BAD=$bad"
  echo "Q200_APP_IP_READONLY_RC=$rc"
  [[ $rc -eq 0 ]] && echo Q200_APP_IP_READONLY_RESULT=PASS || echo Q200_APP_IP_READONLY_RESULT=BLOCKED
  echo Q200_APP_IP_READONLY_DURABLE_STATE_MUTATION=ZERO
  echo Q200_APP_IP_READONLY_ROLLBACK_STATE=NOT_REQUIRED_READONLY
  echo Q200_APP_IP_READONLY_END
  exit "$rc"
}
trap finish EXIT

echo Q200_APP_IP_READONLY_BEGIN

if [[ ${1:-} == --static-validate && $# -eq 1 ]]; then
  echo Q200_APP_IP_READONLY_STATIC_VALIDATE=PASS
  exit 0
fi

[[ ${1:-} == --node && $# -eq 2 ]] || { echo 'ERROR: use --node app01|app02' >&2; exit 2; }
node=$2
case "$node" in
  app01) expected_host=sqjcapp01; expected_ip=10.2.203.104 ;;
  app02) expected_host=sqjcapp02; expected_ip=10.2.203.105 ;;
  *) echo 'ERROR: node must be app01 or app02' >&2; exit 2 ;;
esac

actual_host=$(hostname -s)
[[ ${actual_host,,} == ${expected_host,,} ]] || { echo "ERROR: hostname expected=$expected_host actual=$actual_host" >&2; exit 3; }
ip -o -4 addr show scope global | awk -v ip="$expected_ip" '{split($4,a,"/"); if(a[1]==ip) ok=1} END{exit !ok}' || {
  echo "ERROR: expected IP missing: $expected_ip" >&2; exit 4;
}

echo "Q200_APP_IP_READONLY_NODE=$node"
echo "Q200_APP_IP_READONLY_TARGET=$expected_host/$expected_ip"
echo "Q200_APP_IP_READONLY_CAPTURED_AT=$(date -Is)"

echo '=== TIME ==='
timedatectl show -p Timezone -p NTPSynchronized -p TimeUSec
[[ $(timedatectl show -p NTPSynchronized --value) == yes ]] || bad=1

echo '=== HOSTNAME_RESOLUTION_OBSERVATION_NONBLOCKING ==='
while read -r ip name; do
  answer=$(getent ahostsv4 "$name" 2>/dev/null | awk 'NR==1{print $1}')
  echo "HOST_OBSERVATION name=$name expected=$ip actual=${answer:-UNRESOLVED}"
done <<'EOF'
10.2.203.102 sqjcnginx01
10.2.203.103 sqjcnginx02
10.2.203.104 sqjcapp01
10.2.203.105 sqjcapp02
10.2.208.106 sqjcDB01
10.2.208.107 sqjcDB02
10.2.203.108 sqjcmqtt01
10.2.203.109 sqjcmqtt02
10.2.203.110 sqjcmqtt03
10.2.203.112 sqjcredis01
10.2.203.113 sqjcredis02
EOF
echo Q200_HOSTS_DNS_PREVIOUS_FAILURE=SUPERSEDED_BY_IP_BASED_Q200_POLICY

echo '=== FORMAL_RUNTIME_CONFIG_ENDPOINT_REFERENCES ==='
mapfile -t config_files < <(find /usr/local/nginx/conf /usr/local/php7.3/etc /usr/local/php7.4/etc /etc/supervisor/conf.d /etc/cron.d \
  -xdev -type f -size -2M 2>/dev/null | LC_ALL=C sort)
host_pattern='sqjcnginx01|sqjcnginx02|sqjcapp01|sqjcapp02|sqjcDB01|sqjcDB02|sqjcmqtt01|sqjcmqtt02|sqjcmqtt03|sqjcredis01|sqjcredis02'
ip_pattern='10\.2\.203\.(102|103|104|105|108|109|110|112|113)|10\.2\.208\.(106|107)'
declare -A referenced_hosts=()
for file in "${config_files[@]}"; do
  if grep -Iq . "$file" 2>/dev/null; then
    if grep -Eq "$ip_pattern" "$file"; then echo "CONFIG_FIXED_IP_REFERENCE file=$file"; fi
    while read -r ref; do [[ -n $ref ]] && referenced_hosts["$ref"]=1; done < <(grep -Eho "$host_pattern" "$file" 2>/dev/null | LC_ALL=C sort -u)
  fi
done
if ((${#referenced_hosts[@]} == 0)); then
  echo Q200_FORMAL_CONFIG_HOSTNAME_REFERENCE=NONE
else
  for ref in "${!referenced_hosts[@]}"; do
    resolved=$(getent ahostsv4 "$ref" 2>/dev/null | awk 'NR==1{print $1}')
    echo "CONFIG_HOSTNAME_REFERENCE name=$ref resolution=${resolved:-UNRESOLVED}"
    [[ -n $resolved ]] || bad=1
  done
fi

echo '=== FIXED_IP_ROUTES ==='
for ip in 10.2.203.102 10.2.203.103 10.2.203.104 10.2.203.105 10.2.208.106 10.2.208.107 10.2.203.108 10.2.203.109 10.2.203.110 10.2.203.112 10.2.203.113; do
  [[ $ip == "$expected_ip" ]] && continue
  ip route get "$ip" || bad=1
done

echo '=== FIREWALL_READONLY ==='
if timeout 15 firewall-cmd --state; then
  timeout 15 firewall-cmd --get-active-zones || bad=1
  timeout 15 firewall-cmd --list-all || bad=1
else
  echo Q200_FIREWALLD_QUERY=BLOCKED
  systemctl --no-pager --full status firewalld.service || true
  bad=1
fi

probe() {
  local host=$1 port=$2 rc
  timeout 4 bash -c 'exec 3<>/dev/tcp/$1/$2' _ "$host" "$port" >/dev/null 2>&1
  rc=$?
  echo "TCP_FIXED_IP target=$host:$port rc=$rc"
  [[ $rc -eq 0 ]] || bad=1
}

echo '=== MYSQL_FIXED_IP ==='
for x in 10.2.208.106:3306 10.2.208.106:3308 10.2.208.107:3306 10.2.208.107:3308; do probe "${x%:*}" "${x##*:}"; done
echo '=== REDIS_FIXED_IP ==='
for x in 10.2.203.112:6379 10.2.203.112:6387 10.2.203.113:6379 10.2.203.113:6387; do probe "${x%:*}" "${x##*:}"; done
echo '=== EMQX_FIXED_IP ==='
for x in 10.2.203.108:1883 10.2.203.109:1883 10.2.203.110:1883; do probe "${x%:*}" "${x##*:}"; done

echo '=== LOCAL_APP_RUNTIME ==='
for unit in nginx.service php-fpm73.service php-fpm74.service supervisor.service crond.service; do
  enabled=$(systemctl is-enabled "$unit" 2>/dev/null || true)
  active=$(systemctl is-active "$unit" 2>/dev/null || true)
  echo "UNIT name=$unit enabled=$enabled active=$active"
done
for unit in nginx.service php-fpm73.service php-fpm74.service; do systemctl is-active --quiet "$unit" || bad=1; done
for unit in supervisor.service crond.service; do
  [[ $(systemctl is-enabled "$unit" 2>/dev/null || true) == disabled ]] || bad=1
  [[ $(systemctl is-active "$unit" 2>/dev/null || true) == inactive ]] || bad=1
done
ss -ltnp | awk 'NR==1 || $4 ~ /:(80|81)$/'
ss -H -ltn | awk '$4 ~ /:80$/ {p80=1} $4 ~ /:81$/ {p81=1} END{exit !(p80&&p81)}' || bad=1
pgrep -a -x supervisord && bad=1 || true

[[ $bad -eq 0 ]]
