import { useEffect, useState } from 'react';
import {
  fetchNotificationMessages,
  NOTIFICATION_MESSAGES_UPDATED_EVENT,
} from '../../notificationApi';
import {
  CHAT_CONVERSATIONS_UPDATED_EVENT,
  readChatConversationsUpdatedEvent,
} from '../data/chatClientEvents';
import { chatGateway } from '../data/chatGateway';

type UseUnreadCountsResult = {
  chatUnreadCount: number;
  notificationUnreadCount: number;
  refreshChatUnreadCount: () => Promise<void>;
  refreshNotificationUnreadCount: () => Promise<void>;
};

type SharedUnreadCountsState = {
  chatUnreadCount: number;
  notificationUnreadCount: number;
  hasLoaded: boolean;
  chatRequestPromise: Promise<void> | null;
  notificationRequestPromise: Promise<void> | null;
  subscribers: Set<() => void>;
};

const sharedUnreadCountsState: SharedUnreadCountsState = {
  chatUnreadCount: 0,
  notificationUnreadCount: 0,
  hasLoaded: false,
  chatRequestPromise: null,
  notificationRequestPromise: null,
  subscribers: new Set(),
};

function emitUnreadCounts() {
  sharedUnreadCountsState.subscribers.forEach((listener) => {
    listener();
  });
}

function subscribeUnreadCounts(listener: () => void) {
  sharedUnreadCountsState.subscribers.add(listener);

  return () => {
    sharedUnreadCountsState.subscribers.delete(listener);
  };
}

async function refreshChatUnreadCount() {
  if (sharedUnreadCountsState.chatRequestPromise) {
    return sharedUnreadCountsState.chatRequestPromise;
  }

  sharedUnreadCountsState.chatRequestPromise = (async () => {
    try {
      const items = await chatGateway.listConversations();
      sharedUnreadCountsState.chatUnreadCount = items.filter((item) => item.hasUnreadResponse).length;
    } catch {
      sharedUnreadCountsState.chatUnreadCount = 0;
    } finally {
      sharedUnreadCountsState.chatRequestPromise = null;
      emitUnreadCounts();
    }
  })();

  return sharedUnreadCountsState.chatRequestPromise;
}

async function refreshNotificationUnreadCount() {
  if (sharedUnreadCountsState.notificationRequestPromise) {
    return sharedUnreadCountsState.notificationRequestPromise;
  }

  sharedUnreadCountsState.notificationRequestPromise = (async () => {
    try {
      const response = await fetchNotificationMessages({ limit: 1 });
      sharedUnreadCountsState.notificationUnreadCount = response.unreadCount;
    } catch {
      // Keep the previous badge count when the server is temporarily unavailable.
    } finally {
      sharedUnreadCountsState.notificationRequestPromise = null;
      emitUnreadCounts();
    }
  })();

  return sharedUnreadCountsState.notificationRequestPromise;
}

export function useUnreadCounts(): UseUnreadCountsResult {
  const [chatUnreadCount, setChatUnreadCount] = useState(sharedUnreadCountsState.chatUnreadCount);
  const [notificationUnreadCount, setNotificationUnreadCount] = useState(sharedUnreadCountsState.notificationUnreadCount);

  useEffect(() => {
    return subscribeUnreadCounts(() => {
      setChatUnreadCount(sharedUnreadCountsState.chatUnreadCount);
      setNotificationUnreadCount(sharedUnreadCountsState.notificationUnreadCount);
    });
  }, []);

  useEffect(() => {
    if (sharedUnreadCountsState.hasLoaded) {
      return;
    }

    sharedUnreadCountsState.hasLoaded = true;
    void refreshChatUnreadCount();
    void refreshNotificationUnreadCount();
  }, []);

  useEffect(() => {
    const handleNotificationMessagesUpdated = () => {
      void refreshNotificationUnreadCount();
    };

    const handleChatConversationsUpdated = (event: Event) => {
      const detail = readChatConversationsUpdatedEvent(event);

      if (!detail) {
        return;
      }

      sharedUnreadCountsState.chatUnreadCount = detail.items.filter((item) => item.hasUnreadResponse).length;
      emitUnreadCounts();
    };

    window.addEventListener(NOTIFICATION_MESSAGES_UPDATED_EVENT, handleNotificationMessagesUpdated);
    window.addEventListener(CHAT_CONVERSATIONS_UPDATED_EVENT, handleChatConversationsUpdated as EventListener);

    return () => {
      window.removeEventListener(NOTIFICATION_MESSAGES_UPDATED_EVENT, handleNotificationMessagesUpdated);
      window.removeEventListener(CHAT_CONVERSATIONS_UPDATED_EVENT, handleChatConversationsUpdated as EventListener);
    };
  }, []);

  useEffect(() => {
    const refreshAllUnreadCounts = () => {
      void refreshChatUnreadCount();
      void refreshNotificationUnreadCount();
    };

    const handleVisibilityOrFocus = () => {
      if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {
        return;
      }

      refreshAllUnreadCounts();
    };

    window.addEventListener('focus', handleVisibilityOrFocus);
    window.addEventListener('online', handleVisibilityOrFocus);
    window.addEventListener('pageshow', handleVisibilityOrFocus);
    document.addEventListener('visibilitychange', handleVisibilityOrFocus);

    return () => {
      window.removeEventListener('focus', handleVisibilityOrFocus);
      window.removeEventListener('online', handleVisibilityOrFocus);
      window.removeEventListener('pageshow', handleVisibilityOrFocus);
      document.removeEventListener('visibilitychange', handleVisibilityOrFocus);
    };
  }, []);

  return {
    chatUnreadCount,
    notificationUnreadCount,
    refreshChatUnreadCount,
    refreshNotificationUnreadCount,
  };
}
