#!/bin/bash
# ============================================================
#  S.I.N.S.A — Test de la FASE 3 (planes autoadministrables + contenido)
#  Uso:
#     bash /var/www/sinsa/scripts/test-fase3.sh
#     bash /var/www/sinsa/scripts/test-fase3.sh https://sinsa.appr3.cloud
# ============================================================

BASE="$1"
LOCAL=0
CK_ADMIN=$(mktemp)
CK_CLI=$(mktemp)
OK=0
FALLA=0

if [ -z "$BASE" ]; then
  BASE="http://127.0.0.1:8797"
  LOCAL=1
  php -S 127.0.0.1:8797 -t /var/www/sinsa/public >/dev/null 2>&1 &
  SRV=$!
  sleep 2
fi

echo "Probando contra: $BASE"
echo "============================================================"

chk() {
  local titulo="$1" esperado="$2" contiene="$3" resp="$4"
  local code="${resp##*|}" body="${resp%|*}"
  if [ "$code" = "$esperado" ] && echo "$body" | grep -q -- "$contiene"; then
    printf "  OK    %-56s [HTTP %s]\n" "$titulo" "$code"; OK=$((OK+1))
  else
    printf "  FALLA %-56s [HTTP %s esperaba %s]\n" "$titulo" "$code" "$esperado"
    echo "        respuesta: $(echo "$body" | head -c 200)"; FALLA=$((FALLA+1))
  fi
}

req() {
  local m="$1" url="$2" data="$3" jar="$4"
  local args=(-sS -X "$m" -H 'Content-Type: application/json' -w '|%{http_code}')
  [ -n "$data" ] && args+=(-d "$data")
  [ -n "$jar" ] && args+=(-c "$jar" -b "$jar")
  curl "${args[@]}" "$url" 2>/dev/null
}

# extrae el "id" de la última respuesta JSON con {"plan":{"id":N,...
extraerId() { echo "$1" | grep -oE '"id":[0-9]+' | head -1 | grep -oE '[0-9]+'; }

echo "-- Sesión ----------------------------------------------------"
chk "login admin" 200 '"rol":"admin"' \
  "$(req POST "$BASE/api/auth.php?action=login" '{"username":"adminapp","password":"Admin2026_"}' "$CK_ADMIN")"
chk "login cliente" 200 '"rol":"cliente"' \
  "$(req POST "$BASE/api/auth.php?action=login" '{"username":"clienteprueba","password":"Prueba2026"}' "$CK_CLI")"

echo "-- Lectura pública --------------------------------------------"
LISTA_PUB=$(req GET "$BASE/api/planes.php")
chk "lista pública responde"                 200 '"ok":true'   "$LISTA_PUB"
chk "lista pública trae los planes semilla"  200 'Plan 360'    "$LISTA_PUB"

DET1=$(req GET "$BASE/api/planes.php?id=1")
chk "detalle de plan existente"              200 '"ok":true'          "$DET1"
chk "detalle trae material como array"       200 '"material":\['      "$DET1"
chk "detalle de plan inexistente da 404"     404 'no encontrado' "$(req GET "$BASE/api/planes.php?id=999999")"

echo "-- Control de acceso -------------------------------------------"
chk "listar ?todos=1 sin sesión: 401"        401 'No autenticado' "$(req GET "$BASE/api/planes.php?todos=1" '')"
chk "?todos=1 con sesión cliente: 403"       403 'Sin permisos'   "$(req GET "$BASE/api/planes.php?todos=1" '' "$CK_CLI")"
chk "crear sin sesión: 401"                  401 'No autenticado' \
  "$(req POST "$BASE/api/planes.php" '{"nombre":"x","precio_ars":1,"duracion_dias":1}')"
chk "crear con sesión cliente: 403"          403 'Sin permisos' \
  "$(req POST "$BASE/api/planes.php" '{"nombre":"x","precio_ars":1,"duracion_dias":1}' "$CK_CLI")"
chk "método no soportado: 405"               405 'no permitido' "$(req PATCH "$BASE/api/planes.php" '' "$CK_ADMIN")"

echo "-- CRUD admin: crear -----------------------------------------"
CREAR='{"nombre":"Plan de prueba automática","descripcion":"Creado por el test","precio_ars":9990.50,"duracion_dias":15,"contenido_html":"<h2>Hola</h2><p>Cuerpo</p><script>alert(1)</script>","material":[{"titulo":"Guía","url":"https://ejemplo.com/guia.pdf"}],"activo":1}'
RESP_CREAR=$(req POST "$BASE/api/planes.php" "$CREAR" "$CK_ADMIN")
chk "crear plan válido"                      201 '"ok":true'                 "$RESP_CREAR"
chk "el plan creado aparece en la respuesta" 201 'Plan de prueba automática' "$RESP_CREAR"
PLAN_ID=$(extraerId "$RESP_CREAR")

