import { useEffect, useRef } from 'react';
import {
  getBaseApiReactSocket,
  pauseAllQueues,
  resumeAllQueues,
} from '../../App';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';

export const WebSocketActive = ({ myAddress, setIsLoadingGroups }) => {
  const socketRef = useRef(null); // WebSocket reference
  const timeoutIdRef = useRef(null); // Timeout ID reference
  const groupSocketTimeoutRef = useRef(null); // Group Socket Timeout reference
  const initiateRef = useRef(null);
  const forceCloseWebSocket = () => {
    if (socketRef.current) {
      clearTimeout(timeoutIdRef.current);
      clearTimeout(groupSocketTimeoutRef.current);
      socketRef.current.close(1000, 'forced');
      socketRef.current = null;
    }
  };

  const logoutEventFunc = () => {
    forceCloseWebSocket();
  };

  useEffect(() => {
    subscribeToEvent('logout-event', logoutEventFunc);

    return () => {
      unsubscribeFromEvent('logout-event', logoutEventFunc);
    };
  }, []);

  useEffect(() => {
    if (!myAddress) return; // Only proceed if myAddress is set

    const pingHeads = () => {
      try {
        if (socketRef.current?.readyState === WebSocket.OPEN) {
          socketRef.current.send('ping');
          timeoutIdRef.current = setTimeout(() => {
            if (socketRef.current) {
              socketRef.current.close();
              clearTimeout(groupSocketTimeoutRef.current);
            }
          }, 5000); // Close if no pong in 5 seconds
        }
      } catch (error) {
        console.error('Error during ping:', error);
      }
    };

    const initWebsocketMessageGroup = async () => {
      forceCloseWebSocket(); // Ensure we close any existing connection
      const currentAddress = myAddress;

      try {
        if (!initiateRef.current) {
          setIsLoadingGroups(true);
          pauseAllQueues();
        }
        const socketLink = `${getBaseApiReactSocket()}/websockets/chat/active/${currentAddress}?encoding=BASE64&haschatreference=false`;
        socketRef.current = new WebSocket(socketLink);

        socketRef.current.onopen = () => {
          setTimeout(pingHeads, 50); // Initial ping
        };

        socketRef.current.onmessage = (e) => {
          try {
            if (e.data === 'pong') {
              clearTimeout(timeoutIdRef.current);
              groupSocketTimeoutRef.current = setTimeout(pingHeads, 45000); // Ping every 45 seconds
            } else {
              if (!initiateRef.current) {
                setIsLoadingGroups(false);
                initiateRef.current = true;
                resumeAllQueues();
              }
              const data = JSON.parse(e.data);
              const copyGroups = [...(data?.groups || [])];
              const findIndex = copyGroups?.findIndex(
                (item) => item?.groupId === 0
              );
              if (findIndex !== -1) {
                copyGroups[findIndex] = {
                  ...(copyGroups[findIndex] || {}),
                  groupId: '0',
                };
              }
              const filteredGroups = copyGroups;
              const sortedGroups = filteredGroups.sort(
                (a, b) => (b.timestamp || 0) - (a.timestamp || 0)
              );
              const sortedDirects = (data?.direct || [])
                .filter(
                  (item) =>
                    item?.name !== 'extension-proxy' &&
                    item?.address !== 'QSMMGSgysEuqDCuLw3S4cHrQkBrh3vP3VH'
                )
                .sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));

              window
                .sendMessage('handleActiveGroupDataFromSocket', {
                  groups: sortedGroups,
                  directs: sortedDirects,
                })
                .catch((error) => {
                  // TODO translate
                  console.error(
                    'Failed to handle active group data from socket:',
                    error.message || 'An error occurred'
                  );
                });
            }
          } catch (error) {
            console.error('Error parsing onmessage data:', error);
          }
        };

        socketRef.current.onclose = (event) => {
          clearTimeout(groupSocketTimeoutRef.current);
          clearTimeout(timeoutIdRef.current);
          console.warn(`WebSocket closed: ${event.reason || 'unknown reason'}`);
          if (event.reason !== 'forced' && event.code !== 1000) {
            setTimeout(() => initWebsocketMessageGroup(), 10000); // Retry after 10 seconds
          }
        };

        socketRef.current.onerror = (error) => {
          console.error('WebSocket error:', error);
          clearTimeout(groupSocketTimeoutRef.current);
          clearTimeout(timeoutIdRef.current);
          if (socketRef.current) {
            socketRef.current.close();
          }
        };
      } catch (error) {
        console.error('Error initializing WebSocket:', error);
      }
    };

    initWebsocketMessageGroup(); // Initialize WebSocket on component mount

    return () => {
      forceCloseWebSocket(); // Clean up WebSocket on component unmount
    };
  }, [myAddress]);

  return null;
};
