#!/usr/bin/env bash
# Script: clean_plesk_backups.sh
# Autor: Haz Comunicación
# Descr.: Limpia .tzst antiguos de Plesk (y PMM), conservando N recientes, con reporte por email.

set -Eeuo pipefail

########################
# CONFIGURACIÓN
########################
export TZ="America/Mexico_City"

DAYS=5                 # borrar archivos con más de N días
KEEP_RECENT=3          # conservar al menos N archivos más recientes por carpeta
EMAIL="octavioe@hazcomunicacion.com.mx"

# Carpetas de backups locales (agrega/quita según necesites)
DOMAINS=(
  "/var/lib/psa/dumps/clients/Octavio/domains/hazdigital.net"
  "/var/lib/psa/dumps/clients/Octavio/domains/cosh.club"
)

# Limpiar temporales/archives de PMM (muy recomendable)
CLEAN_PMM=true
PMM_DIR="/usr/local/psa/PMM"
PMM_DAYS=7

# Logging
LOGDIR="/var/log"
LOGFILE="${LOGDIR}/plesk_backup_clean.log"
MAX_LOG_SIZE=$((50*1024*1024))  # 50MB, rota si excede

# Binarios requeridos
REQUIRED_CMDS=(find df du date stat awk sort xargs mail flock tee)

########################
# PARÁMETROS
########################
DRY_RUN=false
VERBOSE=false
for arg in "$@"; do
  case "$arg" in
    -n|--dry-run) DRY_RUN=true ;;
    -v|--verbose) VERBOSE=true ;;
    *) echo "Uso: $0 [--dry-run|-n] [--verbose|-v]"; exit 1 ;;
  esac
done

########################
# PRE-CHEQUEOS
########################
for c in "${REQUIRED_CMDS[@]}"; do
  command -v "$c" >/dev/null 2>&1 || { echo "Falta comando: $c"; exit 1; }
done

mkdir -p "$LOGDIR"

# Rotación simple de log por tamaño
if [ -f "$LOGFILE" ]; then
  size=$(stat -c%s "$LOGFILE" || echo 0)
  if [ "$size" -gt "$MAX_LOG_SIZE" ]; then
    mv -f "$LOGFILE" "${LOGFILE}.$(date +'%Y%m%d_%H%M%S').old" || true
  fi
fi

# Lock para evitar concurrencia
LOCKFILE="/var/run/clean_plesk_backups.lock"
exec 200>"$LOCKFILE"
flock -n 200 || { echo "Otro proceso está ejecutándose. Saliendo."; exit 0; }

log() {
  local msg="$1"
  if $VERBOSE; then
    echo -e "$msg" | tee -a "$LOGFILE"
  else
    echo -e "$msg" >> "$LOGFILE"
  fi
}

run() {
  if $DRY_RUN; then
    log "DRY-RUN ➜ $*"
  else
    eval "$@" >> "$LOGFILE" 2>&1
  fi
}

########################
# EJECUCIÓN
########################
FECHA="$(date +'%Y-%m-%d %H:%M:%S')"
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log "📅 Fecha: $FECHA"
log "🧹 Política: borrar > ${DAYS} días y conservar ${KEEP_RECENT} recientes por carpeta"
$DRY_RUN && log "🟡 Modo: DRY-RUN (no se borrará nada)"

DISK_BEFORE="$(df -h / | awk 'NR==2{print $5" usado, " $4" libres de " $2}' )"
log "💽 Disco antes: $DISK_BEFORE"

