#!/usr/bin/env bash
# vault_audit — Full audit pipeline for one or all declared vaults.
# Runs: layout-ensure → index → profile → dedupe → aggregate → doctor
#
# Usage:
#   vault_audit.sh <vault_name>
#   vault_audit.sh --all
#   vault_audit.sh <vault_name> --skip-profilers
#   vault_audit.sh <vault_name> --dry-run-layout
#   vault_audit.sh --all --skip-profilers
set -euo pipefail

# --- locate FN_REGISTRY_ROOT ---
_find_registry_root() {
    local dir
    dir="$(pwd)"
    while [[ "$dir" != "/" ]]; do
        if [[ -f "$dir/registry.db" ]]; then
            echo "$dir"
            return 0
        fi
        dir="$(dirname "$dir")"
    done
    return 1
}

if [[ -n "${FN_REGISTRY_ROOT:-}" && -f "${FN_REGISTRY_ROOT}/registry.db" ]]; then
    REGISTRY_ROOT="$FN_REGISTRY_ROOT"
elif REGISTRY_ROOT="$(_find_registry_root 2>/dev/null)"; then
    : # found
else
    echo "ERROR: Cannot locate registry.db. Set FN_REGISTRY_ROOT or run from registry root." >&2
    exit 1
fi

FN_BIN="${FN_BIN:-${REGISTRY_ROOT}/fn}"
if [[ ! -x "$FN_BIN" ]]; then
    echo "ERROR: fn binary not found at $FN_BIN. Build with: CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/" >&2
    exit 1
fi

# --- parse args ---
AUDIT_ALL=0
SKIP_PROFILERS=0
DRY_RUN_LAYOUT=0
VAULT_NAMES=()
START_TS=$(date +%s)

while [[ $# -gt 0 ]]; do
    case "$1" in
        --all)           AUDIT_ALL=1 ;;
        --skip-profilers) SKIP_PROFILERS=1 ;;
        --dry-run-layout) DRY_RUN_LAYOUT=1 ;;
        -*)
            echo "ERROR: Unknown flag: $1" >&2
            echo "Usage: vault_audit.sh <name> | --all [--skip-profilers] [--dry-run-layout]" >&2
            exit 1
            ;;
        *)
            VAULT_NAMES+=("$1")
            ;;
    esac
    shift
done

if [[ $AUDIT_ALL -eq 0 && ${#VAULT_NAMES[@]} -eq 0 ]]; then
    echo "Usage: vault_audit.sh <vault_name> | --all [--skip-profilers] [--dry-run-layout]" >&2
    exit 1
fi

# --- resolve vault list ---
if [[ $AUDIT_ALL -eq 1 ]]; then
    mapfile -t VAULT_NAMES < <(
        sqlite3 "${REGISTRY_ROOT}/registry.db" "SELECT name FROM vaults ORDER BY name;" 2>/dev/null || true
    )
    if [[ ${#VAULT_NAMES[@]} -eq 0 ]]; then
        echo "No vaults registered in registry.db. Run 'fn index' first." >&2
        exit 1
    fi
    echo "Found ${#VAULT_NAMES[@]} vault(s): ${VAULT_NAMES[*]}"
fi

# --- build fn vault flags ---
LAYOUT_FLAGS=()
if [[ $DRY_RUN_LAYOUT -eq 1 ]]; then
    LAYOUT_FLAGS+=(--dry-run)
fi

# --- per-vault audit ---
PASS_COUNT=0
FAIL_COUNT=0
declare -A VAULT_STATUS

audit_one() {
    local name="$1"
    local vault_ok=1
    echo ""
    echo "=== vault: $name ==="

    # Step 1: layout-ensure
    echo "  [1/5] layout-ensure"
    if ! "$FN_BIN" vault layout-ensure "$name" "${LAYOUT_FLAGS[@]}" 2>&1 | sed 's/^/    /'; then
        echo "    WARN: layout-ensure failed (non-fatal)" >&2
        vault_ok=0
    fi

    # Step 2: index
    echo "  [2/5] index"
    if ! "$FN_BIN" vault index "$name" 2>&1 | sed 's/^/    /'; then
        echo "    ERROR: index failed" >&2
        vault_ok=0
    fi

    # Step 3: profile
    if [[ $SKIP_PROFILERS -eq 0 ]]; then
        echo "  [3/5] profile"
        if ! "$FN_BIN" vault profile "$name" 2>&1 | sed 's/^/    /'; then
            echo "    WARN: profile had errors (non-fatal)" >&2
        fi
    else
        echo "  [3/5] profile (skipped)"
    fi

    # Step 4: dedupe (informational, non-fatal)
    echo "  [4/5] dedupe"
    "$FN_BIN" vault dedupe "$name" 2>&1 | sed 's/^/    /' || true

    # Step 5 deferred — aggregate runs once at the end
    echo "  [5/5] aggregate (deferred)"

    if [[ $vault_ok -eq 1 ]]; then
        VAULT_STATUS["$name"]="ok"
        PASS_COUNT=$((PASS_COUNT + 1))
    else
        VAULT_STATUS["$name"]="warn"
        FAIL_COUNT=$((FAIL_COUNT + 1))
    fi
}

for vault_name in "${VAULT_NAMES[@]}"; do
    audit_one "$vault_name"
done

# --- aggregate (once, after all vaults) ---
echo ""
echo "=== aggregate ==="
"$FN_BIN" vault aggregate 2>&1 | sed 's/^/  /'

# --- doctor (read-only health check) ---
echo ""
echo "=== doctor ==="
"$FN_BIN" vault doctor 2>&1 | sed 's/^/  /' || true

# --- summary table ---
END_TS=$(date +%s)
ELAPSED=$(( END_TS - START_TS ))

echo ""
echo "=== summary ==="
printf "%-30s  %s\n" "VAULT" "STATUS"
printf "%-30s  %s\n" "-----" "------"
for vault_name in "${VAULT_NAMES[@]}"; do
    status="${VAULT_STATUS[$vault_name]:-unknown}"
    printf "%-30s  %s\n" "$vault_name" "$status"
done
echo ""
echo "Done: ${PASS_COUNT} ok, ${FAIL_COUNT} warn  (${ELAPSED}s)"

if [[ $FAIL_COUNT -gt 0 ]]; then
    exit 4
fi
exit 0
