#!/usr/bin/env bash
# smoke-test.sh — Verifica que las rutas GET respondan sin HTTP 500 ni excepciones PHP.
#
# Uso:
#   ./scripts/smoke-test.sh                  # prueba lista de ~80 rutas
#   ./scripts/smoke-test.sh --verbose        # muestra rutas OK también
#   ./scripts/smoke-test.sh --url http://..  # URL base distinta
#   ./scripts/smoke-test.sh --no-warmup      # saltarse calentado de caché
#   ./scripts/smoke-test.sh --workers 6      # requests concurrentes (default: 2)
#   ./scripts/smoke-test.sh --strict         # tratar timeouts como errores (default: advertencias)
#
# Salida: exit 0 = todo OK, exit 1 = hay errores (500 / excepciones / login redirect)

set -euo pipefail

BASE_URL="${MBINV_URL:-http://127.0.0.1:8099}"
PHP="${MBINV_PHP:-/usr/local/opt/php@8.2/bin/php}"
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
VERBOSE=0
WARMUP=1
WORKERS=2
TIMEOUT=60
SLOW_THRESHOLD=20
STRICT=0

for arg in "$@"; do
  case $arg in
    --verbose)    VERBOSE=1 ;;
    --no-warmup)  WARMUP=0 ;;
    --url=*)      BASE_URL="${arg#--url=}" ;;
    --workers=*)  WORKERS="${arg#--workers=}" ;;
    --timeout=*)  TIMEOUT="${arg#--timeout=}" ;;
    --strict)     STRICT=1 ;;
  esac
done

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
log() { echo -e "${CYAN}[smoke]${RESET} $*"; }

# ── Calentado de caché ─────────────────────────────────────────────────────────
if [[ $WARMUP -eq 1 ]]; then
  log "Calentando caché Symfony..."
  "$PHP" "${PROJECT_DIR}/bin/console" \
    cache:warmup --env=dev --no-optional-warmers -q 2>/dev/null \
    && log "Caché lista" \
    || log "${YELLOW}warmup con advertencias${RESET}"
fi

# ── Login: obtener cookie de sesión ───────────────────────────────────────────
COOKIE_JAR="$(mktemp /tmp/smoke-cookies.XXXXXX)"
trap 'rm -f "$COOKIE_JAR"' EXIT

log "Autenticando..."

hora=$("$PHP" -r "date_default_timezone_set('America/Guatemala'); echo (new DateTime())->format('H');")

