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

EXPECTED_HOST=sqjcDB01
EXPECTED_IP=10.2.208.106
INNER_ARCHIVE_SHA256=77821b30effff6527888ddf4b5c68d9890000b725864f9b21e2195db17e56708
INNER_ARCHIVE=${INNER_ARCHIVE:-/root/sanquan-mysql-q220-222-ha-gates-20260729.tar.gz}
RUNTIME_ROOT=/root/.zhct-mysql-q220-221-fast-chain
INPUT_ROOT=${INPUT_ROOT:-/root/zhct-q220-222-inputs}
WRAPPER_EVIDENCE_ROOT=/var/backups/zhct-q220-221-fast-chain
MUTATION_STARTED=0

die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
require_file() { [[ -f "$1" ]] || die "required file missing: $1"; }
secure_file() {
  require_file "$1"
  [[ $(stat -c '%U:%G' "$1") == root:root ]] || die "unsafe owner: $1"
  case "$(stat -c '%a' "$1")" in 400|600) ;; *) die "unsafe mode: $1" ;; esac
}
receipt_gate() {
  local file=$1 marker=$2
  secure_file "$file"
  grep -Fxq "$marker=PASS" "$file" || die "$marker receipt is not PASS"
  grep -Eq '^archive_sha256=[0-9a-f]{64}$' "$file" || die "$marker receipt SHA missing"
}
mysql_value() {
  local client=$1 cnf=$2 sql=$3
  "$client" --defaults-extra-file="$cnf" --batch --skip-column-names -e "$sql"
}
static_validate() {
  require_file "$INNER_ARCHIVE"
  [[ $(sha256sum "$INNER_ARCHIVE" | awk '{print $1}') == "$INNER_ARCHIVE_SHA256" ]] || die 'inner mature archive SHA mismatch'
  bash -n "${BASH_SOURCE[0]}"
  printf 'MYSQL01_Q220_PRIMARY_SIDE_STATIC_VALIDATE_OK\n'
}
check_listener() {
  local port=$1
  ss -lntH | awk -v endpoint="$EXPECTED_IP:$port" '$4==endpoint{ok=1} END{exit !ok}' ||
    die "listener missing: $EXPECTED_IP:$port"
}
check_unit() {
  systemctl is-enabled --quiet "$1" || die "unit not enabled: $1"
  systemctl is-active --quiet "$1" || die "unit not active: $1"
}
prepare_payload() {
  local runtime="$RUNTIME_ROOT/$RUN_ID/payload"
  require_file "$INNER_ARCHIVE"
  [[ $(sha256sum "$INNER_ARCHIVE" | awk '{print $1}') == "$INNER_ARCHIVE_SHA256" ]] ||
    die 'inner mature archive SHA mismatch'
  [[ ! -e "$runtime" ]] || die "runtime path already exists: $runtime"
  install -d -m 0700 -o root -g root "$runtime"
  tar -xzf "$INNER_ARCHIVE" -C "$runtime" --no-same-owner
  (cd "$runtime" && sha256sum -c SHA256SUMS)
  bash -n "$runtime/q220-222-mysql.sh"
  bash "$runtime/q220-222-mysql.sh" --static-validate
  INNER_ENTRY="$runtime/q220-222-mysql.sh"
}
rollback_on_failure() {
  local rc=$?
  trap - EXIT
  if [[ $rc -ne 0 && $MUTATION_STARTED -eq 1 && -x ${INNER_ENTRY:-/nonexistent} ]]; then
    printf 'failure_rollback_begin=YES\n'
    INPUT_ROOT="$INPUT_ROOT" bash "$INNER_ENTRY" q220 rollback --node mysql01 --approve-dangerous ||
      printf 'failure_rollback_rc=%s\n' "$?"
  fi
  printf 'finished_at=%s\nEND MYSQL01_Q220_PRIMARY_SIDE RC=%s\n' "$(date --iso-8601=seconds)" "$rc"
  exit "$rc"
}

