import { useCallback } from 'react';
import { useQueryClient } from 'react-query';
import { useLocation, useParams, matchPath } from 'react-router-dom';

import { useAuth } from 'src/contexts/JWTContext';
import useUnreadChats from 'src/hooks/useUnreadChats';
import {
  setTicketListData,
  moveFirstTicketListData,
  clearTicketNotifications,
  isTicket,
  ticketKeys,
  ticketInFirstPage,
} from 'src/pages/dashboard/tickets/queries';
import { ticketSkeletonRoutes } from 'src/pages/dashboard/tickets/routes';
import { clearChatNotifications as clearChatNotificationsService } from 'src/services/chats';
import { MessageStatus, ChatListItem, ChatType } from 'src/types/chats';
import { FormType } from 'src/types/forms';
import { isChatCreator } from 'src/utils/chats';

import {
  chatKeys,
  clearUnreadMessages,
  clearArchiveUnreadMessages,
  setChatListData,
  setChatDetailData,
  setChatArchiveListData,
  chatInFirstPage,
  moveFirstChatListData,
  refetchListChats,
  addChatNotification,
  removeChatNotification,
  clearChatNotifications,
  isChat,
} from 'src/components/dashboard/chat/queries';
import { chatSkeletonRoutes } from 'src/components/dashboard/chat/routes';
import {
  removeFormChatNotification,
  removeFormRequestNotification,
  updateFormsNotifications,
  isFormChat,
} from 'src/components/dashboard/form/queries';
import { formSkeletonRoutes } from 'src/components/dashboard/form/routes';

const PATH_CHAT = chatSkeletonRoutes.chats();
const PATH_FORM_CHAT = formSkeletonRoutes.form.chat(FormType.FORM);
const PATH_FORM_REQUEST = formSkeletonRoutes.requests.detail(FormType.FORM);
const PATH_TICKET_REQUEST = ticketSkeletonRoutes.tickets();

