#!/usr/bin/env bash
# ANDANILY INTERACTIVE - DIAGNOSTIC 00
# Server Capability Audit
# Non-destructive: reads environment/capabilities and writes diagnostic output only.

set -u
umask 077

ROOT="/home/smansin1/andanily"
DOMAIN="andanily.my.id"
STAMP="$(date '+%Y%m%d-%H%M%S' 2>/dev/null || echo unknown-time)"
OUTBASE="$ROOT/diagnostics"
OUTDIR="$OUTBASE/diag-00-$STAMP"
REPORT="$OUTDIR/ANDANILY-DIAG-00-REPORT.txt"
SUMMARY="$OUTDIR/ANDANILY-DIAG-00-SUMMARY.txt"
RESULT_ZIP="$ROOT/ANDANILY-DIAG-00-RESULT-$STAMP.zip"
RESULT_TGZ="$ROOT/ANDANILY-DIAG-00-RESULT-$STAMP.tar.gz"

mkdir -p "$OUTDIR" || {
  echo "ERROR: Cannot create $OUTDIR"
  exit 1
}

touch "$REPORT" "$SUMMARY" || {
  echo "ERROR: Cannot write diagnostic files in $OUTDIR"
  exit 1
}

log() {
  printf '%s\n' "$*" | tee -a "$REPORT"
}

sum() {
  printf '%s\n' "$*" | tee -a "$SUMMARY"
}

section() {
  log ""
  log "================================================================"
  log "$1"
  log "================================================================"
}

have() {
  command -v "$1" >/dev/null 2>&1
}

safe_cmd() {
  local label="$1"
  shift
  log ""
  log "--- $label ---"
  if "$@" >>"$REPORT" 2>&1; then
    log "[OK] $label"
  else
    local rc=$?
    log "[WARN] $label returned exit code $rc"
  fi
}

value_cmd() {
  local label="$1"
  shift
  local out
  out="$("$@" 2>&1 | head -n 5)"
  log "$label: ${out:-<no output>}"
}

php_ini_value() {
  local key="$1"
  if have php; then
    php -r "echo ini_get('$key');" 2>/dev/null
  fi
}

php_has_ext() {
  local ext="$1"
  if have php && php -m 2>/dev/null | grep -qiE "^${ext}$"; then
    return 0
  fi
  return 1
}

port_test() {
  if ! have php || ! have curl; then
    log "Loopback bind test: SKIPPED (php/curl missing)"
    return
  fi

  local port
  port=$((20000 + RANDOM % 20000))
  local tmp="$OUTDIR/loopback-test"
  mkdir -p "$tmp"
  printf 'ANDANILY_LOOPBACK_OK\n' > "$tmp/index.html"

  php -S "127.0.0.1:$port" -t "$tmp" >"$OUTDIR/php-loopback.log" 2>&1 &
  local pid=$!
  sleep 1

  if curl -fsS --max-time 3 "http://127.0.0.1:$port/" 2>/dev/null | grep -q "ANDANILY_LOOPBACK_OK"; then
    log "Loopback TCP bind/background-process short test: PASS (port $port)"
    LOOPBACK_PASS="yes"
  else
    log "Loopback TCP bind/background-process short test: FAIL/RESTRICTED"
    LOOPBACK_PASS="no"
  fi

  kill "$pid" >/dev/null 2>&1 || true
  wait "$pid" >/dev/null 2>&1 || true
}

section "ANDANILY INTERACTIVE - DIAGNOSTIC 00"
log "Timestamp           : $STAMP"
log "Target root         : $ROOT"
log "Target domain       : $DOMAIN"
log "Running user        : $(whoami 2>/dev/null || echo unknown)"
log "Current directory   : $(pwd 2>/dev/null || echo unknown)"
log "Hostname            : $(hostname 2>/dev/null || echo unknown)"
log "Kernel              : $(uname -srmo 2>/dev/null || uname -a 2>/dev/null || echo unknown)"
log "Timezone            : $(date '+%Z %z' 2>/dev/null || echo unknown)"
log "OS release          : $(grep -E '^PRETTY_NAME=' /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"' || echo unavailable)"

