import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { fetchNotificacionByTaskId } from '../api/notificaciones';

const STORAGE_KEY = 'efc_audit_tasks';

/**
 * TaskProgressContext
 *
 * Gestiona las tareas de auditoría en background. Persiste en localStorage para
 * sobrevivir recargas de página. Reconecta SSE automáticamente para tareas que
 * quedaron en "processing" tras un refresh.
 *
 * Estructura de cada tarea:
 * {
 *   task_id:      string,
 *   label:        string,   // 'EDocuments', 'COVEs', etc.
 *   status:       'submitted' | 'processing' | 'completed' | 'failed',
 *   message:      string,
 *   progress:     number,   // 0-100
 *   resultado:    object | null,
 *   organizacion_id: string,
 *   started_at:   ISO string,
 *   dismissed:    boolean,
 * }
 */

const TaskProgressContext = createContext(null);

export function useTaskProgress() {
  const ctx = useContext(TaskProgressContext);
  if (!ctx) throw new Error('useTaskProgress debe usarse dentro de TaskProgressProvider');
  return ctx;
}

function loadFromStorage() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return [];
    const tasks = JSON.parse(raw);
    const cutoff = Date.now() - 24 * 60 * 60 * 1000; // 24 horas
    // Auto-descartar tareas "processing/submitted" con más de 24h (nunca terminaron)
    return tasks.map(t => {
      if (
        (t.status === 'processing' || t.status === 'submitted') &&
        t.started_at &&
        new Date(t.started_at).getTime() < cutoff
      ) {
        return { ...t, dismissed: true, status: 'failed', message: 'Tarea expirada' };
      }
      return t;
    });
  } catch {
    return [];
  }
}

function saveToStorage(tasks) {
  try {
    // Solo persistir las últimas 20 tareas no descartadas para no crecer indefinidamente
    const toSave = tasks.slice(-20);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
  } catch {
    // Storage lleno — ignorar
  }
}

export function TaskProgressProvider({ children }) {
  const [tasks, setTasksRaw] = useState(() => loadFromStorage());
  // task_id que Auditor.jsx debe abrir automáticamente al montar
  const [pendingOpenTaskId, setPendingOpenTaskId] = useState(null);

  const setTasks = useCallback((updater) => {
    setTasksRaw((prev) => {
      const next = typeof updater === 'function' ? updater(prev) : updater;
      saveToStorage(next);
      return next;
    });
  }, []);

  // Añade una tarea nueva (cuando el usuario dispara una auditoría)
  const addTask = useCallback((taskData) => {
    setTasks((prev) => {
      // Evitar duplicados
      if (prev.find((t) => t.task_id === taskData.task_id)) return prev;
      return [
        ...prev,
        {
          status: 'submitted',
          message: 'Tarea enviada',
          progress: 0,
          resultado: null,
          dismissed: false,
          started_at: new Date().toISOString(),
          ...taskData,
        },
      ];
    });
  }, [setTasks]);

  // Actualiza campos de una tarea existente por task_id
  const updateTask = useCallback((task_id, patch) => {
    setTasks((prev) =>
      prev.map((t) => (t.task_id === task_id ? { ...t, ...patch } : t))
    );
  }, [setTasks]);

  // Descarta una tarea de la vista (no la borra de storage)
  const dismissTask = useCallback((task_id) => {
    setTasks((prev) =>
      prev.map((t) => (t.task_id === task_id ? { ...t, dismissed: true } : t))
    );
  }, [setTasks]);

  // Llamado desde TaskProgressCard cuando el usuario hace click en "Ver resultado"
  const openTaskInAuditor = useCallback((task_id) => {
    setPendingOpenTaskId(task_id);
  }, []);

  // Llamado desde Auditor.jsx después de consumir el pendingOpenTaskId
  const clearPendingOpen = useCallback(() => {
    setPendingOpenTaskId(null);
  }, []);

  const getTask = useCallback(
    (task_id) => tasks.find((t) => t.task_id === task_id) ?? null,
    [tasks]
  );

  // Al montar: intenta recuperar tareas que completaron mientras el cliente no estaba conectado
  // (Redis TTL expirado, página cerrada, etc.). Consulta la Notificacion en DB por task_id.
  useEffect(() => {
    const staleTasks = loadFromStorage().filter(
      (t) => !t.dismissed && t.status !== 'completed' && t.status !== 'failed'
    );
    if (staleTasks.length === 0) return;

    staleTasks.forEach(async (task) => {
      try {
        const notif = await fetchNotificacionByTaskId(task.task_id);
        if (notif?.datos?.resultado) {
          updateTask(task.task_id, {
            status: 'completed',
            resultado: notif.datos.resultado,
            message: notif.mensaje,
            progress: 100,
          });
        }
      } catch {
        // Tarea aún en proceso o usuario no autenticado aún — ignorar
      }
    });
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // Tareas visibles (no descartadas)
  const visibleTasks = tasks.filter((t) => !t.dismissed);

  return (
    <TaskProgressContext.Provider
      value={{
        tasks,
        visibleTasks,
        addTask,
        updateTask,
        dismissTask,
        openTaskInAuditor,
        pendingOpenTaskId,
        clearPendingOpen,
        getTask,
      }}
    >
      {children}
    </TaskProgressContext.Provider>
  );
}