for attempt in 0 -1; do
  h=$(( (10#$hora + attempt + 24) % 24 ))
  password="monse${h}"
  csrf=$(curl -s -c "$COOKIE_JAR" "${BASE_URL}/login" \
    | grep -o 'name="_csrf_token" value="[^"]*"' \
    | sed 's/name="_csrf_token" value="//;s/"//')
  [[ -z "$csrf" ]] && { echo -e "${RED}ERROR: sin CSRF en ${BASE_URL}/login${RESET}" >&2; exit 1; }
  loc=$(curl -s -c "$COOKIE_JAR" -b "$COOKIE_JAR" \
    -X POST "${BASE_URL}/login_check" \
    --data-urlencode "_username=mb" \
    --data-urlencode "_password=${password}" \
    --data-urlencode "_csrf_token=${csrf}" \
    -D - 2>/dev/null | grep -i "^location:" | tr -d '\r' | awk '{print $2}')
  echo "$loc" | grep -q "/login" || break
done

echo "$loc" | grep -q "/login" && \
  { echo -e "${RED}ERROR: Login fallido. Revisa usuario 'mb' en la BD.${RESET}" >&2; exit 1; }

log "Autenticado (pwd=${password})"
# curl escribe #HttpOnly_hostname; Python's MozillaCookieJar lo trata como comentario
sed -i '' 's/^#HttpOnly_//' "$COOKIE_JAR"

# ── Lanzar pruebas con Python ─────────────────────────────────────────────────
python3 - "$BASE_URL" "$COOKIE_JAR" "$WORKERS" "$TIMEOUT" "$SLOW_THRESHOLD" "$VERBOSE" "$STRICT" << 'PYEOF'
import sys, http.cookiejar, urllib.request, urllib.error, time, os
from concurrent.futures import ThreadPoolExecutor, as_completed

base_url, cookie_file, workers, timeout, slow_thresh, verbose, strict = sys.argv[1:]
workers      = int(workers)
timeout      = int(timeout)
slow_thresh  = int(slow_thresh)
verbose      = verbose == "1"
strict       = strict == "1"

ROUTES = [
    # Catálogos principales
    "/", "/articulo/", "/cajacorrelativos/", "/categoria/",
    "/departamento/", "/documento/", "/documentosmaestro/",
    "/estilo/", "/fabricante/", "/fisico/", "/fisico/plantilla",
    "/fisicoplantillamaestro/", "/formaspago/", "/formulasvariablesmaestro/",
    "/futuromaestro/", "/hoja/", "/limiteclientediascorte/", "/linea/",
    "/listaprecios/", "/maecaj/", "/maecli/", "/maecli/listaclientes",
    "/maecup/", "/maeemi/", "/maemex/", "/maeped/", "/maeprocedencia/",
    "/maerecipiente/", "/maeven/", "/marca/", "/mensajitostelefonos/",
    "/minimomaximo/", "/movimiento/", "/oferta/",
    "/parametrosglobales/", "/parametrosmaeemi/", "/pedidosplantillamaestro/",
    "/produccionmaestro/", "/producto/index", "/proveedor/",
    "/reparaciones/", "/tamano/", "/tienda/", "/tipo/",
    "/touch/", "/traslado/", "/trasladoentransito/",
    "/unidad/", "/usuario/", "/variedad/", "/webreporte/",
    # Formularios new
    "/producto/new", "/documento/new", "/movimiento/new",
    "/traslado/new", "/fisico/new", "/maecli/new", "/maecaj/new",
    # Procesos
    "/procesos/importar/productos", "/procesos/importar/etiquetas",
    "/procesos/importar/compra",    "/procesos/importar/listas",
    "/procesos/importar/fisico",    "/procesos/importar/formulas",
    "/procesos/importar/ventas",    "/procesos/importar/minmax",
    "/procesos/importar/predefinidas", "/procesos/importar/ofertas",
    "/procesos/importar/clientes",  "/procesos/imagenes/cargar",
    "/procesos/recalcular/costos",  "/procesos/index/conteoAleatorio",
    "/procesos/acercade",
    # Consultas
    "/consultas/existencias", "/consultas/existencias/tabla",
    "/consultas/compras", "/consultas/documentos/inventario",
    "/consultas/documentos/pos", "/consultas/consulta/usuario/",
    "/consultas/producto/precios", "/cuadrediario",
]

# Cargar cookies de sesión
jar = http.cookiejar.MozillaCookieJar(cookie_file)
try:
    jar.load(ignore_discard=True, ignore_expires=True)
except:
    pass

opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
opener.addheaders = [('User-Agent', 'MBInv-SmokeTest/1.0')]

GREEN  = '\033[0;32m'
RED    = '\033[0;31m'
YELLOW = '\033[1;33m'
BOLD   = '\033[1m'
RESET  = '\033[0m'

def test_route(route):
    url = base_url + route
    t0  = time.time()
    try:
        resp = opener.open(url, timeout=timeout)
        elapsed = time.time() - t0
        code = resp.getcode()
        body = resp.read(8192).decode('utf-8', errors='replace')

        if code == 500:
            return ('error', code, route, elapsed, 'HTTP 500')
        if '"class":"' in body and 'Exception' in body:
            return ('exception', code, route, elapsed, 'Exception en respuesta')
        if 'name="_username"' in body or 'action="/login_check"' in body:
            return ('error', code, route, elapsed, 'redirigido a login (sin autenticar)')
        if elapsed > slow_thresh:
            return ('slow', code, route, elapsed, f'{elapsed:.1f}s')
        return ('ok', code, route, elapsed, '')

    except urllib.error.HTTPError as e:
        elapsed = time.time() - t0
        return ('error', e.code, route, elapsed, str(e))
    except Exception as e:
        elapsed = time.time() - t0
        err_msg = str(e)[:80]
        if 'timed out' in err_msg.lower():
            return ('timeout', 0, route, elapsed, f'{timeout}s timeout')
        return ('error', 0, route, elapsed, err_msg)

print(f"\n{BOLD}╔══════════════════════════════════════════╗{RESET}")
print(f"{BOLD}║        MBInv — Smoke Test Suite          ║{RESET}")
print(f"{BOLD}╚══════════════════════════════════════════╝{RESET}")
print(f"  URL    : \033[0;36m{base_url}{RESET}")
print(f"  Rutas  : {len(ROUTES)}  |  Workers: {workers}  |  Timeout: {timeout}s  |  Slow: >{slow_thresh}s\n")

results    = []
ok_count   = 0
slow_count = 0
err_count  = 0

with ThreadPoolExecutor(max_workers=workers) as pool:
    futures = {pool.submit(test_route, r): r for r in ROUTES}
    for fut in as_completed(futures):
        status, code, route, elapsed, detail = fut.result()
        results.append((status, code, route, elapsed, detail))
        if status == 'ok':
            ok_count += 1
            if verbose:
                print(f"  {GREEN}v{RESET} {code}  {route}  ({elapsed:.1f}s)")
        elif status == 'slow':
            slow_count += 1
            print(f"  {YELLOW}!{RESET} LENTO  {route}  ({detail})")
        elif status == 'timeout':
            if strict:
                err_count += 1
                print(f"  {RED}x{RESET} TIMEOUT  {route}  ({detail})")
            else:
                slow_count += 1
                print(f"  {YELLOW}!{RESET} TIMEOUT  {route}  ({detail})")
        else:
            err_count += 1
            print(f"  {RED}x{RESET} {code}  {route}  -- {detail}")

timeout_note = "" if strict else " (timeouts = advertencias en modo dev)"
total = len(ROUTES)
print(f"\n{BOLD}══════════════════ Resumen ═══════════════════{RESET}")
print(f"  Rutas probadas : {total}")
print(f"  {GREEN}OK             : {ok_count}{RESET}")
if slow_count: print(f"  {YELLOW}Lentas/Timeout : {slow_count}{timeout_note}{RESET}")

if err_count:
    print(f"  {RED}Errores (500/exc/login): {err_count}{RESET}")
    print(f"\n{RED}Hay errores — revisa las rutas marcadas con x.{RESET}\n")
    sys.exit(1)
else:
    if slow_count:
        print(f"\n  {YELLOW}(rutas lentas/timeout son advertencias, no errores funcionales){RESET}")
    print(f"\n{GREEN}{BOLD}Sin errores funcionales. La migracion responde correctamente.{RESET}\n")
    sys.exit(0)
PYEOF