# Función: limpieza de una carpeta de backups
clean_dir() {
  local DIR="$1"
  [ -d "$DIR" ] || { log "⚠️  Directorio no encontrado: $DIR"; return; }

  log "🔍 Revisando: $DIR"
  local BEFORE_SIZE
  BEFORE_SIZE=$(du -sh "$DIR" 2>/dev/null | awk '{print $1}')
  log "   Tamaño antes: ${BEFORE_SIZE}"

  # 1) Conservar N más recientes (según mtime)
  # Nota: solo .tzst (ajusta si usas .tar/.zip/.psa también)
  mapfile -t files < <(find "$DIR" -type f -name '*.tzst' -printf '%T@ %p\n' | sort -nr | awk '{print $2}')
  local count=${#files[@]}
  if [ "$count" -le "$KEEP_RECENT" ]; then
    log "   Solo ${count} archivos; no se aplicará KEEP_RECENT."
  else
    local keep=("${files[@]:0:$KEEP_RECENT}")
    local rest=("${files[@]:$KEEP_RECENT}")

    # 2) De los restantes, borrar los que sean >DAYS
    if [ "${#rest[@]}" -gt 0 ]; then
      # Filtra por mtime > DAYS
      mapfile -t to_delete < <(
        printf '%s\n' "${rest[@]}" | xargs -r -I{} bash -c '
          f="$1"
          # proteger archivos en curso (tmp/staging)
          case "$f" in
            *.tmp|*.partial|*.staging) exit 1 ;;
          esac
          # mtime > DAYS ?
          find "$f" -type f -mtime +'$DAYS' -print 2>/dev/null
        ' _ {}
      )

      if [ "${#to_delete[@]}" -gt 0 ]; then
        log "   Candidatos a borrar (> ${DAYS} días), manteniendo ${KEEP_RECENT} recientes:"
        printf '      - %s\n' "${to_delete[@]}" >> "$LOGFILE"

        if $DRY_RUN; then
          for f in "${to_delete[@]}"; do log "DRY-RUN: rm -f '$f'"; done
        else
          printf '%s\0' "${to_delete[@]}" | xargs -0 -r rm -f
        fi
      else
        log "   No hay archivos > ${DAYS} días para borrar en $DIR."
      fi
    fi
  fi

  # Resumen por carpeta
  local AFTER_SIZE
  AFTER_SIZE=$(du -sh "$DIR" 2>/dev/null | awk '{print $1}')
  log "   Tamaño después: ${AFTER_SIZE}"
}

# Limpieza por cada dominio
for DIR in "${DOMAINS[@]}"; do
  clean_dir "$DIR"
done

# Limpieza de PMM (temporales/archives viejos)
if $CLEAN_PMM && [ -d "$PMM_DIR" ]; then
  log "🧰 PMM: limpiando temporales/archives > ${PMM_DAYS} días en ${PMM_DIR}"
  local_before=$(du -sh "$PMM_DIR" 2>/dev/null | awk '{print $1}')
  log "   Tamaño PMM antes: $local_before"
  if $DRY_RUN; then
    run "find '$PMM_DIR' -type f -mtime +$PMM_DAYS -printf 'DRY-RUN: %p\n'"
  else
    run "find '$PMM_DIR' -type f -mtime +$PMM_DAYS -delete"
    run "find '$PMM_DIR' -type d -empty -delete"
  fi
  local_after=$(du -sh "$PMM_DIR" 2>/dev/null | awk '{print $1}')
  log "   Tamaño PMM después: $local_after"
fi

DISK_AFTER="$(df -h / | awk 'NR==2{print $5" usado, " $4" libres de " $2}' )"
log "💽 Disco después: $DISK_AFTER"

# Enviar correo
SUBJ="📦 Limpieza de respaldos Plesk: $(date +'%d-%b') — ${DISK_AFTER}"
if command -v mail >/dev/null 2>&1; then
  if $DRY_RUN; then
    log "✉️  (DRY-RUN) No se envía correo."
  else
    mail -s "$SUBJ" "$EMAIL" < "$LOGFILE" || log "⚠️  Error enviando correo (instala mailutils/postfix)."
  fi
else
  log "⚠️  'mail' no está instalado. Instala: apt-get install -y mailutils"
fi

log "✅ Fin de limpieza"