section "1. ROOT PATH / FILESYSTEM"
if [ -d "$ROOT" ]; then
  log "Root exists         : YES"
  safe_cmd "Root permissions" ls -ld "$ROOT"
  safe_cmd "Filesystem usage" df -h "$ROOT"
  if have df; then
    safe_cmd "Filesystem inode usage" df -i "$ROOT"
  fi
  if have quota; then
    safe_cmd "User quota (if available)" quota -s
  else
    log "quota command       : not available"
  fi

  TESTFILE="$OUTDIR/write-test-$STAMP.tmp"
  if printf 'write-test\n' > "$TESTFILE" 2>/dev/null; then
    log "Write test          : PASS"
    if mv "$TESTFILE" "$TESTFILE.renamed" 2>/dev/null; then
      log "Atomic rename test  : PASS"
      rm -f "$TESTFILE.renamed"
    else
      log "Atomic rename test  : FAIL"
      rm -f "$TESTFILE"
    fi
  else
    log "Write test          : FAIL"
  fi

  if ln -s "$REPORT" "$OUTDIR/symlink-test" 2>/dev/null; then
    log "Symlink test        : PASS"
    rm -f "$OUTDIR/symlink-test"
  else
    log "Symlink test        : FAIL/RESTRICTED"
  fi
else
  log "Root exists         : NO"
fi

section "2. CPANEL / HOSTING ENVIRONMENT"
if [ -f /usr/local/cpanel/version ]; then
  log "cPanel detected     : YES"
  log "cPanel version      : $(cat /usr/local/cpanel/version 2>/dev/null || echo unreadable)"
else
  log "cPanel detected     : not confirmed from /usr/local/cpanel/version"
fi

for cmd in uapi whmapi1 selectorctl cloudlinux-summary cagefsctl; do
  if have "$cmd"; then
    log "$cmd path          : $(command -v "$cmd")"
    value_cmd "$cmd version/info" "$cmd" --version
  else
    log "$cmd               : not available"
  fi
done

if [ -n "${LSWS_EDITION:-}" ]; then
  log "LiteSpeed env       : $LSWS_EDITION"
fi

section "3. DOMAIN / HTTP / HTTPS"
if have getent; then
  safe_cmd "DNS resolution (getent)" getent ahosts "$DOMAIN"
elif have nslookup; then
  safe_cmd "DNS resolution (nslookup)" nslookup "$DOMAIN"
elif have dig; then
  safe_cmd "DNS resolution (dig)" dig +short "$DOMAIN"
else
  log "DNS tools           : unavailable"
fi

if have curl; then
  safe_cmd "HTTPS headers" curl -sS -I -L --max-time 10 "https://$DOMAIN/"
  safe_cmd "HTTP headers" curl -sS -I -L --max-time 10 "http://$DOMAIN/"
else
  log "curl                : not available"
fi

if have openssl && have timeout; then
  log ""
  log "--- TLS certificate summary ---"
  timeout 8 bash -c "echo | openssl s_client -connect '$DOMAIN:443' -servername '$DOMAIN' 2>/dev/null | openssl x509 -noout -subject -issuer -dates" >>"$REPORT" 2>&1 \
    && log "[OK] TLS certificate summary" \
    || log "[WARN] Unable to inspect TLS certificate"
else
  log "TLS cert test       : skipped (openssl/timeout unavailable)"
fi

section "4. PHP"
if have php; then
  log "PHP binary          : $(command -v php)"
  safe_cmd "PHP version" php -v
  log "PHP SAPI            : $(php -r 'echo PHP_SAPI;' 2>/dev/null || echo unknown)"
  log "Loaded php.ini      : $(php --ini 2>/dev/null | awk -F': ' '/Loaded Configuration File/{print $2}' | head -n1)"
  log "Scan ini directory  : $(php --ini 2>/dev/null | awk -F': ' '/Scan for additional .ini files in/{print $2}' | head -n1)"

  for key in memory_limit upload_max_filesize post_max_size max_execution_time max_input_time max_input_vars max_file_uploads allow_url_fopen opcache.enable; do
    log "$key: $(php_ini_value "$key")"
  done

  DISABLED="$(php_ini_value disable_functions)"
  log "disable_functions   : ${DISABLED:-<none reported>}"

  log ""
  log "Selected PHP extensions:"
  EXTENSIONS=(bcmath ctype curl dom exif fileinfo gd iconv intl json mbstring openssl pdo pdo_mysql session simplexml sodium tokenizer xml xmlreader xmlwriter zip imagick redis pcntl sockets)
  for ext in "${EXTENSIONS[@]}"; do
    if php_has_ext "$ext"; then
      log "  [YES] $ext"
    else
      log "  [NO ] $ext"
    fi
  done
