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

# Snapshot incremental con hardlinks para /var/www/desarrollo/public_html.
# Permite diagnosticar fallos de permisos, rutas, rsync, cron y borrado.

BASE="${BASE:-/var/www/desarrollo/public_html}"
SNAPROOT="${SNAPROOT:-/var/www/.snapshots_desarrollo}"
RETENTION_DAYS="${RETENTION_DAYS:-30}"
LOGFILE="${LOGFILE:-$SNAPROOT/snapshot.log}"

log() {
  printf '[%s] %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*"
}

die() {
  log "ERROR: $*"
  exit 1
}

on_error() {
  local exit_code=$?
  local line_no=${1:-?}
  local cmd=${BASH_COMMAND:-?}
  log "FALLO: codigo=$exit_code linea=$line_no comando=$cmd"
  exit "$exit_code"
}

trap 'on_error "$LINENO"' ERR

mkdir -p "$SNAPROOT"
touch "$LOGFILE" || {
  printf 'ERROR: no puedo escribir el log en %s\n' "$LOGFILE" >&2
  exit 1
}
exec >>"$LOGFILE" 2>&1

log "Inicio snapshot desarrollo"
log "BASE=$BASE"
log "SNAPROOT=$SNAPROOT"
log "RETENTION_DAYS=$RETENTION_DAYS"
log "Usuario=$(id -un) UID=$(id -u)"
log "Host=$(hostname)"
log "PATH=$PATH"

command -v rsync >/dev/null 2>&1 || die "rsync no esta instalado o no esta en PATH"
command -v find >/dev/null 2>&1 || die "find no esta instalado o no esta en PATH"
command -v date >/dev/null 2>&1 || die "date no esta instalado o no esta en PATH"

[ -d "$BASE" ] || die "BASE no existe o no es un directorio: $BASE"
[ -r "$BASE" ] || die "BASE no se puede leer: $BASE"
[ -d "$SNAPROOT" ] || die "SNAPROOT no existe o no es un directorio: $SNAPROOT"
[ -w "$SNAPROOT" ] || die "SNAPROOT no se puede escribir: $SNAPROOT"
[[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]] || die "RETENTION_DAYS debe ser numerico: $RETENTION_DAYS"

TS="$(date -u '+@GMT-%Y.%m.%d-%H.%M.%S')"
DEST="$SNAPROOT/$TS"

PREV="$(find "$SNAPROOT" -mindepth 1 -maxdepth 1 -type d -name '@GMT-*' -printf '%f\n' 2>/dev/null | sort | tail -n 1 || true)"
[ ! -e "$DEST" ] || die "Ya existe el snapshot destino: $DEST"
mkdir "$DEST"
log "Snapshot destino=$DEST"

if [ -n "${PREV:-}" ] && [ -d "$SNAPROOT/$PREV" ]; then
  log "Snapshot anterior=$SNAPROOT/$PREV"
  rsync -a --delete --stats --link-dest="$SNAPROOT/$PREV" "$BASE/" "$DEST/"
else
  log "No hay snapshot anterior; copia completa"
  rsync -a --stats "$BASE/" "$DEST/"
fi

log "Aplicando retencion: $RETENTION_DAYS dias"
while IFS= read -r -d '' old_snapshot; do
  case "$old_snapshot" in
    "$SNAPROOT"/@GMT-*)
      log "Borrando snapshot antiguo: $old_snapshot"
      rm -rf -- "$old_snapshot"
      ;;
    *)
      die "Ruta inesperada en retencion, no borro: $old_snapshot"
      ;;
  esac
done < <(find "$SNAPROOT" -mindepth 1 -maxdepth 1 -type d -name '@GMT-*' -mtime +"$RETENTION_DAYS" -print0)

log "Snapshot completado correctamente"
