'use client';

import { Passenger } from '@edr/types';
import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useRef } from 'react';
import { io } from 'socket.io-client';

import {
  appendMessageToCache,
  SUPPORT_CONVERSATIONS_KEY,
  SUPPORT_UNREAD_KEY,
  supportMessagesKey,
} from './useSupport';

const SOCKET_ORIGIN = String(process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000').replace(
  /\/api\/?$/,
  '',
);

/**
 * Subscribes the signed-in agent to live support pushes for the whole shared
 * inbox. Any new message / conversation change refreshes the thread, the inbox
 * list, and the unread badge; `onMessage` fires for optional toasts.
 */
export function useSupportSocket(
  enabled: boolean,
  onMessage?: (event: Passenger.PassengerSupportMessageEvent) => void,
) {
  const qc = useQueryClient();
  const onMessageRef = useRef(onMessage);
  onMessageRef.current = onMessage;

  useEffect(() => {
    if (!enabled || typeof window === 'undefined') return;
    const token = localStorage.getItem('auth_token');
    if (!token) return;

    const socket = io(`${SOCKET_ORIGIN}/${Passenger.PASSENGER_SUPPORT_WS_NAMESPACE}`, {
      auth: { token },
      // Prefer WebSocket, fall back to HTTP long-polling if the proxy blocks
      // the upgrade (polling rides normal HTTPS, already CSP-allowed).
      transports: ['websocket', 'polling'],
      withCredentials: true,
    });

    // Temporary diagnostics — remove once live delivery is confirmed.
    socket.on('connect', () => console.warn('[support] agent socket connected', socket.id));
    socket.on('connect_error', (err) =>
      console.warn('[support] agent socket connect_error:', err.message),
    );
    socket.on('disconnect', (reason) =>
      console.warn('[support] agent socket disconnected:', reason),
    );
    socket.on('support:hello', (info) => console.warn('[support] server assigned:', info));

    socket.on(
      Passenger.PASSENGER_SUPPORT_WS_EVENTS.MESSAGE_NEW,
      (event: Passenger.PassengerSupportMessageEvent) => {
        // Append rather than invalidate: the thread is paginated, and
        // invalidating it would refetch every page the agent has scrolled back
        // through on every single inbound message.
        if (appendMessageToCache(qc, event.message) === 'uncached') {
          // The thread's first page is still loading and may have been read
          // before this message existed — without this it would go missing
          // until some unrelated refetch. Cheap: there are no pages to
          // re-fetch yet.
          qc.invalidateQueries({
            queryKey: supportMessagesKey(event.message.conversationId),
          });
        }
        qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
        qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
        onMessageRef.current?.(event);
      },
    );

    socket.on(Passenger.PASSENGER_SUPPORT_WS_EVENTS.CONVERSATION_UPDATED, () => {
      qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
      qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
    });

    return () => {
      socket.off();
      socket.disconnect();
    };
  }, [enabled, qc]);
}
