#!/usr/bin/env bash
# Backup criptat SQLite pentru gateway RAR AUTOPASS (T2/P0-4, evidenta legala L.142/2023).
#
# Foloseste API-ul de backup online SQLite (sqlite3.Connection.backup, stdlib python3) —
# NU `cp`/`rsync`: baza ruleaza in WAL, iar o copie simpla a fisierului .db poate prinde
# tranzactii necheckpoint-ate (copie inconsistenta). python3 e ales ca prim mijloc (nu
# binarul CLI `sqlite3`) pentru ca e garantat prezent in imaginea Docker si pe masina de
# dezvoltare; binarul `sqlite3` e folosit doar daca python3 lipseste (caz neasteptat).
#
# Rezultatul e comprimat (gzip) si criptat simetric (gpg AES256) — snapshot-ul contine
# PII criptat Fernet plus metadate, un backup NECRIPTAT nu e permis.
#
# Utilizare:
#   AUTOPASS_BACKUP_PASSPHRASE_FILE=/run/secrets/backup_pass tools/backup_db.sh
#   AUTOPASS_BACKUP_PASSPHRASE=parola-de-test tools/backup_db.sh
#
# Variabile de mediu:
#   AUTOPASS_DB_PATH                  cale baza sursa (default /data/autopass.db)
#   AUTOPASS_BACKUP_DIR               director destinatie backup-uri (default /data/backups)
#   AUTOPASS_BACKUP_KEEP              cate backup-uri locale pastreaza (default 14)
#   AUTOPASS_BACKUP_PASSPHRASE_FILE   fisier cu parola de criptare (preferat)
#   AUTOPASS_BACKUP_PASSPHRASE        parola de criptare inline (fallback, ex. teste)
#   AUTOPASS_BACKUP_RCLONE_REMOTE     tinta rclone optionala (ex. remote:bucket/autopass)

set -euo pipefail

DB_PATH="${AUTOPASS_DB_PATH:-/data/autopass.db}"
BACKUP_DIR="${AUTOPASS_BACKUP_DIR:-/data/backups}"
KEEP="${AUTOPASS_BACKUP_KEEP:-14}"
RCLONE_REMOTE="${AUTOPASS_BACKUP_RCLONE_REMOTE:-}"

log() { echo "[backup_db] $*"; }
err() { echo "[backup_db] EROARE: $*" >&2; }

CLEANUP_PATHS=()
cleanup() {
    local p
    for p in "${CLEANUP_PATHS[@]:-}"; do
        [[ -n "$p" ]] && rm -rf "$p"
    done
}
trap cleanup EXIT

# --- parola de criptare: fara ea, refuzam sa scriem un backup necriptat ---
if [[ -n "${AUTOPASS_BACKUP_PASSPHRASE_FILE:-}" ]]; then
    if [[ ! -f "$AUTOPASS_BACKUP_PASSPHRASE_FILE" ]]; then
        err "AUTOPASS_BACKUP_PASSPHRASE_FILE indica un fisier inexistent: $AUTOPASS_BACKUP_PASSPHRASE_FILE"
        exit 1
    fi
    PASSPHRASE_FILE="$AUTOPASS_BACKUP_PASSPHRASE_FILE"
elif [[ -n "${AUTOPASS_BACKUP_PASSPHRASE:-}" ]]; then
    PASSPHRASE_FILE="$(mktemp)"
    chmod 600 "$PASSPHRASE_FILE"
    CLEANUP_PATHS+=("$PASSPHRASE_FILE")
    printf '%s' "$AUTOPASS_BACKUP_PASSPHRASE" > "$PASSPHRASE_FILE"
else
    err "lipseste parola de criptare a backup-ului."
    err "seteaza AUTOPASS_BACKUP_PASSPHRASE_FILE (recomandat) sau AUTOPASS_BACKUP_PASSPHRASE."
    err "backup necriptat NU este permis (contine PII criptat Fernet si metadate)."
    exit 1
fi

if [[ ! -f "$DB_PATH" ]]; then
    err "baza de date nu exista: $DB_PATH"
    exit 1
fi

mkdir -p "$BACKUP_DIR"

STAMP="$(date -u +%Y%m%d-%H%M%S)"
TMP_DIR="$(mktemp -d)"
CLEANUP_PATHS+=("$TMP_DIR")
SNAPSHOT="$TMP_DIR/autopass-$STAMP.db"

log "snapshot online din $DB_PATH"
if command -v python3 >/dev/null 2>&1; then
    python3 - "$DB_PATH" "$SNAPSHOT" <<'PYEOF'
import sqlite3
import sys

src = sqlite3.connect(sys.argv[1])
dst = sqlite3.connect(sys.argv[2])
try:
    with dst:
        src.backup(dst)
finally:
    src.close()
    dst.close()
PYEOF
elif command -v sqlite3 >/dev/null 2>&1; then
    sqlite3 "$DB_PATH" ".backup '$SNAPSHOT'"
else
    err "nici python3, nici binarul sqlite3 nu sunt disponibile - nu pot face backup online"
    exit 1
fi

if [[ ! -s "$SNAPSHOT" ]]; then
    err "snapshot-ul rezultat e gol sau lipseste: $SNAPSHOT"
    exit 1
fi

log "comprim (gzip)"
gzip -9 "$SNAPSHOT"
SNAPSHOT_GZ="$SNAPSHOT.gz"

FINAL="$BACKUP_DIR/autopass-$STAMP.db.gz.gpg"
log "criptez simetric (gpg AES256) -> $FINAL"
gpg --batch --yes --symmetric --cipher-algo AES256 \
    --passphrase-file "$PASSPHRASE_FILE" \
    --output "$FINAL" \
    "$SNAPSHOT_GZ"

log "backup scris: $FINAL ($(du -h "$FINAL" | cut -f1))"

# --- retentie locala: pastreaza ultimele $KEEP, sterge restul ---
mapfile -t OLD_BACKUPS < <(ls -1t "$BACKUP_DIR"/autopass-*.db.gz.gpg 2>/dev/null | tail -n "+$((KEEP + 1))")
if [[ "${#OLD_BACKUPS[@]}" -gt 0 ]]; then
    log "sterg ${#OLD_BACKUPS[@]} backup(uri) vechi (pastrez ultimele $KEEP)"
    rm -f "${OLD_BACKUPS[@]}"
fi

# --- upload optional remote ---
if [[ -n "$RCLONE_REMOTE" ]]; then
    if command -v rclone >/dev/null 2>&1; then
        log "upload rclone -> $RCLONE_REMOTE"
        rclone copy "$FINAL" "$RCLONE_REMOTE"
    else
        log "AUTOPASS_BACKUP_RCLONE_REMOTE setat dar rclone nu e instalat - sar peste upload remote"
    fi
else
    log "AUTOPASS_BACKUP_RCLONE_REMOTE nesetat - sar peste upload remote (doar local)"
fi

log "gata."
