'use client';

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

import { getDeviceId } from './deviceIdentity';
import {
  appendMessageToCache,
  patchConversationInCache,
  SUPPORT_THREAD_KEY,
  SUPPORT_UNREAD_KEY,
} from './useSupport';

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

/**
 * Subscribes the device to live support pushes. The gateway joins a
 * `guest:<deviceId>` room; any message/status change refreshes the thread and
 * the unread badge.
 */
export function useSupportSocket(enabled: boolean) {
  const qc = useQueryClient();

  useEffect(() => {
    if (!enabled || typeof window === 'undefined') return;
    const socket = io(`${SOCKET_ORIGIN}/${Passenger.PASSENGER_SUPPORT_WS_NAMESPACE}`, {
      auth: { guestId: getDeviceId() },
      // 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,
    });

    socket.on(
      Passenger.PASSENGER_SUPPORT_WS_EVENTS.MESSAGE_NEW,
      (event: Passenger.PassengerSupportMessageEvent) => {
        // Append rather than invalidate: the thread is paginated now, and
        // invalidating would refetch every loaded page on every inbound message.
        if (appendMessageToCache(qc, event.message) === 'uncached') {
          // The thread's first page is still loading and may have been read on
          // the server before this message existed — without this it would go
          // missing until some unrelated refetch. Cheap: no pages loaded yet.
          qc.invalidateQueries({ queryKey: SUPPORT_THREAD_KEY });
        }
        qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
      },
    );

    // Patch the conversation in place rather than invalidating the thread key —
    // the same key the paginated history uses. The server emits this alongside
    // MESSAGE_NEW for *every* message, so invalidating here would refetch every
    // page the visitor has scrolled back through on each one, cancelling out the
    // append above entirely. The payload is the updated conversation, so there's
    // nothing to go back to the server for.
    socket.on(
      Passenger.PASSENGER_SUPPORT_WS_EVENTS.CONVERSATION_UPDATED,
      (conversation: Passenger.PassengerSupportConversationDto) => {
        patchConversationInCache(qc, conversation);
        qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
      },
    );

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