#!/bin/bash
# ==============================================================================================
# ================================= Arr Cache Prefill ===========================================
# ==============================================================================================
#
# PURPOSE
# ─────────────────────────────────────────────────────────────────────────────
# Populates the shared tracked-data cache (see arr_get_tracked_data() in common.sh) for
# Lidarr, Sonarr, and Radarr. Without this, each arr's cache stays cold until whichever
# script happens to touch that arr first writes through — which could be hours, depending
# on the daily schedule. Originally Lidarr-only (lidarr_cache_prefill.sh, 2026-07-16),
# generalized the same day to cover all three arrs once the cache mechanism itself was
# generalized.
#
# Runs on two schedules (2026-07-17): once at array start (closes the cold-boot gap, 10min
# wait ceiling for slow-starting containers) and again every 30min via
# CRITICAL_MAINTENANCE_SCRIPTS with a 1min wait ceiling (ARR_PREFILL_WAIT_MINUTES=1 override)
# — a live fetch+write takes seconds, so there's no reason to tolerate the boot-time wait on
# a recurring job. This is what keeps the cache-first consumers' data reliably under 30min
# old instead of only refreshing whenever some other script happens to write through.
#
# ==============================================================================================
# OPERATIONAL MODEL
# ==============================================================================================
#
# Each arr's container may still be starting when this fires (array just started) — retries
# reaching that arr's API for up to ARR_PREFILL_WAIT_MINUTES before giving up on it and moving
# to the next. Not fatal if one never comes up in time; that arr's cache just stays cold until
# the next script writes through naturally, exactly as it would without this script existing.
# An arr not configured on this host (e.g. Lidarr is HOST1-only) is skipped cleanly.
#
# ==============================================================================================
# DESIGN PRINCIPLES
# ==============================================================================================
#
# Warm the Cache, Never Own It
#   This script only pre-populates what arr_get_tracked_data() would fetch on demand
#   anyway. Nothing depends on it having run — every consumer still writes through on a
#   cold cache. It removes latency and staleness, it is not a dependency.
#
# Failure Is a No-Op, Not an Error
#   An arr that never comes up in time simply leaves its cache cold, exactly as if this
#   script did not exist. That is why a missed prefill is logged rather than notified —
#   the fallback path is the normal path.
#
# Wait Ceiling Matched to the Trigger
#   The array-start run tolerates a long wait because containers are genuinely still
#   starting. The 30-minute recurring run does not, because a live fetch takes seconds
#   and a long wait there would only serve to overlap the next tick.
#
# Per-Arr Independence
#   Each arr is prefilled on its own. One unconfigured or slow-starting arr never
#   prevents the other two from being warmed.
#
# ==============================================================================================
# OPERATIONAL SAFEGUARDS
# ==============================================================================================
#
#   Root required       — chown-free here, but matches convention across Arrs_Stack/
#   jq required         — skips the whole run cleanly (not fatal) if jq is missing
#   acquire_lock        — prevents two invocations of this script overlapping (default strict
#                         mode) — matters if the boot-time run is still waiting on a slow
#                         container when the first 30min critical-tier tick fires
#   Reachability retry  — tolerates a slow-starting container up to ARR_PREFILL_WAIT_MINUTES;
#                         never fatal if one never comes up, that arr's cache just stays cold
#   Active-rescan check — skips an arr this cycle if a rescan-type command is running, instead
#                         of a live fetch arr_cache_write() would refuse to persist anyway
#                         (2026-07-17) — avoids wasted API calls during a long rescan
#   Per-arr isolation   — one arr failing or timing out never blocks or fails the others
#
# ==============================================================================================
# CONFIGURATION
# ==============================================================================================
#
# host*.conf
#   HOST1_LIDARR_URL / HOST1_LIDARR_API_KEY
#   HOST*_SONARR_URL / HOST*_SONARR_API_KEY
#   HOST*_RADARR_URL / HOST*_RADARR_API_KEY
#   All aliased by detect_hosts()
#
# master.conf
#   ARR_PREFILL_WAIT_MINUTES — how long to retry reaching each arr before giving up on it
#   (default 10). The CRITICAL_MAINTENANCE_SCRIPTS entry overrides this to 1 via parse_args'
#   VAR=VAL mechanism for the 30min recurring run — the 10min default is sized for cold boot,
#   not a job that fires every half hour.
#
# ==============================================================================================
# RUNTIME MODES
# ==============================================================================================
#
# arr_cache_prefill.sh
#     Normal run — populates all three arr caches, or skips cleanly per-arr as described
#     under OPERATIONAL SAFEGUARDS above. No --dry-run/--status mode: this script only ever
#     reads and writes cache, there's no destructive action to preview and no separate state
#     worth inspecting beyond the cache files themselves (see Tools/arr_rescan_monitor.sh
#     --status for cache age/active-rescan inspection).
#
# arr_cache_prefill.sh --log
#     Verbose — per-arr detail as each one is checked/fetched/skipped.
#
# arr_cache_prefill.sh ARR_PREFILL_WAIT_MINUTES=1
#     Override the reachability-retry ceiling for this run only (parse_args VAR=VAL
#     mechanism) — this is how CRITICAL_MAINTENANCE_SCRIPTS invokes it every 30min.
#
# ==============================================================================================

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

