# Shared helpers for the image builder. Source, do not execute.
# Sourcing must have no side effects beyond defining functions.

_log()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] $*"; }
_warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] WARNING: $*" >&2; }
_err()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] ERROR: $*" >&2; exit 1; }

# mirror_path MIRROR RELPATH
# Join a MIRROR (file:///... or http(s)://...) with a relative path.
mirror_path() {
    local mirror="$1" rel="$2"
    printf '%s/%s' "${mirror%/}" "${rel#/}"
}

# is_local_mirror MIRROR -> 0 if file:// or bare absolute path, else 1
is_local_mirror() {
    case "$1" in
        file://*) return 0 ;;
        http://*|https://*) return 1 ;;
        /*) return 0 ;;
        *) return 1 ;;
    esac
}

# strip_scheme URL -> filesystem path for a file:// or bare-local URL
strip_scheme() {
    local u="$1"
    case "$u" in
        file://*) printf '%s' "${u#file://}" ;;
        *) printf '%s' "$u" ;;
    esac
}

# fetch SRC DEST
# Copy SRC (a full mirror URL) to DEST. Local mirror -> cp, http -> curl.
# Returns non-zero on failure; caller decides whether that is fatal.
fetch() {
    local src="$1" dest="$2"
    if is_local_mirror "$src"; then
        local path; path="$(strip_scheme "$src")"
        [[ -f "$path" ]] || return 1
        cp "$path" "$dest"
    else
        curl -sfL --connect-timeout 60 "$src" -o "$dest"
    fi
}

# txz_hash DIR
# Stable hash of the set of .txz files in DIR (names + contents), order
# independent. Empty/absent dir -> empty string.
txz_hash() {
    local dir="$1"
    [[ -d "$dir" ]] || { printf ''; return 0; }
    local files; files=$(find "$dir" -maxdepth 1 -name '*.txz' -type f | sort)
    [[ -n "$files" ]] || { printf ''; return 0; }
    # Hash sorted "name  sha256" lines so reordering does not change output.
    while IFS= read -r f; do
        printf '%s  %s\n' "$(basename "$f")" "$(sha256sum "$f" | cut -d' ' -f1)"
    done <<< "$files" | sha256sum | cut -d' ' -f1
}

# require_mount VERSION
# Assert the NAS tree for VERSION is mounted (file:// mirror only).
# x86_64 tree dir is slackware64-${VERSION}.
require_mount() {
    local version="$1"
    is_local_mirror "$MIRROR" || return 0   # http mirror: nothing to check
    local base; base="$(strip_scheme "$MIRROR")"
    local dir="${base}/slackware64-${version}"
    [[ -d "$dir" ]] || _err "NAS tree not mounted: ${dir}"
}