[[ ${1:-} == --static-validate ]] && { static_validate; exit 0; }
[[ ${1:-} == run && $# -eq 1 ]] || die 'usage: mysql01-primary-side.sh --static-validate|run'
static_validate
printf 'BEGIN MYSQL01_Q220_PRIMARY_SIDE\nstarted_at=%s\n' "$(date --iso-8601=seconds)"
[[ $(id -u) -eq 0 ]] || die 'root is required'
[[ "$(hostname -s)" == "$EXPECTED_HOST" ]] || die "wrong hostname"
ip -o -4 addr show scope global | awk -v ip="$EXPECTED_IP" '{split($4,a,"/"); if(a[1]==ip)ok=1} END{exit !ok}' ||
  die "expected IP missing: $EXPECTED_IP"
RUN_ID="mysql01-q220-fast-$(date '+%Y%m%dT%H%M%S%z')"
EVIDENCE_DIR="$WRAPPER_EVIDENCE_ROOT/$RUN_ID"
install -d -m 0700 -o root -g root "$EVIDENCE_DIR"
exec > >(tee -a "$EVIDENCE_DIR/operator.log") 2>&1
trap rollback_on_failure EXIT
printf 'target_identity=PASS\ntarget_hostname=%s\ntarget_ip=%s\nrun_id=%s\n' "$EXPECTED_HOST" "$EXPECTED_IP" "$RUN_ID"

receipt_gate "$INPUT_ROOT/q200-pass.env" Q200
receipt_gate "$INPUT_ROOT/q210-pass.env" Q210
printf 'dependency_gate=Q200_PASS_Q210_PASS\n'
for unit in mysql56.service mysql80.service mysql-health56.service mysql-health80.service; do check_unit "$unit"; done
for port in 3306 3308 9201 9202; do check_listener "$port"; done
printf 'service_listener_gate=PASS\n'

secure_file "$INPUT_ROOT/mysql56-admin.cnf"
secure_file "$INPUT_ROOT/mysql80-admin.cnf"
id56=$(mysql_value /opt/mysql/5.6.51/bin/mysql "$INPUT_ROOT/mysql56-admin.cnf" 'SELECT CONCAT(@@server_id,"|",@@server_uuid,"|",@@read_only,"|",@@global.binlog_format)')
id80=$(mysql_value /opt/mysql/8.0.46/bin/mysql "$INPUT_ROOT/mysql80-admin.cnf" 'SELECT CONCAT(@@server_id,"|",@@server_uuid,"|",@@read_only,"|",@@super_read_only,"|",@@global.binlog_format)')
IFS='|' read -r sid56 uuid56 ro56 fmt56 <<<"$id56"
IFS='|' read -r sid80 uuid80 ro80 sro80 fmt80 <<<"$id80"
[[ $sid56 == 56106 && $sid80 == 80106 ]] || die 'primary server_id mismatch'
[[ $uuid56 =~ ^[0-9a-fA-F-]{36}$ && $uuid80 =~ ^[0-9a-fA-F-]{36}$ && $uuid56 != "$uuid80" ]] || die 'primary UUID gate failed'
[[ $ro56 == 0 && $ro80 == 0 && $sro80 == 0 ]] || die 'primary is not writable by policy'
[[ ${fmt56^^} == ROW && ${fmt80^^} == ROW ]] || die 'binlog_format must be ROW'
printf 'MYSQL56_PRIMARY server_id=%s server_uuid=%s read_only=%s binlog_format=%s\n' "$sid56" "$uuid56" "$ro56" "$fmt56"
printf 'MYSQL80_PRIMARY server_id=%s server_uuid=%s read_only=%s super_read_only=%s binlog_format=%s\n' "$sid80" "$uuid80" "$ro80" "$sro80" "$fmt80"
printf 'primary_identity_write_policy_gate=PASS\n'

prepare_payload
MUTATION_STARTED=1
INPUT_ROOT="$INPUT_ROOT" bash "$INNER_ENTRY" q220 execute --node mysql01 --approve-dangerous
INPUT_ROOT="$INPUT_ROOT" bash "$INNER_ENTRY" q220 verify --node mysql01
INPUT_ROOT="$INPUT_ROOT" bash "$INNER_ENTRY" q220 archive --node mysql01
MUTATION_STARTED=0
INNER_RUN_ID=$(< /var/lib/zhct-q220-222/q220-mysql01.last)
INNER_ARCHIVE="/var/backups/zhct-q220-222/${INNER_RUN_ID}.tar.gz"
require_file "$INNER_ARCHIVE"
INNER_RESULT_SHA=$(sha256sum "$INNER_ARCHIVE" | awk '{print $1}')
{
  printf 'Q220=PASS\narchive_sha256=%s\n' "$INNER_RESULT_SHA"
  printf 'mysql56_primary_server_id=%s\nmysql56_primary_server_uuid=%s\n' "$sid56" "$uuid56"
  printf 'mysql80_primary_server_id=%s\nmysql80_primary_server_uuid=%s\n' "$sid80" "$uuid80"
  printf 'business_sql=NOT_PERFORMED_Q261_GATE\n'
} > /root/q220-pass.env
chmod 0600 /root/q220-pass.env
sha256sum /root/q220-pass.env "$INNER_ARCHIVE" | tee "$EVIDENCE_DIR/output-sha256.txt"
printf 'Q220_PRIMARY_EXECUTE_VERIFY_ARCHIVE_PASS\nq220_receipt=/root/q220-pass.env\n'
printf 'Q222=NOT_PERFORMED_REQUIRES_ORCHESTRATOR_HAPROXY_NODES\nQ261_BUSINESS_SQL=NOT_PERFORMED\n'
