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

MODE="dry-run"
DELETE_INDEXES=0
ALLOW_INSECURE=0
CONFIRM=""
REPORT_DIR="/var/tmp/wazuh-lab-cleanup"
WAZUH_ROOT="/var/ossec"

usage() {
  cat <<'EOF'
Usage: sudo ./cleanup-wazuh-lab_v20.sh [--dry-run] [--execute --confirm CLEAN-WAZUH-LAB]
       [--delete-indexes] [--allow-insecure] [--report-dir DIR]

Dry-run is the default. Index deletion additionally requires:
  WAZUH_INDEXER_URL=https://127.0.0.1:9200
  WAZUH_INDEXER_USER=<user>
  WAZUH_INDEXER_PASSWORD=<password>
  WAZUH_INDEXER_CA=/etc/wazuh-indexer/certs/root-ca.pem

Only wazuh-alerts-4.x-* and wazuh-archives-4.x-* are eligible for deletion.
Index deletion also requires WAZUH_SNAPSHOT_REPOSITORY. A dated snapshot must
finish successfully before either index pattern can be deleted.
EOF
}

while (($#)); do
  case "$1" in
    --dry-run) MODE="dry-run" ;;
    --execute) MODE="execute" ;;
    --delete-indexes) DELETE_INDEXES=1 ;;
    --allow-insecure) ALLOW_INSECURE=1 ;;
    --confirm) shift; CONFIRM="${1:-}" ;;
    --report-dir) shift; REPORT_DIR="${1:-}" ;;
    -h|--help) usage; exit 0 ;;
    *) echo "ERROR: unknown option: $1" >&2; usage >&2; exit 2 ;;
  esac
  shift
done

[[ $EUID -eq 0 ]] || { echo "ERROR: run as root." >&2; exit 1; }
[[ -d "$WAZUH_ROOT" ]] || { echo "ERROR: $WAZUH_ROOT not found." >&2; exit 1; }
if [[ "$MODE" == execute && "$CONFIRM" != CLEAN-WAZUH-LAB ]]; then
  echo "ERROR: execution requires --confirm CLEAN-WAZUH-LAB" >&2
  exit 2
fi