const useChat = () => {
  const { user } = useAuth();
  const location = useLocation();
  const unread = useUnreadChats();
  const queryClient = useQueryClient();
  const { id } = useParams();
  const currentChatId = Number(id);
  const currentLocation = window.location.pathname.split('/')[1];

  const exactChatMatch = !!matchPath(
    {
      path: PATH_CHAT,
      end: false,
    },
    location.pathname,
  );

  const exactFormChatMatch = !!matchPath(
    {
      path: PATH_FORM_CHAT,
      end: false,
    },
    location.pathname,
  );

  const exactFormRequestMatch = !!matchPath(
    {
      path: PATH_FORM_REQUEST,
      end: false,
    },
    location.pathname,
  );

  const exactTicketsRequestMatch = !!matchPath(
    {
      path: PATH_TICKET_REQUEST,
      end: false,
    },
    location.pathname,
  );

  const editMessage = useCallback((messageItem: any) => {
    if (messageItem) {
      setChatListData(messageItem.chatId, chatItem => {
        if (messageItem.id === chatItem.chat.lastMessage.id) {
          chatItem.chat.lastMessage.status = messageItem.status;
          chatItem.chat.lastMessage.text =
            messageItem.status === MessageStatus.DELETED
              ? ''
              : messageItem.text;
        }

        return chatItem;
      });
    }
  }, []);

  const markAsUnread = useCallback((messageItem: { chatId: number }) => {
    if (messageItem) {
      setChatListData(messageItem.chatId, chatItem => {
        if (messageItem.chatId === chatItem.chatId) {
          addChatNotification();
          chatItem.chat.markedAsUnread = true;
        }

        return chatItem;
      });
    }
  }, []);

  const clearUnreadChats = useCallback(async () => {
    if (
      !exactChatMatch &&
      !exactFormChatMatch &&
      !exactFormRequestMatch &&
      !exactTicketsRequestMatch &&
      !unread.has(currentChatId)
    )
      return;

    if (exactChatMatch) {
      removeChatNotification();
    } else if (exactFormChatMatch) {
      removeFormChatNotification();
    } else {
      removeFormRequestNotification();
    }

    unread.delete(currentChatId);

    const markAsRead = (oldData: any) => {
      if (!oldData) return;
      oldData.chat.markedAsUnread = false;
      return oldData;
    };

    setChatDetailData(Number(currentChatId), markAsRead);
    clearUnreadMessages(currentChatId);
    clearArchiveUnreadMessages(currentChatId);

    try {
      await clearChatNotificationsService(currentChatId);
    } catch (err) {
      console.error(err);
    }
  }, [currentChatId, exactChatMatch, unread]);

  const updateChatNotifications = useCallback(
    (updateId: number) => {
      if (unread.has(updateId)) {
        if (isChat(updateId)) {
          clearChatNotifications(updateId);
        } else if (isTicket(updateId)) {
          clearTicketNotifications(updateId, user.id);
        } else if (isFormChat(updateId)) {
          updateFormsNotifications();
        }
        unread.delete(updateId);
      }
    },
    [unread],
  );

  const updateGroupChatTitleChat = useCallback(chatUpdateItem => {
    const chatId = chatUpdateItem?.message?.chatId;
    const archived = chatUpdateItem?.message?.archived;

    const titleUpdater = (oldData: any) => {
      if (!oldData) return;
      oldData.title = chatUpdateItem?.title;
      return oldData;
    };

    if (archived) setChatArchiveListData(Number(chatId), titleUpdater);
    else setChatListData(Number(chatId), titleUpdater);

    setChatDetailData(Number(chatId), titleUpdater);

    queryClient.invalidateQueries(chatKeys.messages.list(chatId));
    queryClient.invalidateQueries(chatKeys.list());
    queryClient.invalidateQueries(chatKeys.detail(chatId));
  }, []);

  const updateGroupChatPictureChat = useCallback(chatUpdateItem => {
    const chatId = chatUpdateItem?.message?.chatId;
    const archived = chatUpdateItem?.message?.archived;

    const pictureUpdater = (oldData: any) => {
      if (!oldData) return;
      oldData.pictureUrl = chatUpdateItem?.pictureUrl;
      return oldData;
    };

    if (archived) setChatArchiveListData(Number(chatId), pictureUpdater);
    else setChatListData(Number(chatId), pictureUpdater);

    setChatDetailData(Number(chatId), pictureUpdater);

    queryClient.invalidateQueries(chatKeys.messages.list(chatId));
    queryClient.invalidateQueries(chatKeys.list());
    queryClient.invalidateQueries(chatKeys.detail(chatId));
  }, []);

  const updateStatus = useCallback(chatUpdateItem => {
    let chatId;
    if (chatUpdateItem?.message) {
      chatId = chatUpdateItem?.message?.chatId;
    } else {
      chatId = chatUpdateItem?.chatId;
    }
    queryClient.invalidateQueries(chatKeys.messages.list(chatId));
    queryClient.invalidateQueries(chatKeys.list());
    queryClient.invalidateQueries(chatKeys.archivedChats.list());
    queryClient.invalidateQueries(chatKeys.notifications.module());
    queryClient.invalidateQueries(chatKeys.participants(chatId));
    queryClient.invalidateQueries(chatKeys.detail(chatId));
  }, []);

  const addMessage = useCallback(
    (chatListItem: any) => {
      const chatId = chatListItem?.chat?.id;
      const messageUserId = chatListItem?.chat?.lastMessage?.userId;

      if (!chatId) return;

      let queryKey = null;
      if (chatListItem.status === 'UNASSIGNED') {
        queryKey = ticketKeys.list.unassigned();
      } else if (chatListItem.status === 'ASSIGNED') {
        queryKey = ticketKeys.list.assigned();
      } else if (chatListItem.status === 'CLOSED') {
        queryKey = ticketKeys.list.closed();
      }
      if (
        ticketInFirstPage(chatId, queryKey) &&
        currentLocation === 'tickets'
      ) {
        setTicketListData(chatId, queryKey, ticketItem => {
          ticketItem.chat.lastMessage = chatListItem.chat.lastMessage;
          ticketItem.chat.messageUpdatedAt =
            chatListItem.chat.lastMessage.createdAt;
          if (chatId !== currentChatId && messageUserId !== user.id) {
            ticketItem.chat.unreadMessages++;
            queryClient.invalidateQueries(
              chatKeys.ticketAgentStats.detail(user.id),
            );
          } else if (chatId === currentChatId && messageUserId !== user.id) {
            ticketItem.chat.unreadMessages = 0;
            clearChatNotificationsService(chatId);
          }

          return ticketItem;
        });
        moveFirstTicketListData(chatId, queryKey);
      } else if (currentLocation === 'tickets') {
        queryClient.invalidateQueries(queryKey);
        queryClient.invalidateQueries(
          chatKeys.ticketAgentStats.detail(user.id),
        );
      } else if (chatId === currentChatId && messageUserId !== user.id) {
        clearChatNotificationsService(chatId);
      }

      if (chatInFirstPage(chatId) && currentLocation === 'chats') {
        if (
          chatId !== currentChatId &&
          messageUserId !== user.id &&
          chatListItem.status !== 'UNASSIGNED' &&
          !unread.has(chatId)
        ) {
          addChatNotification();
        } else if (chatId === currentChatId && messageUserId !== user.id) {
          clearChatNotificationsService(chatId);
        }

        setChatListData(chatId, chatItem => {
          chatItem.chat.lastMessage = chatListItem.chat.lastMessage;
          chatItem.chat.messageUpdatedAt =
            chatListItem.chat.lastMessage.createdAt;
          if (chatId !== currentChatId && messageUserId !== user.id) {
            chatItem.chat.unreadMessages++;
          }
          if (chatItem.chatType === ChatType.TICKET) {
            chatItem.chat.otherUser = chatListItem.chat.otherUser;
            chatItem.responsibleId = chatListItem.responsibleId;
            chatItem.status = chatListItem.status;
            queryClient.invalidateQueries(chatKeys.participants(chatId));
          }

          return chatItem;
        });
        moveFirstChatListData(chatId);
      } else {
        refetchListChats();
      }

      if (chatId !== currentChatId) {
        queryClient.invalidateQueries(chatKeys.notifications.module());
      }
    },
    [currentChatId, exactChatMatch, unread, user.id],
  );

  const addUnreadChat = useCallback(
    (chatListItem: ChatListItem) => {
      const chatId = chatListItem?.chat?.id;

      if (!chatId || isChatCreator(chatListItem, user.id)) return;

      addChatNotification();
    },
    [user.id],
  );

  return {
    clearUnreadChats,
    updateChatNotifications,
    addUnreadChat,
    addMessage,
    editMessage,
    markAsUnread,
    updateStatus,
    updateGroupChatPictureChat,
    updateGroupChatTitleChat,
  };
};

export default useChat;
