#!/bin/bash
# sync_audio_bulk.sh — Sincroniza a producción, uno por uno, un lote de posts con
# audio TTS ya generado en local. Envoltorio de sync_audio_to_prod.py que añade
# "parar en el primer fallo" (el script Python no lo hace: recorre toda la
# lista y acumula errores, ver #212/#213).
#
# Motivo del wrapper en bash con mapfile: un `while read id; do ...; done <
# fichero` normal comparte el file descriptor de stdin con cualquier `ssh`
# lanzado dentro del bucle. sync_audio_to_prod.py llama a ssh internamente; si
# el bucle no está protegido, ssh se come el resto del fichero de IDs y el
# bucle termina "sin error" tras procesar solo el primero. Detectado y
# documentado en memoria (feedback-bash-while-read-ssh-stdin) el 2026-08-24
# tras un lote real que solo sincronizó 1 de 184 posts sin ningún error visible.
#
# Uso:
#   scripts/sync_audio_bulk.sh --ids 55519,55520,822
#   scripts/sync_audio_bulk.sh --file /tmp/ids.txt          # un ID por línea
#   scripts/sync_audio_bulk.sh --carta 54254                # cola completa de la carta
#   scripts/sync_audio_bulk.sh --ids 55519,55520 --dry-run  # solo plan, no toca prod
#
# Requiere las mismas variables de entorno que sync_audio_to_prod.py para
# apuntar a producción (ver ese script): FEA_PROD_SSH_HOST,
# FEA_PROD_DOCKER_CONTAINER. Ejemplo:
#   export FEA_PROD_SSH_HOST="rafa@188.40.120.157"
#   export FEA_PROD_DOCKER_CONTAINER="wordpress-r2ssjifwj0r0ghyoqd528uaa"

set -u

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SYNC_PY="$SCRIPT_DIR/sync_audio_to_prod.py"

usage() {
  echo "Uso: $0 (--ids id1,id2,... | --file ruta | --carta post_id) [--dry-run]" >&2
  exit 2
}

ids_csv=""
ids_file=""
carta=""
dry_run=""

while [ $# -gt 0 ]; do
  case "$1" in
    --ids) ids_csv="$2"; shift 2 ;;
    --file) ids_file="$2"; shift 2 ;;
    --carta) carta="$2"; shift 2 ;;
    --dry-run) dry_run="--dry-run"; shift ;;
    *) usage ;;
  esac
done

# Carga explícita de IDs en un array ANTES de cualquier llamada a ssh — es la
# parte que evita el bug de stdin. No usar `while read ... < fichero`.
ids=()
if [ -n "$ids_csv" ]; then
  IFS=',' read -r -a ids <<< "$ids_csv"
elif [ -n "$ids_file" ]; then
  mapfile -t ids < "$ids_file"
elif [ -n "$carta" ]; then
  # No usar `mapfile < <(cmd)`: la sustitución de procesos no deja comprobar
  # de forma fiable el exit code de `cmd` (mapfile ve su propio $?, no el de
  # la tubería). Si la consulta falla, un array vacío se confundiría con
  # "la carta no tiene artículos" y el lote saldría "éxito" sin sincronizar
  # nada. Se resuelve a fichero temporal y se comprueba el rc de python
  # explícitamente antes de poblar el array.
  carta_tmpfile="$(mktemp)"
  python3 - "$carta" "$SCRIPT_DIR" > "$carta_tmpfile" <<'PYEOF'
import sys
sys.path.insert(0, sys.argv[2])
from sync_audio_to_prod import carta_article_ids
for pid in carta_article_ids(int(sys.argv[1])):
    print(pid)
PYEOF
  py_rc=$?
  if [ $py_rc -ne 0 ]; then
    echo "ERROR: fallo consultando la cola de la carta $carta (exit $py_rc), no se sincroniza nada." >&2
    rm -f "$carta_tmpfile"
    exit 1
  fi
  mapfile -t ids < "$carta_tmpfile"
  rm -f "$carta_tmpfile"
else
  usage
fi

total=${#ids[@]}
if [ "$total" -eq 0 ]; then
  echo "Nada que sincronizar (lista de IDs vacía)." >&2
  exit 0
fi

ok=0
skip=0
n=0
for id in "${ids[@]}"; do
  id="$(echo "$id" | tr -d '[:space:]')"
  [ -z "$id" ] && continue
  n=$((n + 1))
  # stdin del hijo explícitamente en /dev/null: cinturón y tirantes además del
  # array en memoria, por si algún día se cambia el bucle.
  out="$(python3 "$SYNC_PY" --ids "$id" $dry_run < /dev/null)"
  rc=$?
  echo "$out"
  if [ $rc -ne 0 ]; then
    echo "=== ABORT: fallo en #$id ($n/$total procesados, $ok ok). Deteniendo lote, sin reintentar. ==="
    exit 1
  fi
  if echo "$out" | grep -q "PLAN: subiría\|#$id: ok"; then
    ok=$((ok + 1))
  else
    skip=$((skip + 1))
  fi
done

echo "=== FIN LOTE. ok=$ok skip=$skip de $total candidatos. ==="
