import {
  SUPPORT_CHAT_WS_EVENTS,
  SUPPORT_CHAT_WS_NAMESPACE,
  type SupportConversationDto,
  type SupportMessageEvent,
} from "@edr/types";
import { useQueryClient } from "@tanstack/react-query";
import { useEffect, useRef } from "react";
import { io } from "socket.io-client";

import { API_BASE_URL } from "@/constants/apiConfig";

import {
  appendMessageToCache,
  SUPPORT_CONVERSATION_KEY,
  SUPPORT_MESSAGES_KEY,
  SUPPORT_UNREAD_KEY,
} from "./useSupport";

function getAuthToken(): string | undefined {
  return document.cookie
    .split("; ")
    .find((row) => row.startsWith("auth-token="))
    ?.split("=")[1];
}

// The socket namespace lives at the server root, not under the `/api` REST
// prefix — strip a trailing `/api` if the base URL carries one.
const SOCKET_ORIGIN = String(API_BASE_URL ?? "").replace(/\/api\/?$/, "");

/**
 * Subscribes to live support-chat pushes for the signed-in customer. The company
 * only has one thread, so every push belongs to it: the message goes straight
 * into the thread cache, the conversation and unread badge are refreshed, and
 * `onMessage` fires (the widget shows a toast when the panel is closed).
 */
export function useSupportSocket(
  enabled: boolean,
  onMessage?: (event: SupportMessageEvent) => void,
) {
  const qc = useQueryClient();
  const onMessageRef = useRef(onMessage);
  onMessageRef.current = onMessage;

  useEffect(() => {
    if (!enabled) return;
    const token = getAuthToken();
    if (!token) return;

    const socket = io(`${SOCKET_ORIGIN}/${SUPPORT_CHAT_WS_NAMESPACE}`, {
      auth: { token },
      transports: ["websocket"],
      withCredentials: true,
    });

    socket.on(
      SUPPORT_CHAT_WS_EVENTS.MESSAGE_NEW,
      (event: SupportMessageEvent) => {
        // Append rather than invalidate: the thread is paginated, and invalidating
        // it would refetch every page the customer 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: SUPPORT_MESSAGES_KEY });
        }
        qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATION_KEY });
        qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
        onMessageRef.current?.(event);
      },
    );

    socket.on(
      SUPPORT_CHAT_WS_EVENTS.CONVERSATION_UPDATED,
      (_conversation: SupportConversationDto) => {
        qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATION_KEY });
        qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
      },
    );

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