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

component_failures=0

finish() {
  final_rc=$?
  printf '%s\n' 'REMOTE_MUTATION=ZERO'
  printf 'END|REDIS02_SENTINEL_TOPOLOGY_DIAGNOSIS|RC=%s\n' "$final_rc"
}
trap finish EXIT

printf 'BEGIN|REDIS02_SENTINEL_TOPOLOGY_DIAGNOSIS|%s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z')"

test "$(id -u)" -eq 0
test "$(hostname -s)" = 'sqjcredis02'
ip -o -4 addr show scope global | grep -q '10\.2\.203\.113/'
printf '%s\n' 'IDENTITY|user=root|hostname=sqjcredis02|ip=10.2.203.113|PASS'

readonly CLI5='/opt/redis/5.0.14/bin/redis-cli'
readonly CLI7='/opt/redis/7.2.14/bin/redis-cli'
readonly PW5='/etc/zhct/secrets/redis5.password'
readonly PW7='/etc/zhct/secrets/redis7.password'
readonly CONF5='/var/lib/redis-sentinel5/sentinel.conf'
readonly CONF7='/var/lib/redis-sentinel7/sentinel.conf'

for required_file in "$CLI5" "$CLI7" "$PW5" "$PW7" "$CONF5" "$CONF7"; do
  if test -e "$required_file"; then
    stat -c 'REQUIRED|PRESENT|%F|%A|%U:%G|%s|%n' "$required_file"
  else
    printf 'REQUIRED|ABSENT|%s\n' "$required_file"
    component_failures=$((component_failures + 1))
  fi
done

printf '%s\n' '=== UNIT_AND_LISTENER_STATE ==='
for unit in redis5.service redis7.service sentinel5.service sentinel7.service orchestrator.service; do
  enabled=$(systemctl is-enabled "$unit" 2>/dev/null || true)
  active=$(systemctl is-active "$unit" 2>/dev/null || true)
  printf 'UNIT|%s|enabled=%s|active=%s\n' "$unit" "${enabled:-unknown}" "${active:-unknown}"
done
ss -lntpH | awk '$4 ~ /10\.2\.203\.113:(6379|6387|26379|26387)$/ {print "LISTENER|"$0}'

safe_config() {
  local label=$1
  local file=$2

  printf '=== SAFE_CONFIG|%s ===\n' "$label"
  awk -v label="$label" '
    /^[[:space:]]*#/ || NF == 0 {next}
    $1 == "sentinel" && $2 == "monitor" {
      printf "CONFIG|%s|monitor_name=%s|master_ip=%s|master_port=%s|quorum=%s\n", label,$3,$4,$5,$6
      next
    }
    $1 == "sentinel" && $2 == "auth-pass" {
      printf "CONFIG|%s|auth_pass_name=%s|auth_pass_present=YES\n",label,$3
      next
    }
    $1 == "sentinel" && $2 == "myid" {
      printf "CONFIG|%s|sentinel_myid_present=YES\n",label
      myid=1
      next
    }
    $1 == "sentinel" && $2 == "announce-ip" {
      printf "CONFIG|%s|announce_ip=%s\n",label,$3
      next
    }
    $1 == "sentinel" && $2 == "announce-port" {
      printf "CONFIG|%s|announce_port=%s\n",label,$3
      next
    }
    $1 == "announce-ip" {
      printf "CONFIG|%s|announce_ip=%s\n",label,$2
      next
    }
    $1 == "announce-port" {
      printf "CONFIG|%s|announce_port=%s\n",label,$2
      next
    }
    $1 == "bind" {
      printf "CONFIG|%s|bind=%s\n",label,$2
      next
    }
    $1 == "port" {
      printf "CONFIG|%s|port=%s\n",label,$2
      next
    }
    $1 == "protected-mode" {
      printf "CONFIG|%s|protected_mode=%s\n",label,$2
      next
    }
    END {
      if (!myid) printf "CONFIG|%s|sentinel_myid_present=NO\n",label
    }
  ' "$file"
}

safe_config sentinel5 "$CONF5"
safe_config sentinel7 "$CONF7"

tcp_probe() {
  local host=$1
  local port=$2

  if timeout 5 bash -c "exec 3<>/dev/tcp/${host}/${port}" 2>/dev/null; then
    printf 'TCP|%s:%s|PASS\n' "$host" "$port"
  else
    printf 'TCP|%s:%s|FAIL\n' "$host" "$port"
    component_failures=$((component_failures + 1))
  fi
}

printf '%s\n' '=== TCP_FROM_REDIS02_TO_REDIS01 ==='
for port in 6379 6387 26379 26387; do
  tcp_probe 10.2.203.112 "$port"
done