chk "nombre muy corto: 400"     400 'nombre' \
  "$(req POST "$BASE/api/planes.php" '{"nombre":"ab","precio_ars":1,"duracion_dias":1}' "$CK_ADMIN")"
chk "precio negativo: 400"      400 'precio' \
  "$(req POST "$BASE/api/planes.php" '{"nombre":"Plan válido","precio_ars":-5,"duracion_dias":1}' "$CK_ADMIN")"
chk "duración inválida: 400"    400 'duración' \
  "$(req POST "$BASE/api/planes.php" '{"nombre":"Plan válido","precio_ars":10,"duracion_dias":0}' "$CK_ADMIN")"

echo "-- Sanitización del contenido HTML -----------------------------"
if [ -n "$PLAN_ID" ]; then
  DET_CREADO=$(req GET "$BASE/api/planes.php?id=$PLAN_ID" '' "$CK_ADMIN")
  chk "el <script> inyectado NO sobrevive"      200 '' "$DET_CREADO"
  echo "$DET_CREADO" | grep -q '<script>alert' \
    && { printf "  FALLA %-56s\n" "contenido_html: <script> eliminado"; FALLA=$((FALLA+1)); } \
    || { printf "  OK    %-56s\n" "contenido_html: <script> eliminado"; OK=$((OK+1)); }
  chk "el resto del HTML permitido se conserva" 200 '<h2>Hola' "$DET_CREADO"
  chk "el material inválido no se guarda mal"   200 '"titulo":"Gu' "$DET_CREADO"
fi

CREAR_LINK_MALO='{"nombre":"Plan con link malicioso","precio_ars":100,"duracion_dias":10,"contenido_html":"<p>Click <a href=\"javascript:alert(1)\" onclick=\"steal()\">acá</a></p>"}'
RESP_LINK=$(req POST "$BASE/api/planes.php" "$CREAR_LINK_MALO" "$CK_ADMIN")
chk "crea el plan con el link peligroso" 201 '"ok":true' "$RESP_LINK"
echo "$RESP_LINK" | grep -q 'javascript:alert' \
  && { printf "  FALLA %-56s\n" "href javascript: neutralizado"; FALLA=$((FALLA+1)); } \
  || { printf "  OK    %-56s\n" "href javascript: neutralizado"; OK=$((OK+1)); }
echo "$RESP_LINK" | grep -q 'onclick=' \
  && { printf "  FALLA %-56s\n" "atributo onclick eliminado"; FALLA=$((FALLA+1)); } \
  || { printf "  OK    %-56s\n" "atributo onclick eliminado"; OK=$((OK+1)); }
PLAN_ID_LINK=$(extraerId "$RESP_LINK")

echo "-- Material: validación -----------------------------------------"
CREAR_MAT_MALO='{"nombre":"Plan con material malo","precio_ars":100,"duracion_dias":10,"material":[{"titulo":"","url":"https://x.com"},{"titulo":"Sin URL","url":"no-es-url"},{"titulo":"javascript","url":"javascript:alert(1)"},{"titulo":"OK","url":"https://valido.com/a"}]}'
RESP_MAT=$(req POST "$BASE/api/planes.php" "$CREAR_MAT_MALO" "$CK_ADMIN")
chk "crea igual, descartando ítems inválidos" 201 '"ok":true' "$RESP_MAT"
echo "$RESP_MAT" | grep -oE '"material":\[[^]]*\]' | grep -q '"titulo":"OK"' \
  && { printf "  OK    %-56s\n" "solo el material válido quedó guardado"; OK=$((OK+1)); } \
  || { printf "  FALLA %-56s\n" "solo el material válido quedó guardado"; FALLA=$((FALLA+1)); }
echo "$RESP_MAT" | grep -q 'javascript:alert' \
  && { printf "  FALLA %-56s\n" "material javascript: descartado"; FALLA=$((FALLA+1)); } \
  || { printf "  OK    %-56s\n" "material javascript: descartado"; OK=$((OK+1)); }
PLAN_ID_MAT=$(extraerId "$RESP_MAT")

echo "-- CRUD admin: actualizar --------------------------------------"
if [ -n "$PLAN_ID" ]; then
  chk "actualizar precio"        200 '"ok":true' \
    "$(req PUT "$BASE/api/planes.php?id=$PLAN_ID" '{"precio_ars":12345.67}' "$CK_ADMIN")"
  DET_UPD=$(req GET "$BASE/api/planes.php?id=$PLAN_ID")
  chk "el precio quedó actualizado" 200 '12345.67' "$DET_UPD"

  chk "actualizar sin body: 400" 400 'No hay cambios' \
    "$(req PUT "$BASE/api/planes.php?id=$PLAN_ID" '{}' "$CK_ADMIN")"
  chk "actualizar plan inexistente: 404" 404 'no encontrado' \
    "$(req PUT "$BASE/api/planes.php?id=999999" '{"precio_ars":1}' "$CK_ADMIN")"
  chk "actualizar sin id: 400" 400 'Falta el id' \
    "$(req PUT "$BASE/api/planes.php" '{"precio_ars":1}' "$CK_ADMIN")"
  chk "cliente no puede actualizar: 403" 403 'Sin permisos' \
    "$(req PUT "$BASE/api/planes.php?id=$PLAN_ID" '{"precio_ars":1}' "$CK_CLI")"
