#!/usr/bin/env bash
#
# wal-retention.sh — poda do WAL arquivado (G-14 / UPDATE_INFRA I7).
#
# O `archive_command` copia cada segmento para `${PGDATA}/wal_archive` e **nada** apagava:
# o diretório cresce até encher o disco. A política é por **idade** (não há base backup
# contínuo; o `pg_dump` lógico não depende de WAL). O PITR usa os segmentos da janela.
#
# Uso:
#   tools/wal-retention.sh                  # poda além de WAL_RETENTION_DAYS (padrão 14)
#   tools/wal-retention.sh --days 7
#   tools/wal-retention.sh --dry-run        # lista o que sairia, não apaga
#   tools/wal-retention.sh --dir /caminho   # diretório local (teste/inspeção), sem Docker
#   tools/wal-retention.sh --json           # evidência para o log de operação
#
# Segurança: `--days` < 1 é recusado; a poda nunca toca `pg_wal` (o WAL ativo do cluster),
# só o arquivo morto em `wal_archive`.
set -Eeuo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

DAYS="${WAL_RETENTION_DAYS:-14}"
DRY_RUN=0
JSON=0
DIR=""

usage() {
    sed -n '3,15p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
    exit "${1:-0}"
}

while [ $# -gt 0 ]; do
    case "$1" in
        --days) shift; DAYS="${1:-}" ;;
        --days=*) DAYS="${1#*=}" ;;
        --dry-run) DRY_RUN=1 ;;
        --json) JSON=1 ;;
        --dir) shift; DIR="${1:-}" ;;
        --dir=*) DIR="${1#*=}" ;;
        -h | --help) usage 0 ;;
        *) echo "flag desconhecida: $1" >&2; usage 2 ;;
    esac
    shift
done

case "$DAYS" in
    '' | *[!0-9]*) echo "ERRO: --days precisa ser inteiro positivo (recebido: '$DAYS')." >&2; exit 2 ;;
esac
[ "$DAYS" -ge 1 ] || { echo 'ERRO: --days < 1 apagaria WAL ainda necessário ao PITR.' >&2; exit 2; }

# Executa no container (produção) ou no diretório local (`--dir`, testes).
# `$1` do script é sempre o diretório do arquivo; os demais são parâmetros.
if [ -n "$DIR" ]; then
    [ -d "$DIR" ] || { echo "ERRO: diretório inexistente: $DIR" >&2; exit 2; }
    ARCHIVE="$DIR"
    run_sh() {
        local script="$1"
        shift
        sh -c "$script" sh "$ARCHIVE" "$@"
    }
else
    [ -f .env ] || { echo "'.env' ausente." >&2; exit 2; }
    PROJECT="$(bash "$ROOT/tools/project-name.sh" 2>/dev/null)"
    # shellcheck source=tools/runtime.sh
    . "$ROOT/tools/runtime.sh"
    COMPOSE=("${ENGINE[@]}" compose -p "$PROJECT" --env-file .env "${COMPOSE_FILES[@]}")
    ARCHIVE="$("${COMPOSE[@]}" exec -T postgres sh -c 'printf %s "${PGDATA:-/var/lib/postgresql/pgdata}/wal_archive"')"
    ARCHIVE="${ARCHIVE%$'\r'}"
    run_sh() {
        local script="$1"
        shift
        "${COMPOSE[@]}" exec -T postgres sh -c "$script" sh "$ARCHIVE" "$@"
    }
fi

[ -n "$ARCHIVE" ] || { echo 'ERRO: não foi possível resolver o wal_archive.' >&2; exit 1; }

before_bytes="$(run_sh 'du -sb "$1" 2>/dev/null | cut -f1' | tr -d '[:space:]' || true)"
before_bytes="${before_bytes:-0}"

find_script='find "$1" -type f -mtime "+$2" -print'
if [ "$DRY_RUN" = 0 ]; then
    find_script="$find_script -delete"
fi
removed="$(run_sh "$find_script" "$DAYS" | wc -l)"
removed="${removed//[^0-9]/}"

after_bytes="$(run_sh 'du -sb "$1" 2>/dev/null | cut -f1' | tr -d '[:space:]' || true)"
after_bytes="${after_bytes:-$before_bytes}"

freed=$((before_bytes > after_bytes ? before_bytes - after_bytes : 0))

if [ "$JSON" = 1 ]; then
    printf '{"event":"db.wal_retention","archive":"%s","days":%s,"files":%s,"freed_bytes":%s,"remaining_bytes":%s,"dry_run":%s}\n' \
        "$ARCHIVE" "$DAYS" "$removed" "$freed" "$after_bytes" \
        "$([ "$DRY_RUN" = 1 ] && echo true || echo false)"
else
    printf '%s: %s arquivo(s) %s · %s bytes liberados · %s bytes restantes (retenção: %s dias)%s\n' \
        "$ARCHIVE" "$removed" "$([ "$DRY_RUN" = 1 ] && echo 'seriam removidos' || echo 'removidos')" \
        "$freed" "$after_bytes" "$DAYS" "$([ "$DRY_RUN" = 1 ] && echo ' [dry-run]' || echo '')"
fi
