#!/usr/bin/env bash
# load_test.sh — prueba de carga configurable via .env
#
# Lee la configuración del .env del proyecto.
# Variables relevantes (todas opcionales — tienen defaults):
#
#   LOAD_TEST_RPS=50          requests por segundo
#   LOAD_TEST_DURATION=5      duración en segundos
#   LOAD_TEST_URL=http://localhost:3100   URL destino (sin path)
#   LOAD_TEST_NATIONALID=22222222
#   LOAD_TEST_GENDER=M
#   APIKEY_MASTER=...         se lee del .env automáticamente
#
# Uso:
#   bash load_test.sh
#   LOAD_TEST_RPS=100 LOAD_TEST_DURATION=10 bash load_test.sh
#   LOAD_TEST_URL=https://apibatch.fidelitas.com.ar bash load_test.sh

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"

# Cargar .env si existe
if [[ -f "$ENV_FILE" ]]; then
  # Exportar solo las variables relevantes, ignorando comentarios y líneas vacías
  set -a
  # shellcheck disable=SC1090
  source <(grep -v '^\s*#' "$ENV_FILE" | grep -v '^\s*$')
  set +a
fi

# ── Configuración — override via variable de entorno o .env ──────────────────
RPS="${LOAD_TEST_RPS:-50}"
DURATION="${LOAD_TEST_DURATION:-5}"
BASE_URL="${LOAD_TEST_URL:-http://localhost:3100}"
APIKEY="${APIKEY_MASTER:-fide-dev-local-test-key}"
NATIONALID="${LOAD_TEST_NATIONALID:-22222222}"
GENDER="${LOAD_TEST_GENDER:-M}"
ENDPOINT="/v3/face-match/"

TOTAL=$(( RPS * DURATION ))
INTERVAL_US=$(( 1000000 / RPS ))   # microsegundos entre requests

# Selfie: usar archivo si existe, si no base64 mínimo válido
SELFIE_FILE="$SCRIPT_DIR/storage/selfie_test_b64.txt"
if [[ -f "$SELFIE_FILE" ]]; then
  SELFIE=$(cat "$SELFIE_FILE")
else
  SELFIE="AAAA"
fi

# ── Contadores ───────────────────────────────────────────────────────────────
SENT=0; DONE=0; OK=0; ERR=0; RATE_LIMITED=0
declare -A STATUS_CODES
START_TS=$(date +%s%3N)   # epoch ms

# Archivo temporal para resultados de curl en background
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT

# ── Función: un request ──────────────────────────────────────────────────────
do_request() {
  local idx="$1"
  local t0 t1 http_code

  t0=$(date +%s%3N)
  http_code=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "${BASE_URL}${ENDPOINT}" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "apikey=${APIKEY}" \
    --data-urlencode "selfie_image=${SELFIE}" \
    --data-urlencode "nationalid=${NATIONALID}" \
    --data-urlencode "gender=${GENDER}" \
    --max-time 15 \
    2>/dev/null) || http_code="ERR"

  t1=$(date +%s%3N)
  echo "${http_code} $(( t1 - t0 ))" > "$TMP_DIR/$idx"
}

# ── Cabecera ─────────────────────────────────────────────────────────────────
echo ""
echo "════════════════════════════════════════════════════════════"
echo "  PRUEBA DE CARGA — face-match-node"
echo "════════════════════════════════════════════════════════════"
echo "  Destino   : ${BASE_URL}${ENDPOINT}"
echo "  Objetivo  : ${RPS} rps × ${DURATION}s = ${TOTAL} requests"
echo "  Selfie    : $([ -f "$SELFIE_FILE" ] && echo "$SELFIE_FILE" || echo "mínima (sin imagen real)")"
echo "────────────────────────────────────────────────────────────"
echo "  Iniciando... (Ctrl+C para detener)"
echo ""

# ── Bucle de envío ───────────────────────────────────────────────────────────
for (( i=1; i<=TOTAL; i++ )); do
  do_request "$i" &
  SENT=$i

  # Progreso cada segundo
  if (( i % RPS == 0 )); then
    ELAPSED=$(( ( $(date +%s%3N) - START_TS ) / 1000 ))
    printf "  [%ds] enviados: %d/%d\r" "$ELAPSED" "$SENT" "$TOTAL"
  fi

  # Throttle: esperar el intervalo entre requests
  if (( i < TOTAL )); then
    sleep "0.$(printf '%06d' $INTERVAL_US | head -c 6)" 2>/dev/null \
      || usleep "$INTERVAL_US" 2>/dev/null \
      || true
  fi
