import { useMemo } from 'react';
import { useMutation } from 'react-query';

import { debounce } from 'lodash-es';

import { useSnackbar } from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/amplitude';
import { useAuth } from 'src/contexts/JWTContext';
import useFeatureFlag from 'src/hooks/useFeatureFlag';
import useGeneralError from 'src/hooks/useGeneralError';
import { CONVERSATION_TYPE } from 'src/pages/dashboard/Conversations/constants';
import { sendMessage } from 'src/pages/dashboard/Conversations/services';
import {
  type ParamsSendMessageApi,
  type SendMessageContext,
} from 'src/pages/dashboard/Conversations/types';
import {
  createMessage,
  formatDataAudio,
  getTypeMessage,
} from 'src/pages/dashboard/Conversations/utils';
import { EventName } from 'src/types/amplitude';
import { FeatureFlags } from 'src/types/featureFlags';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  useReplayMessageSetter,
  useReplyMessageValue,
} from '../contexts/ReplayMessageConversationContext';
import {
  addMessage,
  changePositionOfConversation,
  getChannelFromList,
  getConversationInfo,
  replaceMessage,
  resetUnreadMessages,
  updateLastRead,
  updateLatestMessageInCache,
  updateMarkedUnreadTs,
} from '../queries';

import {
  useEditConversationProperties,
  useMarkMessages,
  useUploadAudio,
} from './useConversationsQueries';
import { getMembers } from '../stores/membersStore';

type UseSendMessageType = {
  onScrollToBottom: () => void;
  reset: () => void;
  isGroupConversation: boolean;
};

export const useSendMessage = (globalParams: UseSendMessageType) => {
  const { onScrollToBottom, reset, isGroupConversation } = globalParams;

  const { t } = useLokaliseTranslation('chat');
  const isInternetConnected = navigator.onLine;
  const { user } = useAuth();
  const { clearReply } = useReplayMessageSetter();
  const { messageToReply } = useReplyMessageValue();
  const editConversationProperties = useEditConversationProperties();
  const { enqueueSnackbar } = useSnackbar();
  const callbackErrorUpdateConversation = () =>
    enqueueSnackbar({
      title: t('errors.update_conversations'),
      variant: 'error',
    });

  const showGeneralError = useGeneralError({
    showEnqueueSnackbar: isInternetConnected,
  });
  const { mutateAsync: uploadAudio, isLoading: isLoadingUploadAudio } =
    useUploadAudio();

  const markMessageMutation = useMarkMessages();
  const markReadOnPost = useFeatureFlag(
    FeatureFlags.CHATS_V2_MARK_READ_ON_POST,
  );
  const debouncedMarkAsRead = useMemo(
    () =>
      debounce(
        (channelId: string, ts?: string) =>
          markMessageMutation.mutate(
            { channelId, markedUnreadTs: ts },
            {
              onSuccess: (_, variables) => {
                if (variables.markedUnreadTs) {
                  updateMarkedUnreadTs(variables);
                }
              },
            },
          ),
        1000,
      ),
    [],
  );

  const openConversationMutation = useMutation(
    async (params: ParamsSendMessageApi) => {
      if (params.audio) {
        const audio = await uploadAudio(params.audio);
        const audioFormated = formatDataAudio(audio);
        params.attachments = [audioFormated];
      }
      return sendMessage(params);
    },
    {
      onMutate: values => {
        if (!user) return;
        const members = getMembers();
        const member = members[user?.id.toString()];
        const message = createMessage({
          ...values,
          messageToReply,
          user,
          pictureAssetUrl: member?.picture_asset_url,
        });
        addMessage({ id: values.channel, message, isSendMessage: true });
        if (messageToReply && clearReply) {
          clearReply();
        }
        if (markReadOnPost) {
          debouncedMarkAsRead(values.channel);
        }

        const conversation = getConversationInfo(values.channel);
        if (conversation) {
          const { properties } = conversation;
          if (properties.marked_unread_at) {
            editConversationProperties.mutate({
              channel: values.channel,
              properties: {
                notification_status: properties.notification_status,
                pinned_at: properties.pinned_at,
                marked_unread_at: undefined,
              },
            });
          }
        }
        reset();
        return {
          client_msg_id: message.client_msg_id,
          ts: values.ulid,
        } as SendMessageContext;
      },
      onSettled: () => {
        setTimeout(() => onScrollToBottom());
      },
      onError: (_error, context) => {
        if (!user || !context) return;
        showGeneralError(_error, t('errors.send_message'));
      },
      onSuccess: (response, values, context) => {
        if (!context) return;
        if (markReadOnPost) {
          debouncedMarkAsRead(
            values.channel,
            response.data.message.hu_data.message_ts,
          );
        }
        const { text, attachments } = values;
        const messageType = getTypeMessage(attachments, text);
        const eventProperties = {
          userId: response.data.message.user,
          conversationType: isGroupConversation
            ? CONVERSATION_TYPE.GROUP
            : CONVERSATION_TYPE.INDIVIDUAL,
          conversationID: values.channel,
          messageType,
        };
        logEvent(EventName.CHATS_2_MESSAGE_SENT, eventProperties);
        const conversationInfo = getConversationInfo(values.channel);
        const conversationList = getChannelFromList(values.channel);

        if (conversationList) {
          const { unread_count_display: unreadCountDisplayList } =
            conversationList;
          if (unreadCountDisplayList > 0) {
            resetUnreadMessages({ channelId: values.channel });
          }
        }

        if (conversationInfo && conversationInfo.unread_count_display === 0) {
          updateLastRead(
            values.channel,
            response.data.message.hu_data.message_ts,
          );
        }
        replaceMessage({
          channelId: values.channel,
          messageInternId: context.client_msg_id,
          newMessage: response.data.message,
        });
        updateLatestMessageInCache(values.channel, response.data.message);
        changePositionOfConversation({
          channelId: values.channel,
          message: response.data.message,
          callback: callbackErrorUpdateConversation,
          userId: user?.id,
        });
      },
    },
  );

  return {
    ...openConversationMutation,
    isLoading: openConversationMutation.isLoading || isLoadingUploadAudio,
  };
};