redis_probe() {
  local label=$1
  local cli=$2
  local password_file=$3
  local host=$4
  local port=$5
  local mode=$6
  local output

  if output=$(REDISCLI_AUTH="$(<"$password_file")" "$cli" --no-auth-warning -h "$host" -p "$port" PING 2>&1); then
    if test "$output" = 'PONG'; then
      printf 'AUTH_PING|%s|%s:%s|PONG\n' "$label" "$host" "$port"
    else
      printf 'AUTH_PING|%s|%s:%s|UNEXPECTED_RESPONSE\n' "$label" "$host" "$port"
      component_failures=$((component_failures + 1))
    fi
  else
    printf 'AUTH_PING|%s|%s:%s|FAIL\n' "$label" "$host" "$port"
    component_failures=$((component_failures + 1))
  fi

  if test "$mode" = redis; then
    if output=$(REDISCLI_AUTH="$(<"$password_file")" "$cli" --no-auth-warning -h "$host" -p "$port" INFO replication 2>&1); then
      printf '%s\n' "$output" | awk -F: -v label="$label" '
        $1 ~ /^(role|master_host|master_port|master_link_status|master_sync_in_progress|connected_slaves)$/ {
          gsub(/\r/,"",$2)
          print "REPLICATION|"label"|"$1"="$2
        }
      '
    else
      printf 'REPLICATION|%s|FAIL\n' "$label"
      component_failures=$((component_failures + 1))
    fi
  fi
}

printf '%s\n' '=== AUTHENTICATED_ENDPOINT_PROBES ==='
redis_probe redis02-sentinel5 "$CLI5" "$PW5" 10.2.203.113 26379 sentinel
redis_probe redis02-sentinel7 "$CLI7" "$PW7" 10.2.203.113 26387 sentinel
redis_probe redis01-sentinel5 "$CLI5" "$PW5" 10.2.203.112 26379 sentinel
redis_probe redis01-sentinel7 "$CLI7" "$PW7" 10.2.203.112 26387 sentinel
redis_probe redis01-master5 "$CLI5" "$PW5" 10.2.203.112 6379 redis
redis_probe redis01-master7 "$CLI7" "$PW7" 10.2.203.112 6387 redis
redis_probe redis02-replica5 "$CLI5" "$PW5" 10.2.203.113 6379 redis
redis_probe redis02-replica7 "$CLI7" "$PW7" 10.2.203.113 6387 redis

sentinel_query() {
  local label=$1
  local cli=$2
  local password_file=$3
  local port=$4
  local master_name=$5
  local operation
  local output

  printf '=== SENTINEL_QUERY|%s|%s ===\n' "$label" "$master_name"

  for operation in master replicas sentinels; do
    if output=$(REDISCLI_AUTH="$(<"$password_file")" "$cli" --no-auth-warning -h 10.2.203.113 -p "$port" --raw SENTINEL "$operation" "$master_name" 2>&1); then
      printf '%s\n' "$output" | awk -v label="$label" -v op="$operation" '
        {
          if (pending == "") {
            pending=$0
          } else {
            key=pending
            value=$0
            pending=""
            if (key ~ /^(name|ip|port|flags|master-host|master-port|quorum|num-slaves|num-other-sentinels|down-after-milliseconds|failover-timeout|parallel-syncs)$/)
              print "SENTINEL|"label"|"op"|"key"="value
          }
        }
      '
    else
      printf 'SENTINEL|%s|%s|FAIL\n' "$label" "$operation"
      component_failures=$((component_failures + 1))
    fi
  done

  if output=$(REDISCLI_AUTH="$(<"$password_file")" "$cli" --no-auth-warning -h 10.2.203.113 -p "$port" SENTINEL ckquorum "$master_name" 2>&1); then
    printf 'SENTINEL|%s|ckquorum=%s\n' "$label" "$output"
  else
    printf 'SENTINEL|%s|ckquorum=%s\n' "$label" "$output"
    component_failures=$((component_failures + 1))
  fi
}

sentinel_query sentinel5 "$CLI5" "$PW5" 26379 sanquan-redis5
sentinel_query sentinel7 "$CLI7" "$PW7" 26387 sanquan-redis7

printf '%s\n' '=== ERROR_ONLY_JOURNAL ==='
for unit in sentinel5.service sentinel7.service redis5.service redis7.service; do
  printf 'JOURNAL|%s\n' "$unit"
  journalctl -u "$unit" --since '-30 min' --no-pager 2>/dev/null |
    grep -Ei 'error|fail|denied|noquorum|sdown|odown|cannot|can.t|refused|timeout|no route|master.*down|link.*down' |
    tail -n 40 || true
done

printf 'DIAGNOSTIC_COMPONENT_FAILURES=%s\n' "$component_failures"
printf '%s\n' 'REDIS02_SENTINEL_TOPOLOGY_DIAGNOSIS=PASS_READ_ONLY'