done

echo ""
echo "  Esperando que terminen los requests en vuelo..."
wait

# ── Recolectar resultados ────────────────────────────────────────────────────
declare -a LATENCIES=()
for (( i=1; i<=TOTAL; i++ )); do
  if [[ -f "$TMP_DIR/$i" ]]; then
    read -r code lat < "$TMP_DIR/$i"
    LATENCIES+=("$lat")
    STATUS_CODES["$code"]=$(( ${STATUS_CODES["$code"]:-0} + 1 ))
    case "$code" in
      2*) OK=$(( OK + 1 )) ;;
      429) RATE_LIMITED=$(( RATE_LIMITED + 1 )); ERR=$(( ERR + 1 )) ;;
      ERR) ERR=$(( ERR + 1 )) ;;
      *) ERR=$(( ERR + 1 )) ;;
    esac
    DONE=$(( DONE + 1 ))
  fi
done

# ── Calcular estadísticas ────────────────────────────────────────────────────
END_TS=$(date +%s%3N)
ELAPSED_MS=$(( END_TS - START_TS ))
ELAPSED_S=$(echo "scale=1; $ELAPSED_MS / 1000" | bc)
REAL_RPS=$(echo "scale=1; $DONE * 1000 / $ELAPSED_MS" | bc)

# Ordenar latencias para percentiles
IFS=$'\n' SORTED=($(sort -n <<< "${LATENCIES[*]}")); unset IFS
N=${#SORTED[@]}
SUM=0
for lat in "${SORTED[@]}"; do SUM=$(( SUM + lat )); done
AVG=$(( N > 0 ? SUM / N : 0 ))
P50=${SORTED[$(( N * 50 / 100 ))]}
P95=${SORTED[$(( N * 95 / 100 ))]}
P99=${SORTED[$(( N * 99 / 100 ))]}
MAX=${SORTED[$(( N - 1 ))]}

# ── Informe ──────────────────────────────────────────────────────────────────
echo ""
echo "════════════════════════════════════════════════════════════"
echo "  RESULTADO"
echo "════════════════════════════════════════════════════════════"
printf "  Enviados     : %d\n" "$SENT"
printf "  Completados  : %d\n" "$DONE"
printf "  Exitosos 2xx : %d\n" "$OK"
printf "  Errores      : %d\n" "$ERR"
printf "  Rate limited : %d  (HTTP 429)\n" "$RATE_LIMITED"
printf "  Throughput   : %s rps reales\n" "$REAL_RPS"
echo "────────────────────────────────────────────────────────────"
echo "  Latencia (ms):"
printf "    Promedio   : %d ms\n" "$AVG"
printf "    p50        : %d ms\n" "${P50:-0}"
printf "    p95        : %d ms\n" "${P95:-0}"
printf "    p99        : %d ms\n" "${P99:-0}"
printf "    Máximo     : %d ms\n" "${MAX:-0}"
echo "────────────────────────────────────────────────────────────"
echo "  Códigos HTTP:"
for code in $(echo "${!STATUS_CODES[@]}" | tr ' ' '\n' | sort); do
  count="${STATUS_CODES[$code]}"
  pct=$(echo "scale=1; $count * 100 / $DONE" | bc)
  printf "    %-8s : %d  (%s%%)\n" "$code" "$count" "$pct"
done
echo "════════════════════════════════════════════════════════════"

# Interpretación automática
[[ "$RATE_LIMITED" -gt 0 ]] && echo "  ⚠  Rate limit activado — ajustar RATE_LIMIT_PER_IP_PER_MIN en .env"
[[ "$ERR" -gt $(( DONE / 100 )) ]] && echo "  ⚠  Tasa de error > 1% — verificar que el servicio esté corriendo"
[[ "${P95:-9999}" -lt 100 ]] && echo "  ✓  p95 < 100ms — el servicio responde rápido (antes de RENAPER)"
echo ""