else
  log "PHP                 : NOT FOUND in CLI PATH"
fi

section "5. COMPOSER / PHP PACKAGE TOOLING"
if have composer; then
  log "Composer path       : $(command -v composer)"
  safe_cmd "Composer version" composer --version
  safe_cmd "Composer diagnose (limited)" composer diagnose
else
  log "Composer            : not available in PATH"
fi

section "6. NODE / FRONTEND TOOLING"
for cmd in node npm npx yarn pnpm bun; do
  if have "$cmd"; then
    log "$cmd path          : $(command -v "$cmd")"
    value_cmd "$cmd version" "$cmd" --version
  else
    log "$cmd               : not available"
  fi
done

section "7. DATABASE CLIENTS / DRIVERS"
if have mysql; then
  value_cmd "mysql client" mysql --version
else
  log "mysql client        : not available"
fi

if have mariadb; then
  value_cmd "mariadb client" mariadb --version
else
  log "mariadb client      : not available"
fi

if have mysql_config; then
  value_cmd "mysql_config" mysql_config --version
fi

if have php; then
  log "PDO drivers         : $(php -r 'echo implode(", ", PDO::getAvailableDrivers());' 2>/dev/null || echo unavailable)"
fi

section "8. REDIS / CACHE CAPABILITY"
if have redis-cli; then
  value_cmd "redis-cli version" redis-cli --version
  if have timeout; then
    log ""
    log "--- Local Redis ping (no credentials) ---"
    timeout 3 redis-cli -h 127.0.0.1 -p 6379 ping >>"$REPORT" 2>&1 \
      && log "[OK] Local Redis responded without auth" \
      || log "[INFO] Local Redis not reachable without auth / not running"
  fi
else
  log "redis-cli           : not available"
fi

section "9. CRON / QUEUE / LONG-RUNNING PROCESS CAPABILITY"
if have crontab; then
  CRON_COUNT="$(crontab -l 2>/dev/null | grep -Ev '^[[:space:]]*(#|$)' | wc -l | tr -d ' ')"
  log "crontab command     : available"
  log "Current cron count  : ${CRON_COUNT:-0} (commands intentionally not printed)"
else
  log "crontab             : not available"
fi

for cmd in supervisorctl systemctl service nohup setsid screen tmux flock timeout; do
  if have "$cmd"; then
    log "$cmd               : $(command -v "$cmd")"
  else
    log "$cmd               : not available"
  fi
done

safe_cmd "User process limits (ulimit -a)" bash -lc 'ulimit -a'
LOOPBACK_PASS="unknown"
port_test
log "NOTE: Short loopback/background PASS does NOT prove cPanel allows persistent WebSocket workers."

section "10. PDF / IMAGE / OFFICE CONVERSION"
for cmd in pdfinfo pdftoppm pdftocairo gs magick convert identify cwebp mutool qpdf libreoffice soffice; do
  if have "$cmd"; then
    log "$cmd path          : $(command -v "$cmd")"
    case "$cmd" in
      gs) value_cmd "$cmd version" "$cmd" --version ;;
      pdfinfo|pdftoppm|pdftocairo) value_cmd "$cmd version" "$cmd" -v ;;
      magick|convert|identify) value_cmd "$cmd version" "$cmd" -version ;;
      libreoffice|soffice) value_cmd "$cmd version" "$cmd" --version ;;
      *) value_cmd "$cmd version/info" "$cmd" --version ;;
    esac
  else
    log "$cmd               : not available"
  fi
done

section "11. ARCHIVE / DEPLOYMENT TOOLS"
for cmd in unzip zip tar gzip rsync git curl wget openssl; do
  if have "$cmd"; then
    log "$cmd               : $(command -v "$cmd")"
  else
    log "$cmd               : not available"
  fi
done

if have unzip; then
  value_cmd "unzip version" unzip -v
fi
if have git; then
  value_cmd "git version" git --version
fi

section "12. NETWORK / OUTBOUND HTTPS CAPABILITY"
if have curl; then
  # No API secrets; only checks generic outbound TLS reachability.
  if curl -fsS --max-time 8 -o /dev/null "https://www.google.com/generate_204"; then
    log "Outbound HTTPS      : PASS (Google connectivity test)"
    OUTBOUND_HTTPS="yes"
  else
    log "Outbound HTTPS      : FAIL/RESTRICTED"
    OUTBOUND_HTTPS="no"
  fi