STAMP=$(date -u +%Y%m%dT%H%M%SZ)
RUN_DIR="$REPORT_DIR/$STAMP"
mkdir -p "$RUN_DIR"
RUN_REAL=$(realpath -e "$RUN_DIR")
case "$RUN_REAL" in
  "$WAZUH_ROOT"|"$WAZUH_ROOT"/*)
    echo "ERROR: report directory must not be inside $WAZUH_ROOT" >&2; exit 2 ;;
esac
LOG="$RUN_DIR/run.log"
exec > >(tee -a "$LOG") 2>&1

for required_log_dir in "$WAZUH_ROOT/logs/alerts" "$WAZUH_ROOT/logs/archives"; do
  [[ -d "$required_log_dir" && ! -L "$required_log_dir" ]] || {
    echo "ERROR: required Wazuh log directory is missing or symlinked: $required_log_dir" >&2; exit 2;
  }
  [[ "$(realpath -e "$required_log_dir")" == "$required_log_dir" ]] || {
    echo "ERROR: Wazuh log directory resolves outside its expected path: $required_log_dir" >&2; exit 2;
  }
done

PROTECTED=(
  "$WAZUH_ROOT/etc"
  "$WAZUH_ROOT/ruleset"
  "$WAZUH_ROOT/agentless"
  "$WAZUH_ROOT/active-response/bin"
  "/etc/filebeat"
  "/etc/wazuh-indexer"
  "/etc/wazuh-dashboard"
)

manifest() {
  local out="$1" p
  : > "$out"
  for p in "${PROTECTED[@]}"; do
    [[ -e "$p" ]] || continue
    if [[ -d "$p" ]]; then
      find -P "$p" -xdev -type f -print0
    else
      printf '%s\0' "$p"
    fi
  done | sort -z | xargs -0 -r sha256sum > "$out"
}

show_targets() {
  local d
  for d in "$WAZUH_ROOT/logs/alerts" "$WAZUH_ROOT/logs/archives"; do
    [[ -d "$d" ]] && find -P "$d" -xdev -type f -printf '%s\t%p\n' | sort -k2
  done
}

echo "Wazuh lab cleanup | mode=$MODE | UTC=$STAMP"
[[ -s "$WAZUH_ROOT/etc/client.keys" ]] || {
  echo "ERROR: required nonempty agent enrollment file is missing: $WAZUH_ROOT/etc/client.keys" >&2
  exit 3
}
manifest "$RUN_DIR/config-before.sha256"
cp -a "$WAZUH_ROOT/etc/client.keys" "$RUN_DIR/client.keys.$STAMP.bak"
show_targets | tee "$RUN_DIR/local-targets.tsv"

curl_indexer() {
  local method="$1" path="$2"
  shift 2
  local args=(--silent --show-error --fail-with-body --request "$method"
    --user "${WAZUH_INDEXER_USER}:${WAZUH_INDEXER_PASSWORD}"
    "${WAZUH_INDEXER_URL%/}$path")
  if [[ -n "${WAZUH_INDEXER_CA:-}" ]]; then args+=(--cacert "$WAZUH_INDEXER_CA")
  elif ((ALLOW_INSECURE)); then args+=(--insecure)
  else echo "ERROR: set WAZUH_INDEXER_CA or explicitly use --allow-insecure" >&2; return 2
  fi
  curl "${args[@]}" "$@"
}

if ((DELETE_INDEXES)); then
  : "${WAZUH_INDEXER_URL:?Set WAZUH_INDEXER_URL}"
  : "${WAZUH_INDEXER_USER:?Set WAZUH_INDEXER_USER}"
  : "${WAZUH_INDEXER_PASSWORD:?Set WAZUH_INDEXER_PASSWORD}"
  curl_indexer GET '/_cat/indices/wazuh-alerts-4.x-*,wazuh-archives-4.x-*?h=index,docs.count,store.size&s=index&expand_wildcards=open,closed' \
    | tee "$RUN_DIR/index-targets.tsv"
fi

if [[ "$MODE" == dry-run ]]; then
  echo "DRY-RUN COMPLETE: no services, files, indices, configurations, or enrollments changed."
  exit 0
fi

# Mandatory dated backups. No cleanup begins unless both archives verify.
CONFIG_BAK="$RUN_DIR/wazuh-protected-config-$STAMP.tar.gz.bak"
LOG_BAK="$RUN_DIR/wazuh-generated-logs-$STAMP.tar.gz.bak"
config_items=(var/ossec/etc var/ossec/ruleset)
[[ -d /etc/filebeat ]] && config_items+=(etc/filebeat)
[[ -d /etc/wazuh-indexer ]] && config_items+=(etc/wazuh-indexer)
[[ -d /etc/wazuh-dashboard ]] && config_items+=(etc/wazuh-dashboard)
tar -czf "$CONFIG_BAK" -C / "${config_items[@]}"
tar -tzf "$CONFIG_BAK" >/dev/null
tar -czf "$LOG_BAK" -C / var/ossec/logs/alerts var/ossec/logs/archives
tar -tzf "$LOG_BAK" >/dev/null
echo "Backups verified: $CONFIG_BAK ; $LOG_BAK"

if ((DELETE_INDEXES)); then
  : "${WAZUH_SNAPSHOT_REPOSITORY:?Set WAZUH_SNAPSHOT_REPOSITORY to a configured snapshot repository}"
  [[ "$WAZUH_SNAPSHOT_REPOSITORY" =~ ^[A-Za-z0-9._-]+$ ]] || {
    echo "ERROR: invalid snapshot repository name." >&2; exit 2;
  }
  SNAPSHOT_NAME="lab-cleanup-${STAMP,,}"
  SNAPSHOT_BODY='{"indices":"wazuh-alerts-4.x-*,wazuh-archives-4.x-*","ignore_unavailable":true,"include_global_state":false,"metadata":{"purpose":"pre-student-lab-cleanup"}}'
  curl_indexer PUT "/_snapshot/$WAZUH_SNAPSHOT_REPOSITORY/$SNAPSHOT_NAME?wait_for_completion=true" \
    -H 'Content-Type: application/json' -d "$SNAPSHOT_BODY" | tee "$RUN_DIR/index-snapshot-result.json"
  grep -Eq '"state"[[:space:]]*:[[:space:]]*"SUCCESS"' "$RUN_DIR/index-snapshot-result.json" || {
    echo "ERROR: index snapshot did not report SUCCESS; no indices deleted." >&2; exit 5;
  }
fi

manager_was_active=0; filebeat_was_active=0
systemctl is-active --quiet wazuh-manager && manager_was_active=1
systemctl is-active --quiet filebeat && filebeat_was_active=1
trap 'rc=$?; ((manager_was_active)) && systemctl start wazuh-manager || true; ((filebeat_was_active)) && systemctl start filebeat || true; exit $rc' EXIT

((filebeat_was_active)) && systemctl stop filebeat
((manager_was_active)) && systemctl stop wazuh-manager

find -P "$WAZUH_ROOT/logs/alerts" "$WAZUH_ROOT/logs/archives" -xdev -type f -delete
if ((DELETE_INDEXES)); then
  : > "$RUN_DIR/index-delete-results.jsonl"
  while read -r index _; do
    [[ -n "$index" ]] || continue
    [[ "$index" =~ ^wazuh-(alerts|archives)-4\.x-[A-Za-z0-9._-]+$ ]] || {
      echo "CRITICAL: refusing unexpected index name from inventory: $index" >&2; exit 6;
    }
    curl_indexer DELETE "/$index" | tee -a "$RUN_DIR/index-delete-results.jsonl"
    printf '\n' >> "$RUN_DIR/index-delete-results.jsonl"
  done < "$RUN_DIR/index-targets.tsv"
fi

((manager_was_active)) && systemctl start wazuh-manager
((filebeat_was_active)) && systemctl start filebeat
manager_was_active=0; filebeat_was_active=0
manifest "$RUN_DIR/config-after.sha256"
if ! diff -u "$RUN_DIR/config-before.sha256" "$RUN_DIR/config-after.sha256" > "$RUN_DIR/config-diff.txt"; then
  echo "CRITICAL: protected configuration changed; inspect $RUN_DIR/config-diff.txt" >&2
  exit 3
fi

[[ -s "$WAZUH_ROOT/etc/client.keys" ]] || { echo "CRITICAL: client.keys is missing or empty." >&2; exit 3; }
systemctl is-active --quiet wazuh-manager || { echo "ERROR: wazuh-manager is not active." >&2; exit 4; }
echo "PASS: generated logs removed; protected configuration and agent keys unchanged."