source "$SCRIPT_DIR/../load_config.sh"

parse_args "$@"

if [[ "$EUID" -ne 0 ]]; then
    error "Must be run as root"
    exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
    warn "jq not found — skipping arr cache prefill"
    exit 0
fi

acquire_lock

detect_hosts

WAIT_MINUTES="${ARR_PREFILL_WAIT_MINUTES:-10}"

# Args: arr_type, url, api_key, api_version
_prefill_one() {
    local arr_type="$1" url="$2" api_key="$3" api_version="$4"

    if [[ -z "$url" ]] || [[ -z "$api_key" ]]; then
        info "${arr_type^} not configured on $MY_ID ($LOCAL_SERVER_NAME) — nothing to prefill"
        return 0
    fi

    local waited=0
    until check_api "$url" "${arr_type^}" 5 >/dev/null 2>&1; do
        if [[ "$waited" -ge $(( WAIT_MINUTES * 60 )) ]]; then
            warn "${arr_type^} not reachable after ${WAIT_MINUTES}m — leaving cache cold, next script will write through"
            return 0
        fi
        sleep 15
        (( waited += 15 ))
    done

    # Skip cleanly if a rescan-type command is already active — arr_cache_write() below
    # would refuse to persist a mid-rescan snapshot anyway (2026-07-17 guard), so fetching
    # it live first would just be a wasted API call every time this fires during a long
    # rescan. Matches the same check arr_full_rescan.sh and the cleanup scripts already do.
    local active_cmd
    active_cmd=$(arr_active_rescan_command "$arr_type" "$url" "$api_key" "$api_version")
    if [[ -n "$active_cmd" ]]; then
        info "${arr_type^} mid-rescan ($active_cmd) — skipping this cycle, cache stays as-is"
        return 0
    fi

    local endpoint="${ARR_LIBRARY_ENDPOINT[$arr_type]:-}"
    if [[ -z "$endpoint" ]]; then
        warn "No library endpoint known for ${arr_type} — skipping"
        return 0
    fi

    local items
    items=$(arr_api "$url" "$api_key" "$api_version" "$endpoint" "${arr_type^}") || {
        warn "Could not fetch ${arr_type} library for cache prefill — leaving cache cold"
        return 0
    }

    if arr_cache_write "$arr_type" "$items"; then
        log "$ICON_DONE ${arr_type^} cache prefilled ($(echo "$items" | jq 'length') items)"
    else
        warn "Failed to write ${arr_type} cache prefill"
    fi
}

_prefill_one "lidarr" "${LIDARR_URL:-}" "${LIDARR_API_KEY:-}" "v1"
_prefill_one "sonarr" "${SONARR_URL:-}" "${SONARR_API_KEY:-}" "v3"
_prefill_one "radarr" "${RADARR_URL:-}" "${RADARR_API_KEY:-}" "v3"

exit 0