else
  log "Outbound HTTPS      : UNKNOWN (curl unavailable)"
  OUTBOUND_HTTPS="unknown"
fi

section "13. BASIC LARAVEL-ORIENTED READINESS"
REQ_EXT=(ctype curl dom fileinfo mbstring openssl pdo tokenizer xml)
MISSING_REQ=()
if have php; then
  for ext in "${REQ_EXT[@]}"; do
    if ! php_has_ext "$ext"; then
      MISSING_REQ+=("$ext")
    fi
  done
fi

if [ "${#MISSING_REQ[@]}" -eq 0 ] && have php && have composer; then
  log "Basic PHP/Composer readiness: PASS"
  BASIC_READY="yes"
else
  log "Basic PHP/Composer readiness: INCOMPLETE"
  BASIC_READY="no"
  log "Missing core extensions: ${MISSING_REQ[*]:-none}"
fi

PDF_READY="no"
if (have pdftoppm || have pdftocairo || php_has_ext imagick) && (have cwebp || have magick || have convert || php_has_ext imagick); then
  PDF_READY="yes"
fi
log "PDF-to-image candidate readiness: $PDF_READY"

AI_READY="no"
if php_has_ext curl && php_has_ext openssl && [ "${OUTBOUND_HTTPS:-unknown}" = "yes" ]; then
  AI_READY="yes"
fi
log "Outbound AI API candidate readiness: $AI_READY"

section "14. PRIVACY / SAFETY NOTE"
log "This diagnostic intentionally does NOT print:"
log "  - .env contents"
log "  - database passwords"
log "  - OAuth client secrets"
log "  - API keys"
log "  - cPanel passwords"
log "  - full cron command contents"

section "15. SUMMARY"
sum "ANDANILY INTERACTIVE - DIAGNOSTIC 00 SUMMARY"
sum "Generated             : $STAMP"
sum "Root path             : $ROOT"
sum "Domain                : $DOMAIN"
sum ""
sum "Basic PHP/Composer readiness : $BASIC_READY"
sum "PDF-to-image candidate       : $PDF_READY"
sum "Outbound HTTPS / AI candidate: $AI_READY"
sum "Short loopback bind test     : $LOOPBACK_PASS"
sum ""
if have php; then
  sum "PHP                   : $(php -r 'echo PHP_VERSION;' 2>/dev/null)"
else
  sum "PHP                   : not found"
fi
if have composer; then
  sum "Composer              : $(composer --version 2>/dev/null | head -n1)"
else
  sum "Composer              : not found"
fi
if have node; then
  sum "Node                  : $(node --version 2>/dev/null)"
else
  sum "Node                  : not found"
fi
if have npm; then
  sum "npm                   : $(npm --version 2>/dev/null)"
else
  sum "npm                   : not found"
fi
sum ""
sum "IMPORTANT:"
sum "- Persistent WebSocket feasibility is NOT concluded by this diagnostic alone."
sum "- Actual realtime strategy will be chosen after reviewing the report."
sum "- No application/configuration files were modified."

cp "$SUMMARY" "$OUTDIR/README-FIRST.txt" 2>/dev/null || true

section "16. PACKAGE RESULT"
if have zip; then
  (
    cd "$OUTBASE" &&
    zip -qr "$RESULT_ZIP" "$(basename "$OUTDIR")"
  )
  if [ -f "$RESULT_ZIP" ]; then
    log "Result package       : $RESULT_ZIP"
    echo ""
    echo "=============================================================="
    echo "DIAGNOSTIC COMPLETE"
    echo "Please download and send this file back:"
    echo "$RESULT_ZIP"
    echo "=============================================================="
    exit 0
  fi
fi

if have tar; then
  tar -czf "$RESULT_TGZ" -C "$OUTBASE" "$(basename "$OUTDIR")" 2>/dev/null || true
  if [ -f "$RESULT_TGZ" ]; then
    log "Result package       : $RESULT_TGZ"
    echo ""
    echo "=============================================================="
    echo "DIAGNOSTIC COMPLETE"
    echo "ZIP utility unavailable; please download and send this file:"
    echo "$RESULT_TGZ"
    echo "=============================================================="
    exit 0
  fi
fi

echo ""
echo "=============================================================="
echo "DIAGNOSTIC COMPLETE"
echo "Could not create an archive automatically."
echo "Please download this folder:"
echo "$OUTDIR"
echo "=============================================================="
