#!/bin/bash
# Cedapug custom-maps overlay.
# Scrapes the JS map list at https://cedapug.com/custom and keeps
# $OVERLAY/left4dead2/addons/ in sync. Re-downloads only when the zip's
# Last-Modified header changed.
set -euo pipefail

CEDAPUG_HOST="https://cedapug.com"
LIST_URL="$CEDAPUG_HOST/custom"
ADDONS_DIR="$OVERLAY/left4dead2/addons"
STATE_DIR="$OVERLAY/.cedapug"
WORK_DIR="$STATE_DIR/work"
MANIFEST="$STATE_DIR/manifest.tsv"   # zip_basename \t last_modified \t vpk1,vpk2,...

mkdir -p "$ADDONS_DIR" "$STATE_DIR" "$WORK_DIR"

# --- 1. Discover the current zip list -----------------------------------
# The page embeds the map list inside renderCustomMapDownloads([...]) with
# JSON-escaped slashes (\/maps\/foo.zip). Unescape with sed before grepping.
echo ":: fetching $LIST_URL"
mapfile -t ZIP_PATHS < <(
    curl -fsSL --retry 3 --retry-delay 2 "$LIST_URL" \
        | sed 's@\\/@/@g' \
        | grep -oE '"/maps/[A-Za-z0-9_.+-]+\.zip"' \
        | tr -d '"' \
        | sort -u
)
if [[ ${#ZIP_PATHS[@]} -eq 0 ]]; then
    echo "!! no map zips found on $LIST_URL — page format may have changed" >&2
    exit 1
fi
echo ":: ${#ZIP_PATHS[@]} custom map zip(s) listed"

# --- 2. Load previous manifest ------------------------------------------
declare -A PREV_LM PREV_VPKS
if [[ -f "$MANIFEST" ]]; then
    while IFS=$'\t' read -r zname lm vpks; do
        [[ -n "$zname" ]] || continue
        PREV_LM[$zname]=$lm
        PREV_VPKS[$zname]=$vpks
    done < "$MANIFEST"
fi

# --- 3. Download / extract each desired zip -----------------------------
declare -A NEW_LM NEW_VPKS
for zpath in "${ZIP_PATHS[@]}"; do
    zname="${zpath##*/}"
    url="$CEDAPUG_HOST$zpath"

    lm="$(curl -fsSI --retry 3 --retry-delay 2 "$url" \
        | awk 'BEGIN{IGNORECASE=1} /^last-modified:/ {sub(/^[^:]*:[[:space:]]*/, ""); gsub(/\r/, ""); print; exit}')"
    NEW_LM[$zname]=$lm

    prev_lm="${PREV_LM[$zname]:-}"
    prev_vpks="${PREV_VPKS[$zname]:-}"

    # Skip if Last-Modified matches AND every recorded vpk is still on disk.
    if [[ -n "$lm" && "$lm" == "$prev_lm" && -n "$prev_vpks" ]]; then
        all_present=1
        IFS=',' read -r -a v_arr <<<"$prev_vpks"
        for v in "${v_arr[@]}"; do
            [[ -f "$ADDONS_DIR/$v" ]] || { all_present=0; break; }
        done
        if (( all_present )); then
            echo ":: $zname unchanged (Last-Modified: $lm) — skipped"
            NEW_VPKS[$zname]=$prev_vpks
            continue
        fi
    fi

    echo ":: downloading $zname"
    zfile="$WORK_DIR/$zname"
    curl -fSL --retry 3 --retry-delay 2 -o "$zfile" "$url"

    7z x -y -bd -o"$ADDONS_DIR" "$zfile" '*.vpk' >/dev/null

    vpk_list="$(7z l -slt -ba "$zfile" \
        | awk '/^Path = .*\.vpk$/ {sub(/^Path = /, ""); print}' \
        | paste -sd, -)"
    if [[ -z "$vpk_list" ]]; then
        echo "!! warning: $zname contained no .vpk — leaving manifest entry empty" >&2
    fi
    NEW_VPKS[$zname]=$vpk_list

    rm -f "$zfile"
done

# --- 4. Prune vpks from zips that disappeared from the listing ----------
for old_zname in "${!PREV_VPKS[@]}"; do
    if [[ -z "${NEW_LM[$old_zname]:-}" ]]; then
        IFS=',' read -r -a old_v_arr <<<"${PREV_VPKS[$old_zname]}"
        for v in "${old_v_arr[@]}"; do
            if [[ -n "$v" && -f "$ADDONS_DIR/$v" ]]; then
                echo ":: pruning $v (zip $old_zname no longer listed)"
                rm -f "$ADDONS_DIR/$v"
            fi
        done
    fi
done

# --- 5. Rewrite manifest -------------------------------------------------
tmp_manifest="$(mktemp -p "$STATE_DIR")"
for zname in "${!NEW_LM[@]}"; do
    printf '%s\t%s\t%s\n' "$zname" "${NEW_LM[$zname]}" "${NEW_VPKS[$zname]:-}" >>"$tmp_manifest"
done
mv -f "$tmp_manifest" "$MANIFEST"

rm -rf "$WORK_DIR"
echo ":: done — ${#NEW_LM[@]} zip(s) tracked, addons/ in sync"
