#!/bin/bash

# Per-location engine dispatcher. Resolves the engine for a given location
# (CFG_BACKUP_LOC_N_ENGINE → CFG_BACKUP_ENGINE → 'restic'), then forwards to
# the engine adapter's `<engine><FunctionName>` implementation. Adapters live
# in scripts/backup/engine/<engine>_*.sh; today restic_*.sh is the only one.

engineForLocation()
{
    local idx="$1"
    local var="CFG_BACKUP_LOC_${idx}_ENGINE"
    local e="${!var}"
    [[ -z "$e" ]] && e="${CFG_BACKUP_ENGINE:-restic}"
    echo "$e"
}

engineKnownIds()
{
    # List adapter implementations discovered by looking for the canonical
    # `<engine>BackupAppToLocation` function name registered at source time.
    compgen -A function 2>/dev/null | grep -oE '^[a-z]+BackupAppToLocation$' | sed 's/BackupAppToLocation//' | sort -u
}

engineDispatch()
{
    # Internal helper: call $1=<engine><FunctionName> with the remaining args.
    # Falls back with a clear error if the adapter doesn't implement it.
    local fn="$1"
    shift
    if ! declare -f "$fn" >/dev/null 2>&1; then
        isError "Backup engine has no '$fn' implementation"
        return 1
    fi
    "$fn" "$@"
}

# ---- Idx-scoped dispatchers ----------------------------------------------------

# Local/removable-drive safety guard runs before init, readiness, and any backup
# write (see backupLocationLocalGuard) — refuses to write when a REQUIRE_MOUNT
# drive isn't mounted, so restic never fills the system disk.
engineInitLocation()         { local i="$1"; backupLocationLocalGuard "$i" || return 1; engineDispatch "$(engineForLocation "$i")InitLocation" "$i"; }
engineEnsureLocationReady()  { local i="$1"; backupLocationLocalGuard "$i" || return 1; engineDispatch "$(engineForLocation "$i")EnsureLocationReady" "$i"; }
enginePasswordEnsure()       { local i="$1"; engineDispatch "$(engineForLocation "$i")PasswordEnsure" "$i"; }
engineLocationUri()          { local i="$1"; engineDispatch "$(engineForLocation "$i")LocationUri" "$i"; }
engineLocationStats()        { local i="$1"; engineDispatch "$(engineForLocation "$i")LocationStats" "$i"; }
engineEnvExport()            { local i="$1"; engineDispatch "$(engineForLocation "$i")EnvExport" "$i"; }
engineEnvUnset()             { local i="$1"; engineDispatch "$(engineForLocation "${i:-1}")EnvUnset"; }

engineBackupApp()            { local i="$1"; shift; backupLocationLocalGuard "$i" || return 1; engineDispatch "$(engineForLocation "$i")BackupAppToLocation" "$i" "$@"; }
engineBackupSystem()         { local i="$1"; shift; backupLocationLocalGuard "$i" || return 1; engineDispatch "$(engineForLocation "$i")BackupSystemToLocation" "$i" "$@"; }
engineRestoreSystemLatest()  { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")RestoreSystemLatest" "$i" "$@"; }
engineRestoreSnapshot()      { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")RestoreSnapshot" "$i" "$@"; }
engineSnapshotLatestId()     { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")SnapshotLatestId" "$i" "$@"; }
engineSnapshotsJson()        { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")SnapshotsJson" "$i" "$@"; }
engineSystemSnapshotsJson()  { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")SystemSnapshotsJson" "$i" "$@"; }
engineSnapshotListFiles()    { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")SnapshotListFiles" "$i" "$@"; }
engineForgetApp()            { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")ForgetApp" "$i" "$@"; }
engineForgetSystem()         { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")ForgetSystem" "$i" "$@"; }
engineCheckLocation()        { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")CheckLocation" "$i" "$@"; }
engineDumpFile()             { local i="$1"; shift; engineDispatch "$(engineForLocation "$i")DumpFile" "$i" "$@"; }

# ---- Aggregate helpers (iterate enabled locations) ---------------------------

engineInstallAll()
{
    if ! declare -f resticEnabledLocations >/dev/null 2>&1; then
        isError "engineInstallAll: location helpers not loaded yet"
        return 1
    fi
    declare -A seen
    local idx engine fn
    while IFS= read -r idx; do
        [[ -z "$idx" ]] && continue
        engine=$(engineForLocation "$idx")
        [[ -n "${seen[$engine]}" ]] && continue
        seen[$engine]=1
        fn="${engine}Install"
        if declare -f "$fn" >/dev/null 2>&1; then
            "$fn"
        fi
    done < <(resticEnabledLocations)
}

engineInitAllLocations()
{
    isHeader "Backup Location Initialization"
    local idx
    while IFS= read -r idx; do
        [[ -z "$idx" ]] && continue
        engineInitLocation "$idx"
    done < <(resticEnabledLocations)
}

engineEnsureAllLocationsReady()
{
    engineInstallAll
    local idx
    while IFS= read -r idx; do
        [[ -z "$idx" ]] && continue
        engineEnsureLocationReady "$idx"
    done < <(resticEnabledLocations)
}

engineForgetAppAllLocations()
{
    local app="$1"
    local idx
    while IFS= read -r idx; do
        [[ -z "$idx" ]] && continue
        engineForgetApp "$idx" "$app"
    done < <(resticEnabledLocations)
}

engineCheckAllLocations()
{
    local pct="$1"
    local idx
    local failed=0
    while IFS= read -r idx; do
        [[ -z "$idx" ]] && continue
        engineCheckLocation "$idx" "$pct" || failed=$((failed + 1))
    done < <(resticEnabledLocations)
    return $failed
}
