#!/bin/bash

# ======================================================================
# Archivo:       actualizar-wardrobe
# Propósito:     Actualizar, dentro de un .deb de quirinux-update, la lista
#                de paquetes del wardrobe leyéndola de GitHub.
# Uso:           actualizar-wardrobe quirinux-update_1_0_11_q1_all.deb
# Distribución:  Quirinux 2.x (script de mantenimiento, solo para el autor)
# ======================================================================
#
# Qué hace:
#   1. Descarga la rama pr/quirinux-updates de penguins-wardrobe
#      (o usa un checkout local con --wardrobe).
#   2. Genera la lista de paquetes del costume "quirinux" y el preseed.
#   3. Si no hay cambios respecto a la lista del .deb, no hace nada.
#   4. Si los hay: sustituye ambos ficheros dentro del .deb, sube la versión
#      (1.0.11+q2 -> 1.0.12+q2; el sufijo +q2 es fijo), recalcula md5sums y Installed-Size y escribe
#      el .deb nuevo junto al original (el original no se toca).
# ----------------------------------------------------------------------

set -euo pipefail
export LC_ALL=C

REPO_URL="https://github.com/charliemartinez/penguins-wardrobe.git"
BRANCH="pr/quirinux-updates"
WARDROBE=""
FORCE=0
BUMP=1
OUTDIR=""
DEB=""

# Paquetes que el costume instala en "finalize" y no están en ningún accesorio
# (mantener alineado con index.yaml -> finalize.cmds)
EXTRA_PACKAGES="quirinux-firmware quirinux-youdown quirinux-youtubedown mintinstall mint-common"

# Ruta de los ficheros dentro del .deb
REL_SHARE="opt/quirinux-update/tmp/usr/local/share/quirinux-update"
REL_SYNC="opt/quirinux-update/tmp/usr/local/bin/quirinux-sync"

usage() {
    cat <<'EOF'
Uso: actualizar-wardrobe [opciones] paquete.deb

  --branch RAMA     rama de GitHub (por defecto: pr/quirinux-updates)
  --repo URL        repositorio (por defecto: github.com/charliemartinez/penguins-wardrobe)
  --wardrobe DIR    usar un checkout local en lugar de descargar
  -o, --out DIR     directorio de salida (por defecto: el del .deb)
  --no-bump         no cambiar la versión (genera el mismo nombre en -o)
  --force           reconstruir aunque la lista no haya cambiado
  -h, --help        esta ayuda
EOF
}

die() { echo "ERROR: $*" >&2; exit 1; }

while [ $# -gt 0 ]; do
    case "$1" in
        --branch)    BRANCH="${2:?falta la rama}"; shift ;;
        --repo)      REPO_URL="${2:?falta la URL}"; shift ;;
        --wardrobe)  WARDROBE="${2:?falta el directorio}"; shift ;;
        -o|--out)    OUTDIR="${2:?falta el directorio}"; shift ;;
        --no-bump)   BUMP=0 ;;
        --force)     FORCE=1 ;;
        -h|--help)   usage; exit 0 ;;
        -*)          usage >&2; die "opción desconocida: $1" ;;
        *)           [ -z "$DEB" ] || die "solo se admite un .deb"; DEB="$1" ;;
    esac
    shift
done

[ -n "$DEB" ] || { usage >&2; exit 2; }
[ -f "$DEB" ] || die "no existe $DEB"
for c in dpkg-deb md5sum awk sed sort; do command -v "$c" >/dev/null || die "falta el comando: $c"; done
[ -n "$WARDROBE" ] || command -v git >/dev/null || die "falta git"

DEB=$(readlink -f "$DEB")
[ -n "$OUTDIR" ] || OUTDIR=$(dirname "$DEB")
mkdir -p "$OUTDIR"

TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT

# ----------------------------------------------------------------------
# 1. Obtener el wardrobe
# ----------------------------------------------------------------------
if [ -z "$WARDROBE" ]; then
    echo "Descargando $REPO_URL (rama $BRANCH)..."
    git clone --quiet --depth 1 -b "$BRANCH" "$REPO_URL" "$TMP/wardrobe" \
        || die "no se pudo descargar la rama $BRANCH"
    WARDROBE="$TMP/wardrobe"