fi

echo "-- Ocultar / publicar y baja lógica -----------------------------"
if [ -n "$PLAN_ID" ]; then
  chk "ocultar el plan (activo=0)" 200 '"ok":true' \
    "$(req PUT "$BASE/api/planes.php?id=$PLAN_ID" '{"activo":0}' "$CK_ADMIN")"
  chk "plan oculto: público lo ve como 404" 404 'no está disponible' \
    "$(req GET "$BASE/api/planes.php?id=$PLAN_ID")"
  chk "plan oculto: el admin SÍ lo sigue viendo" 200 '"ok":true' \
    "$(req GET "$BASE/api/planes.php?id=$PLAN_ID" '' "$CK_ADMIN")"
  LISTA_PUB2=$(req GET "$BASE/api/planes.php")
  echo "$LISTA_PUB2" | grep -q "Plan de prueba automática" \
    && { printf "  FALLA %-56s\n" "plan oculto no aparece en la lista pública"; FALLA=$((FALLA+1)); } \
    || { printf "  OK    %-56s\n" "plan oculto no aparece en la lista pública"; OK=$((OK+1)); }

  chk "DELETE es baja lógica (activo=0)" 200 '"ok":true' \
    "$(req DELETE "$BASE/api/planes.php?id=$PLAN_ID" '' "$CK_ADMIN")"
  chk "tras DELETE el plan sigue existiendo (para el admin)" 200 '"ok":true' \
    "$(req GET "$BASE/api/planes.php?id=$PLAN_ID" '' "$CK_ADMIN")"
  chk "DELETE de plan inexistente: 404" 404 'no encontrado' \
    "$(req DELETE "$BASE/api/planes.php?id=999999" '' "$CK_ADMIN")"
  chk "cliente no puede eliminar: 403" 403 'Sin permisos' \
    "$(req DELETE "$BASE/api/planes.php?id=$PLAN_ID" '' "$CK_CLI")"
fi

echo "-- Reordenar (orden) --------------------------------------------"
if [ -n "$PLAN_ID_MAT" ]; then
  chk "reordenar: PUT orden" 200 '"ok":true' \
    "$(req PUT "$BASE/api/planes.php?id=$PLAN_ID_MAT" '{"orden":1}' "$CK_ADMIN")"
  DET_ORD=$(req GET "$BASE/api/planes.php?id=$PLAN_ID_MAT" '' "$CK_ADMIN")
  chk "el orden quedó guardado" 200 '"orden":1' "$DET_ORD"
fi

echo "-- Limpieza -------------------------------------------------------"
# Dar de baja TODO lo que creó este test, con la sesión admin todavía activa
# (tiene que ir antes del logout de la sección de regresión, o los DELETE
# de limpieza fallarían con 401 y quedarían planes de prueba publicados).
for pid in "$PLAN_ID" "$PLAN_ID_MAT" "$PLAN_ID_LINK"; do
  if [ -n "$pid" ]; then
    RESP_LIMPIEZA=$(req DELETE "$BASE/api/planes.php?id=$pid" '' "$CK_ADMIN")
    echo "$RESP_LIMPIEZA" | grep -q '"ok":true' \
      && { printf "  OK    %-56s [HTTP %s]\n" "plan de prueba #$pid dado de baja" "${RESP_LIMPIEZA##*|}"; OK=$((OK+1)); } \
      || { printf "  FALLA %-56s\n" "plan de prueba #$pid dado de baja"; echo "        $RESP_LIMPIEZA"; FALLA=$((FALLA+1)); }
  fi
done

echo "-- Regresión Fase 1 y 2 ------------------------------------------"
chk "health sigue ok"           200 '"tablas":6'  "$(req GET "$BASE/api/health.php")"
chk "config inicio sigue ok"    200 'Plan 360'    "$(req GET "$BASE/api/config.php?action=inicio")"
chk "metrics admin sigue ok"    200 '"metricas"'  "$(req GET "$BASE/api/metrics.php?action=admin" '' "$CK_ADMIN")"
chk "logout admin"              200 '"ok":true'   "$(req POST "$BASE/api/auth.php?action=logout" '' "$CK_ADMIN")"

echo "============================================================"
echo "  $OK OK · $FALLA fallas"

rm -f "$CK_ADMIN" "$CK_CLI"
rm -f /var/www/sinsa/logs/ratelimit/*.json 2>/dev/null
if [ "$LOCAL" = "1" ]; then
  kill "$SRV" 2>/dev/null
  wait "$SRV" 2>/dev/null
fi

exit $([ "$FALLA" -eq 0 ] && echo 0 || echo 1)
