// app/components/SSEContext.tsx
'use client';

import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { useCurrentUser } from './AuthContext';
import { Recognition } from '@/types/plates';

type ConnectionStatus = 'connected' | 'connecting' | 'disconnected' | 'error';

type ExportProgressMsg = {
  jobId: string;
  stage?: string;
  done?: number;
  total?: number;
  progress?: number; // 0..100 (serverseitig typ. bis 99)
};

type SSEContextType = {
  onNewRecognition: (cb: (r: Recognition) => void) => () => void;           // ← gibt Unsubscribe zurück
  onExportProgress: (cb: (m: ExportProgressMsg) => void) => () => void;      // ← neu
  connectionStatus: ConnectionStatus;
  newCount: number;
  resetNewCount: () => void;
};

const SSEContext = createContext<SSEContextType | undefined>(undefined);

export function SSEProvider({ children }: { children: React.ReactNode }) {
  const { user } = useCurrentUser();

  // Listener-Sets statt Arrays → leichtes Unsubscribe & keine Duplikate
  const recListeners   = useRef<Set<(r: Recognition) => void>>(new Set());
  const exportListeners= useRef<Set<(m: ExportProgressMsg) => void>>(new Set());

  const [status, setStatus]     = useState<ConnectionStatus>('disconnected');
  const [newCount, setNewCount] = useState(0);

  useEffect(() => {
    if (!user) {
      setStatus('disconnected');
      return;
    }

    setStatus('connecting');

    const es = new EventSource('/api/recognitions/stream', { withCredentials: true });

    es.onopen = () => setStatus('connected');

    es.addEventListener('new-recognition', (e) => {
      try {
        const rec = JSON.parse((e as MessageEvent).data) as Recognition;
        recListeners.current.forEach((cb) => {
          try { cb(rec); } catch {}
        });
        setNewCount((c) => c + 1);
      } catch {}
    });

    // Optional: ping nur, damit Verbindung „lebt“
    es.addEventListener('ping', () => { /* noop */ });

    // NEU: Export-Fortschritt
    es.addEventListener('export-progress', (e) => {
      try {
        const msg = JSON.parse((e as MessageEvent).data) as ExportProgressMsg;
        if (!msg || !msg.jobId) return;
        exportListeners.current.forEach((cb) => {
          try { cb(msg); } catch {}
        });
      } catch {}
    });

    // Server-initiierter Logout
    es.addEventListener('logout', (e) => {
      try {
        const { reason } = JSON.parse((e as MessageEvent).data);
        console.info('Server verlangt Logout:', reason);
      } catch {}
      fetch('/api/logout', { method: 'POST', credentials: 'include' })
        .finally(() => (window.location.href = '/login'));
    });

    es.onerror = (err) => {
      console.warn('SSE-Fehler:', err);
      // EventSource versucht selbst zu reconnecten; wir zeigen "error"/"connecting".
      setStatus('error');
      // kurze Zeit später wieder als "connecting" markieren
      setTimeout(() => setStatus('connecting'), 1000);
    };

    return () => {
      es.close();
      setStatus('disconnected');
    };
  }, [user]); // neu verbinden, wenn sich der eingeloggte User ändert

  // Registrieren & Unsubscribe zurückgeben
  const onNewRecognition = useCallback((cb: (r: Recognition) => void) => {
    recListeners.current.add(cb);
    return () => recListeners.current.delete(cb);
  }, []);

  const onExportProgress = useCallback((cb: (m: ExportProgressMsg) => void) => {
    exportListeners.current.add(cb);
    return () => exportListeners.current.delete(cb);
  }, []);

  const ctx: SSEContextType = {
    onNewRecognition,
    onExportProgress,   // ← im Frontend verwenden
    connectionStatus: status,
    newCount,
    resetNewCount: () => setNewCount(0),
  };

  return <SSEContext.Provider value={ctx}>{children}</SSEContext.Provider>;
}

export function useSSE() {
  const ctx = useContext(SSEContext);
  if (!ctx) throw new Error('useSSE must be used inside SSEProvider');
  return ctx;
}