else
    [ -d "$WARDROBE" ] || die "no existe el directorio $WARDROBE"
fi

COSTUME_DIR="$WARDROBE/v2/costumes/quirinux"
INDEX="$COSTUME_DIR/index.yaml"
[ -f "$INDEX" ] || die "no se encuentra $INDEX"

COMMIT=$(git -C "$WARDROBE" rev-parse --short HEAD 2>/dev/null || echo "desconocido")
RELEASE=$(sed -n 's/^release:[[:space:]]*//p' "$INDEX" | head -n1)

# ----------------------------------------------------------------------
# 2. Generar lista y preseed
# ----------------------------------------------------------------------
mapfile -t ACCESSORIES < <(sed -n 's#^[[:space:]]*-[[:space:]]*\./accessories/\([^[:space:]#]*\).*#\1#p' "$INDEX")
[ "${#ACCESSORIES[@]}" -gt 0 ] || die "index.yaml no lista accesorios"

RAW="$TMP/raw"; : > "$RAW"
for acc in "${ACCESSORIES[@]}"; do
    f="$COSTUME_DIR/accessories/$acc/packages.yaml"
    if [ ! -f "$f" ]; then echo "AVISO: $acc no tiene packages.yaml" >&2; continue; fi
    awk '/^[[:space:]]*-[[:space:]]+/ {
            sub(/^[[:space:]]*-[[:space:]]+/, "")
            sub(/[[:space:]]*#.*/, "")
            gsub(/["\047\r]/, "")
            if (length($0)) print $1
         }' "$f" >> "$RAW"
done
for p in $EXTRA_PACKAGES; do echo "$p" >> "$RAW"; done

BAD=$(grep -vE '^[a-z0-9][a-z0-9+.-]+$' "$RAW" || true)
[ -n "$BAD" ] && { echo "AVISO: se descartan nombres no válidos:" >&2; echo "$BAD" >&2; }

NEW_LIST="$TMP/new.list"
{
    echo "# Lista de paquetes del wardrobe de Quirinux (generada, no editar a mano)"
    echo "# Origen: penguins-wardrobe ${BRANCH}@${COMMIT}, costume quirinux release ${RELEASE:-?}"
    echo "# Generada: $(date '+%Y-%m-%d %H:%M:%S')"
    grep -E '^[a-z0-9][a-z0-9+.-]+$' "$RAW" | sort -u
} > "$NEW_LIST"

# Preseed: sin debconf/*, tzdata/* ni ufw/* (cambiarían sistemas ya en uso)
NEW_PRESEED="$TMP/new.preseed"
{
    echo "# Respuestas debconf del wardrobe (filtradas, generado)"
    {
        [ -f "$COSTUME_DIR/packages.preseed" ] && cat "$COSTUME_DIR/packages.preseed"
        for acc in "${ACCESSORIES[@]}"; do
            f="$COSTUME_DIR/accessories/$acc/packages.preseed"
            [ -f "$f" ] && cat "$f"
        done
    } | tr -d '\r' \
      | grep -vE '^[[:space:]]*(#|$)' \
      | grep -vE '^(debconf|tzdata|ufw)[[:space:]]' \
      | sort -u || true
} > "$NEW_PRESEED"

NEW_COUNT=$(grep -vc '^#' "$NEW_LIST")
[ "$NEW_COUNT" -gt 100 ] || die "la lista generada solo tiene $NEW_COUNT paquetes; algo va mal, se cancela"
echo "Wardrobe ${BRANCH}@${COMMIT}: ${#ACCESSORIES[@]} accesorios, $NEW_COUNT paquetes."

# ----------------------------------------------------------------------
# 3. Abrir el .deb y comparar
# ----------------------------------------------------------------------
B="$TMP/deb"
dpkg-deb -R "$DEB" "$B" || die "no se pudo abrir $DEB"
[ -f "$B/$REL_SYNC" ] || die "este .deb no incluye quirinux-sync (¿es anterior a la 1.0.11?)"
mkdir -p "$B/$REL_SHARE"

OLD_LIST="$B/$REL_SHARE/wardrobe-packages.list"
OLD_PRESEED="$B/$REL_SHARE/wardrobe-packages.preseed"
body() { [ -f "$1" ] && grep -vE '^[[:space:]]*(#|$)' "$1" | sort -u || true; }

body "$OLD_LIST"    > "$TMP/old.body"
body "$NEW_LIST"    > "$TMP/new.body"
body "$OLD_PRESEED" > "$TMP/oldp.body"
body "$NEW_PRESEED" > "$TMP/newp.body"

ADDED=$(comm -13 "$TMP/old.body" "$TMP/new.body")
REMOVED=$(comm -23 "$TMP/old.body" "$TMP/new.body")
PRESEED_CHANGED=0; cmp -s "$TMP/oldp.body" "$TMP/newp.body" || PRESEED_CHANGED=1

if [ -z "$ADDED" ] && [ -z "$REMOVED" ] && [ "$PRESEED_CHANGED" -eq 0 ] && [ "$FORCE" -eq 0 ]; then
    echo "La lista del .deb ya coincide con GitHub: no hay nada que actualizar."
    exit 0
fi

echo
echo "Cambios respecto a la lista del .deb:"
echo "  Paquetes añadidos : $(printf '%s' "$ADDED" | grep -c . || true)"
[ -n "$ADDED" ]   && printf '%s\n' "$ADDED"   | sed 's/^/    + /'
echo "  Paquetes quitados : $(printf '%s' "$REMOVED" | grep -c . || true)"
[ -n "$REMOVED" ] && printf '%s\n' "$REMOVED" | sed 's/^/    - /'
[ "$PRESEED_CHANGED" -eq 1 ] && echo "  El preseed también cambió."
echo

# ----------------------------------------------------------------------
# 4. Sustituir ficheros, subir versión y reconstruir
# ----------------------------------------------------------------------
install -m 644 "$NEW_LIST"    "$OLD_LIST"
install -m 644 "$NEW_PRESEED" "$OLD_PRESEED"

CTL="$B/DEBIAN/control"
OLD_VER=$(sed -n 's/^Version:[[:space:]]*//p' "$CTL" | head -n1)
NEW_VER="$OLD_VER"
if [ "$BUMP" -eq 1 ]; then
    # El sufijo +qN (Quirinux N.x) es fijo: solo se sube el último número de
    # la versión base (1.0.11+q2 -> 1.0.12+q2).
    BASE="$OLD_VER"; SUFFIX=""
    if [[ "$OLD_VER" =~ ^(.*)(\+q[0-9]+)$ ]]; then BASE="${BASH_REMATCH[1]}"; SUFFIX="${BASH_REMATCH[2]}"; fi
    [[ "$BASE" =~ ^(.*[^0-9])?([0-9]+)$ ]] || die "no sé subir la versión '$OLD_VER'; usa --no-bump"
    NEW_VER="${BASH_REMATCH[1]}$(( 10#${BASH_REMATCH[2]} + 1 ))${SUFFIX}"
    sed -i "s/^Version:.*/Version: $NEW_VER/" "$CTL"
fi

SZ=$(du -sk --exclude=DEBIAN "$B" | cut -f1)
if grep -q '^Installed-Size:' "$CTL"; then
    sed -i "s/^Installed-Size:.*/Installed-Size: $SZ/" "$CTL"
else
    echo "Installed-Size: $SZ" >> "$CTL"
fi

( cd "$B" && find . -type f -not -path './DEBIAN/*' -printf '%P\n' | sort | xargs -d '\n' md5sum ) > "$B/DEBIAN/md5sums"

PKG=$(sed -n 's/^Package:[[:space:]]*//p' "$CTL" | head -n1)
ARCH=$(sed -n 's/^Architecture:[[:space:]]*//p' "$CTL" | head -n1)
OUT="$OUTDIR/${PKG}_${NEW_VER}_${ARCH}.deb"
[ "$OUT" = "$DEB" ] && OUT="${OUT%.deb}.new.deb"

dpkg-deb --root-owner-group -Zzstd -b "$B" "$OUT" >/dev/null || die "falló dpkg-deb"

echo "Versión : $OLD_VER -> $NEW_VER"
echo "Creado  : $OUT"
