#!/usr/bin/env bash
#
# Generates /srv/status.json from /srv/mirrors.json.
#
# Usage:
#   update-mirror-status.sh quick   -> refresh sync freshness only (cheap, run often)
#   update-mirror-status.sh full    -> also recompute disk usage with du (slow, run rarely)

set -euo pipefail

MODE="${1:-quick}"
MIRRORS_JSON="/srv/mirrors.json"
STATUS_JSON="/srv/status.json"
DEBIAN_CD_TRACE="/scripts/debian-cd/trace_version"
TMP_JSON="$(mktemp)"
NOW="$(date +%s)"

trap 'rm -f "$TMP_JSON"' EXIT

if [[ ! -f "$MIRRORS_JSON" ]]; then
    echo "error: $MIRRORS_JSON not found" >&2
    exit 1
fi

# Load previous status (if any) so 'quick' mode can carry over the last known size.
PREV_JSON="{}"
if [[ -f "$STATUS_JSON" ]]; then
    PREV_JSON="$(cat "$STATUS_JSON")"
fi

MIRROR_ENTRIES="{}"

while IFS= read -r mirror; do
    id="$(jq -r '.id' <<<"$mirror")"
    path="$(jq -r '.path' <<<"$mirror")"
    rsync_url="$(jq -r '.rsync // ""' <<<"$mirror")"
    stale_after_minutes="$(jq -r '.sync_interval_minutes // 60' <<<"$mirror")"

    # Host name from the rsync URL (rsync://deb.syxpi.fr/debian -> deb.syxpi.fr)
    host="${rsync_url#rsync://}"
    host="${host%%/*}"

    lastsync=""
    lastupdate=""
    status="unknown"
    TRACE_DIR="$path/project/trace"

    # 1. Upstream-style trace files (ftpsync): local host trace = last sync,
    #    ftp-master trace = last upstream update.
    if [[ -d "$TRACE_DIR" ]]; then
        TRACE_FILE=""
        if [[ -n "$host" && -f "$TRACE_DIR/$host" ]]; then
            TRACE_FILE="$TRACE_DIR/$host"
        else
            TRACE_FILE="$(find "$TRACE_DIR" -type f ! -name "*_local*" -printf '%T@ %p
' 2>/dev/null | sort -rn | head -n1 | cut -d' ' -f2- || true)"
        fi
        if [[ -n "$TRACE_FILE" && -f "$TRACE_FILE" ]]; then
            RAW_DATE="$(head -n1 "$TRACE_FILE" || true)"
            lastsync="$(date -d "$RAW_DATE" +%s 2>/dev/null || true)"
        fi
        if [[ -f "$TRACE_DIR/ftp-master.debian.org" ]]; then
            RAW_DATE="$(head -n1 "$TRACE_DIR/ftp-master.debian.org" || true)"
            lastupdate="$(date -d "$RAW_DATE" +%s 2>/dev/null || true)"
      fi
    fi

    # 2. Plain file markers (Arch layout: lastsync / lastupdate)
    if [[ -z "$lastsync" && -f "$path/lastsync" ]]; then
        lastsync="$(grep -oE '[0-9]+' "$path/lastsync" | head -n1 || true)"
    fi
    if [[ -z "$lastupdate" && -f "$path/lastupdate" ]]; then
        lastupdate="$(grep -oE '[0-9]+' "$path/lastupdate" | head -n1 || true)"
    fi

    # 3. Debian CD: mtime of the local trace_version file
    if [[ -z "$lastsync" && "$id" == "debian-cd" && -f "$DEBIAN_CD_TRACE" ]]; then
        lastsync="$(stat -c %Y "$DEBIAN_CD_TRACE" 2>/dev/null || true)"
    fi

    # Freshness status
    if [[ -n "$lastsync" ]]; then
        age=$(( NOW - lastsync ))
        threshold=$(( stale_after_minutes * 60 * 3 ))
        warn_threshold=$(( stale_after_minutes * 60 * 3 / 2 ))
        if   (( age <= warn_threshold )); then status="ok"
        elif (( age <= threshold ));      then status="warn"
        else                                   status="stale"
        fi
    elif compgen -G "$path/Archive-Update-in-Progress-*" > /dev/null; then
        # First sync still running, nothing to measure yet
        status="syncing"
    fi

    # Disk usage
    if [[ "$MODE" == "full" ]]; then
        size_bytes="$(du -sb "$path" 2>/dev/null | cut -f1 || true)"
    else
        size_bytes="$(jq -r --arg id "$id" '.mirrors[$id].size_bytes // 0' <<<"$PREV_JSON")"
    fi
    size_bytes="${size_bytes:-0}"
    size_human="$(numfmt --to=iec-i --suffix=B --format="%.1f" "$size_bytes" 2>/dev/null || echo "0.0B")"

    entry="$(jq -n --arg id "$id" --argjson size_bytes "$size_bytes" --arg size_human "$size_human" --argjson lastsync "${lastsync:-null}" --argjson lastupdate "${lastupdate:-null}" --arg status "$status" '{($id): {size_bytes: $size_bytes, size_human: $size_human, lastsync: $lastsync, lastupdate: $lastupdate, status: $status}}')"

    MIRROR_ENTRIES="$(jq --argjson e "$entry" '. * $e' <<<"$MIRROR_ENTRIES")"
done < <(jq -c 'if type == "array" then .[] else .mirrors[] end' "$MIRRORS_JSON")

jq -n --argjson mirrors "$MIRROR_ENTRIES" --argjson generated_at "$NOW" '{generated_at: $generated_at, mirrors: $mirrors}' > "$TMP_JSON"

mv "$TMP_JSON" "$STATUS_JSON"
chmod 644 "$STATUS_JSON"

