import { useEffect, useRef, useState, useCallback } from 'react';

const MICROSERVICE_V2_URL = import.meta.env.VITE_EFC_MICROSERVICE_URL?.replace('/api/v1', '/api/v2') ?? '';

/**
 * Hook para conectarse a un endpoint SSE del microservicio y recibir eventos
 * de progreso de una tarea de auditoría.
 *
 * @param {string|null} taskId  - ID de la tarea Celery. null = no conectar.
 * @param {object}      options
 * @param {function}    options.onUpdate    - cb({ task_id, status, message, progress, resultado })
 * @param {function}    options.onCompleted - cb(resultado)
 * @param {function}    options.onFailed    - cb(message)
 */
export function useServerSentEvents(taskId, { onUpdate, onCompleted, onFailed } = {}) {
  const [connected, setConnected] = useState(false);
  const [lastEvent, setLastEvent] = useState(null);
  const esRef = useRef(null);
  const taskIdRef = useRef(taskId);
  taskIdRef.current = taskId;

  const disconnect = useCallback(() => {
    if (esRef.current) {
      esRef.current.close();
      esRef.current = null;
      setConnected(false);
    }
  }, []);

  useEffect(() => {
    if (!taskId) {
      disconnect();
      return;
    }

    // Evita reconexión si ya estamos conectados al mismo taskId
    if (esRef.current) {
      disconnect();
    }

    const url = `${MICROSERVICE_V2_URL}/stream/tasks/${taskId}`;
    const es = new EventSource(url);
    esRef.current = es;

    es.onopen = () => setConnected(true);

    es.addEventListener('task_update', (e) => {
      try {
        const data = JSON.parse(e.data);
        setLastEvent(data);
        onUpdate?.(data);

        if (data.status === 'completed') {
          onCompleted?.(data.resultado ?? data);
          disconnect();
        } else if (data.status === 'failed') {
          onFailed?.(data.message ?? 'La tarea falló');
          disconnect();
        }
      } catch {
        // JSON mal formado — ignorar
      }
    });

    es.addEventListener('heartbeat', () => {
      // Mantiene la conexión viva, no requiere acción
    });

    es.addEventListener('error', (e) => {
      // Solo fallar ante un evento SSE explícito del servidor (tiene e.data).
      // Los errores nativos de EventSource (red caída, timeout de Nginx) NO tienen e.data
      // y EventSource se reconecta automáticamente — no deben marcar la tarea como fallida.
      if (e instanceof MessageEvent && e.data) {
        try {
          onFailed?.(JSON.parse(e.data)?.message ?? 'Error en el stream');
        } catch {
          onFailed?.('Error en el stream');
        }
        disconnect();
      }
    });

    es.onerror = () => {
      // Error de conexión nativo — EventSource reintenta automáticamente.
      setConnected(false);
    };

    return () => {
      es.close();
      esRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [taskId]);

  return { connected, lastEvent, disconnect };
}
