#!/usr/bin/env bash
# backup_all — Backup completo del estado del registry: registry.db, operations.db de cada app, y vaults declarados.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../infra/backup_sqlite_db.sh"
source "$SCRIPT_DIR/../infra/rotate_backups.sh"

backup_all() {
    local backup_root="${1:?Arg 1 requerido: backup_root}"
    local start_ts
    start_ts=$(date +%s)

    # --- 1. Localizar FN_REGISTRY_ROOT ---
    local registry_root
    if [[ -n "${FN_REGISTRY_ROOT:-}" && -f "$FN_REGISTRY_ROOT/registry.db" ]]; then
        registry_root="$FN_REGISTRY_ROOT"
    elif [[ -f "$(pwd)/registry.db" ]]; then
        registry_root="$(pwd)"
    else
        echo "ERROR: No se puede localizar registry.db. Setea FN_REGISTRY_ROOT o ejecuta desde la raiz del registry." >&2
        return 1
    fi

    # --- 2. Verificar herramientas del sistema ---
    local missing_tools=()
    for tool in sqlite3 rsync find; do
        command -v "$tool" &>/dev/null || missing_tools+=("$tool")
    done
    if [[ ${#missing_tools[@]} -gt 0 ]]; then
        echo "ERROR: Herramientas faltantes: ${missing_tools[*]}" >&2
        return 5
    fi

    # --- 3. Crear backup_root ---
    if ! mkdir -p "$backup_root/registry" "$backup_root/operations" "$backup_root/vaults"; then
        echo "ERROR: No se puede crear/escribir en $backup_root" >&2
        return 2
    fi

    local log_file="$backup_root/backup_log.txt"
    local iso_ts
    iso_ts=$(date --iso-8601=seconds)
    local ops_count=0
    local vaults_count=0
    local registry_bytes=0
    local partial_errors=0

    # --- 4. Backup registry.db ---
    local snap_registry="/tmp/registry-snap-$$.db"
    if ! backup_sqlite_db "$registry_root/registry.db" "$snap_registry"; then
        echo "ERROR critico: Fallo snapshot de registry.db" >&2
        rm -f "$snap_registry"
        return 3
    fi
    registry_bytes=$(stat -c%s "$snap_registry" 2>/dev/null || echo 0)
    rotate_backups "$backup_root/registry" "$snap_registry" 7 4 12
    rm -f "$snap_registry"

    # --- 5. Backup operations.db de cada app ---
    while IFS= read -r ops_db; do
        local app_dir
        app_dir="$(dirname "$ops_db")"
        local app_name
        app_name="$(basename "$app_dir")"
        local snap_ops="/tmp/ops-snap-$$-${app_name}.db"
        if backup_sqlite_db "$ops_db" "$snap_ops"; then
            rotate_backups "$backup_root/operations/$app_name" "$snap_ops" 7 4 12 || partial_errors=$((partial_errors + 1))
            rm -f "$snap_ops"
            ops_count=$((ops_count + 1))
        else
            echo "WARN: Fallo snapshot de $ops_db — skipped" >&2
            rm -f "$snap_ops"
            partial_errors=$((partial_errors + 1))
        fi
    done < <(find "$registry_root/apps" "$registry_root/projects" -name "operations.db" -maxdepth 4 2>/dev/null || true)

    # --- 6. Backup vaults via rsync + link-dest ---
    local vault_yaml
    while IFS= read -r vault_yaml; do
        if [[ ! -f "$vault_yaml" ]]; then continue; fi
        # Parsear entradas de vault.yaml: buscar pares name/path
        local current_name=""
        while IFS= read -r line; do
            if [[ "$line" =~ ^[[:space:]]*-[[:space:]]*name:[[:space:]]*(.+)$ ]]; then
                current_name="${BASH_REMATCH[1]}"
            elif [[ "$line" =~ ^[[:space:]]*path:[[:space:]]*(.+)$ && -n "$current_name" ]]; then
                local vault_path="${BASH_REMATCH[1]}"
                # Strip surrounding quotes ("..." o '...')
                vault_path="${vault_path%\"}"
                vault_path="${vault_path#\"}"
                vault_path="${vault_path%\'}"
                vault_path="${vault_path#\'}"
                # Expandir ~ si fuera necesario
                vault_path="${vault_path/#\~/$HOME}"
                if [[ ! -d "$vault_path" ]]; then
                    echo "WARN: Vault '$current_name' path '$vault_path' no existe — skipped" >&2
                    partial_errors=$((partial_errors + 1))
                    current_name=""
                    continue
                fi
                local vault_dest="$backup_root/vaults/$current_name"
                mkdir -p "$vault_dest"
                local link_dest="$vault_dest/daily.1"
                local tmp_dest="$vault_dest/daily.0.tmp"
                rm -rf "$tmp_dest"
                if [[ -d "$link_dest" ]]; then
                    rsync -a --link-dest="$link_dest" "$vault_path/" "$tmp_dest/"
                else
                    rsync -a "$vault_path/" "$tmp_dest/"
                fi
                # Rotacion manual de directorios (7 daily, 4 weekly, 12 monthly)
                _rotate_vault_dirs "$vault_dest" 7 4 12
                mv "$tmp_dest" "$vault_dest/daily.0"
                vaults_count=$((vaults_count + 1))
                current_name=""
            fi
        done < "$vault_yaml"
    done < <(find "$registry_root/projects" -name "vault.yaml" -maxdepth 4 2>/dev/null || true)

    # --- 7. Log y stdout ---
    local end_ts elapsed
    end_ts=$(date +%s)
    elapsed=$(( end_ts - start_ts ))
    local summary="${iso_ts} registry=${registry_bytes}B ops=${ops_count} vaults=${vaults_count} partial_errors=${partial_errors} elapsed=${elapsed}s"
    echo "$summary" >> "$log_file"
    echo "$summary"

    if [[ $partial_errors -gt 0 ]]; then
        echo "WARN: $partial_errors errores parciales (no criticos). Ver $log_file" >&2
        return 4
    fi
    return 0
}

# Rotacion manual de directorios vault (mismo algoritmo que rotate_backups pero sobre dirs)
_rotate_vault_dirs() {
    local dir="$1"
    local daily="${2:-7}"
    local weekly="${3:-4}"
    local monthly="${4:-12}"

    # Promover a monthly (del weekly.0 al ultimo monthly)
    local week_day
    week_day=$(date +%u)  # 1=lunes..7=domingo
    local month_day
    month_day=$(date +%d)

    if [[ "$month_day" == "01" && -d "$dir/weekly.0" ]]; then
        for ((i=monthly-1; i>=1; i--)); do
            if [[ -d "$dir/monthly.$((i-1))" ]]; then mv "$dir/monthly.$((i-1))" "$dir/monthly.$i"; fi
        done
        if [[ -d "$dir/weekly.0" ]]; then cp -al "$dir/weekly.0" "$dir/monthly.0"; fi
    fi

    if [[ "$week_day" == "7" && -d "$dir/daily.0" ]]; then
        for ((i=weekly-1; i>=1; i--)); do
            if [[ -d "$dir/weekly.$((i-1))" ]]; then mv "$dir/weekly.$((i-1))" "$dir/weekly.$i"; fi
        done
        if [[ -d "$dir/daily.0" ]]; then cp -al "$dir/daily.0" "$dir/weekly.0"; fi
    fi

    # Rotar daily
    if [[ -d "$dir/daily.$((daily-1))" ]]; then rm -rf "$dir/daily.$((daily-1))"; fi
    for ((i=daily-1; i>=1; i--)); do
        if [[ -d "$dir/daily.$((i-1))" ]]; then mv "$dir/daily.$((i-1))" "$dir/daily.$i"; fi
    done
}

backup_all "$@"
