import { type FC, useEffect, useRef, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useParams, useSearchParams } from 'react-router-dom';

import { type IGif } from '@giphy/js-types';
import { ulid } from 'ulid';
import {
  IconChevronDown,
  IconMicrophone,
  IconSend,
} from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';

import HuBadge from '@material-hu/components/design-system/Badge';
import useHuSnackbar 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 {
  CONVERSATIONS_THREAD_FOOTER_ID,
  MAX_MEDIA_SIZE_MB,
  MEDIA_ORIGIN,
  MESSAGE_TYPE,
} from 'src/pages/dashboard/Conversations/constants';
import useAudioRecorder from 'src/pages/dashboard/Conversations/hooks/useAudioRecorder';
import {
  type Channel,
  Format,
  type Member,
} from 'src/pages/dashboard/Conversations/types';
import {
  formateDataGif,
  getDefaultMessage,
  getEnabledSendAudio,
  getOtherUserStatus,
  getTypeMessageFromFiles,
} from 'src/pages/dashboard/Conversations/utils';
import { EventName } from 'src/types/amplitude';
import { FileTypes } from 'src/types/attachments';
import { FeatureFlags } from 'src/types/featureFlags';
import {
  getFilesToPaste,
  isValidFilesSizeChatsV2,
} from 'src/utils/attachments';
import { bytesFrom } from 'src/utils/bytes';
import {
  buildConversationDraftKey,
  clearComposerDraft,
  readComposerDraft,
} from 'src/utils/composerDrafts';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useReplyMessageValue } from '../../../contexts/ReplayMessageConversationContext';
import { useSearchHighlight } from '../../../contexts/SearchHighlightContext';
import { useSendAttachments } from '../../../contexts/SendAttachmentsContext';
import { useSendMessage } from '../../../hooks/useSendMessage';
import useSnackbarPosition from '../../../hooks/useSnackbarPosition';

import AudioRecorder from './AudioRecorder';
import DisabledInput from './DisabledInput';
import InputEditor from './InputEditor';
import SendMediaMenu from './SendMediaMenu';
import ShowAttachmentSelected from './ShowAttachmentSelected';
import ShowMessageToReplay from './ShowReplyToReplay';

type ConversationsThreadFooterProps = {
  onScrollToBottom: () => void;
  isNetworkOnline: boolean;
  conversation: Channel;
  isGroupConversation: boolean;
  inViewMessagesEnd: boolean;
  members: Member[];
};

export const MAX_FILES_ATTACHMENTS = 10;

const ConversationsThreadFooter: FC<ConversationsThreadFooterProps> = props => {
  const {
    onScrollToBottom,
    isNetworkOnline,
    conversation,
    isGroupConversation,
    inViewMessagesEnd,
    members,
  } = props;

  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);

  const { id = '' } = useParams();
  const [searchParams] = useSearchParams();
  const { t } = useLokaliseTranslation(['chat', 'general']);

  const defaultMessage = getDefaultMessage(searchParams);
  const { enqueueSnackbar } = useHuSnackbar();
  const showGeneralError = useGeneralError();
  const footerRef = useRef<HTMLDivElement | null>(null);
  useSnackbarPosition({ ref: footerRef });

  const {
    uploadFiles,
    isLoadingUpload,
    uploadGif,
    isLoadingUploadGif,
    updateAttachments,
    attachments,
    cancelUpload,
  } = useSendAttachments();

  const { isDeleted, isInactive } = getOtherUserStatus({
    isGroupConversation,
    conversation,
  });
  const { instance, user } = useAuth();
  const allowAttachmentsInChats = !!instance?.allowAttachmentsInChats;

  const draftKey =
    user && id
      ? buildConversationDraftKey({ userId: user.id, conversationId: id })
      : null;
  const blockSendFiles = useFeatureFlag(FeatureFlags.BLOCK_FILES_CHATS_V2);
  const maxMediaSize =
    useFeatureFlag<number>(FeatureFlags.CHATS_V2_MAX_MEDIA_SIZE_MB) ??
    MAX_MEDIA_SIZE_MB;

  const {
    audioUrl,
    isIdle: isIdleAudio,
    isRecording,
    startRecording,
    pauseRecording,
    resumeRecording,
    stopRecording,
  } = useAudioRecorder();

  const { messageToReply } = useReplyMessageValue();
  const { closeSearch } = useSearchHighlight();

  const form = useForm({
    defaultValues: {
      body:
        defaultMessage ||
        (draftKey
          ? readComposerDraft(draftKey, { ttlMs: Number.POSITIVE_INFINITY })
          : ''),
    },
    mode: 'onChange',
  });

  const {
    handleSubmit,
    formState: { isSubmitting },
    reset,
    watch,
  } = form;

  const body = watch('body');

  const { mutateAsync: sendMessageMutation, isLoading: isLoadingSendMessage } =
    useSendMessage({
      onScrollToBottom,
      reset,
      isGroupConversation,
    });

  const handleAddGif = async (gif: IGif) => {
    if (!isNetworkOnline) {
      return;
    }

    try {
      const uploadedGif = await uploadGif(gif);
      const gifBody = formateDataGif(uploadedGif);
      closeSearch();
      await sendMessageMutation({
        text: '',
        attachments: [gifBody],
        channel: id,
        ulid: ulid(),
        reply_ts: messageToReply?.hu_data?.message_ts,
      });
    } catch (error) {
      showGeneralError(error, t('chat:errors.upload_files'));
    }
  };

  const handleChangeFiles = async (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    handleOnCloseMenu();
    const files = event.target.files;
    if (!files || files.length + attachments.length > MAX_FILES_ATTACHMENTS) {
      enqueueSnackbar({
        title: t('chat:files.limit_count_files', {
          count: MAX_FILES_ATTACHMENTS,
        }),
        variant: 'error',
      });
      return;
    }

    const isValidSendFiles = isValidFilesSizeChatsV2(
      [...attachments, ...files],
      bytesFrom(maxMediaSize, 'MB'),
    );

    if (!isValidSendFiles) {
      enqueueSnackbar({
        title: t('chat:files.max_limit_files', {
          max: `${maxMediaSize}MB`,
        }),
        variant: 'error',
      });
      return;
    }

    const filesArray = Array.from(files);
    uploadFiles(filesArray, Format.FILE);

    logEvent(EventName.CHATS_2_MESSAGE_MEDIA_ATTACHED, {
      conversationId: id,
      mediaQuantity: files.length,
      mediaOrigin: MEDIA_ORIGIN.FILE_EXPLORER,
      mediaType: MESSAGE_TYPE.FILE,
    });
  };

  const handleChangeImagesVideos = async (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    handleOnCloseMenu();
    const files = event.target.files;

    if (!files || files.length + attachments.length > MAX_FILES_ATTACHMENTS) {
      enqueueSnackbar({
        title: t('chat:files.limit_count_files', {
          count: MAX_FILES_ATTACHMENTS,
        }),
        variant: 'error',
      });
      return;
    }

    const isValidSendFiles = isValidFilesSizeChatsV2(
      [...attachments, ...files],
      bytesFrom(maxMediaSize, 'MB'),
    );

    if (!isValidSendFiles) {
      enqueueSnackbar({
        title: t('chat:files.max_limit_files', {
          max: `${maxMediaSize}MB`,
        }),
        variant: 'error',
      });
      return;
    }

    const images = Array.from(files).filter(file =>
      file.type.includes(Format.IMAGE),
    );

    const videos = Array.from(files).filter(file =>
      file.type.includes(Format.VIDEO),
    );

    let mediaType;

    if (images.length > 0) {
      mediaType = MESSAGE_TYPE.IMAGE;
      uploadFiles(images, Format.IMAGE);
    }

    if (videos.length > 0) {
      mediaType =
        images.length > 0 ? MESSAGE_TYPE.IMAGES_AND_VIDEO : MESSAGE_TYPE.VIDEO;
      uploadFiles(videos, Format.VIDEO);
    }

    logEvent(EventName.CHATS_2_MESSAGE_MEDIA_ATTACHED, {
      conversationId: id,
      mediaQuantity: images.length + videos.length,
      mediaOrigin: MEDIA_ORIGIN.GALLERY,
      mediaType,
    });
  };

  const handlePaste = async (event: ClipboardEvent) => {
    if (!isNetworkOnline) {
      return;
    }

    try {
      const files = await getFilesToPaste(event);
      if (!files || !files.length) {
        return;
      }

      if (attachments.length + files.length > MAX_FILES_ATTACHMENTS) {
        enqueueSnackbar({
          title: t('chat:files.limit_count_files', {
            count: MAX_FILES_ATTACHMENTS,
          }),
          variant: 'error',
        });
        return;
      }

      const isValidSendFiles = isValidFilesSizeChatsV2(
        [...attachments, ...files],
        bytesFrom(maxMediaSize, 'MB'),
      );

      if (!isValidSendFiles) {
        enqueueSnackbar({
          title: t('chat:files.max_limit_files', {
            max: `${maxMediaSize}MB`,
          }),
          variant: 'error',
        });
        handleOnCloseMenu();
        return;
      }
      const images = files.filter(file => file.type === FileTypes.IMAGE);
      const videos = files.filter(file => file.type === FileTypes.VIDEO);
      const otherFiles = files.filter(file => file.type === FileTypes.FILE);

      if (images.length > 0) {
        const imageFiles = images.map(file => file.fileObject as File);
        uploadFiles(imageFiles, Format.IMAGE);
      }

      if (videos.length > 0) {
        const videoFiles = videos.map(file => file.fileObject as File);
        uploadFiles(videoFiles, Format.VIDEO);
      }

      if (otherFiles.length > 0) {
        if (blockSendFiles) {
          enqueueSnackbar({
            title: t('chat:files.block_send_files'),
            variant: 'error',
          });
          return;
        }
        const otherFilesList = otherFiles.map(file => file.fileObject as File);
        uploadFiles(otherFilesList, Format.FILE);
      }

      logEvent(EventName.CHATS_2_MESSAGE_MEDIA_ATTACHED, {
        conversationId: id,
        mediaQuantity: files.length,
        mediaOrigin: MEDIA_ORIGIN.PASTE,
        mediaType: getTypeMessageFromFiles(files),
      });
    } catch (error) {
      enqueueSnackbar({
        title: t('chat:errors.upload_files'),
        variant: 'error',
      });
    }
  };

  const handleSendMessage = async (values: any) => {
    const cleanedBody = values.body ? values.body.trim() : '';

    if (!cleanedBody && !attachments.length && !values.audio) {
      return;
    }

    const isValidSendFiles = isValidFilesSizeChatsV2(
      attachments,
      bytesFrom(maxMediaSize, 'MB'),
    );

    if (!isValidSendFiles) {
      enqueueSnackbar({
        title: t('chat:files.max_limit_files', {
          max: `${maxMediaSize}MB`,
        }),
        variant: 'error',
      });
      handleOnCloseMenu();
      return;
    }

    const mediaToSend = attachments.filter(
      file =>
        file.metadata.format === FileTypes.IMAGE.toLowerCase() ||
        file.metadata.format === FileTypes.VIDEO.toLowerCase(),
    );
    const files = attachments.filter(
      file => file.metadata.format === FileTypes.FILE.toLowerCase(),
    );
    closeSearch();
    if (mediaToSend.length > 0) {
      await sendMessageMutation({
        text: cleanedBody,
        attachments: mediaToSend,
        channel: id,
        ulid: ulid(),
        reply_ts: messageToReply?.hu_data?.message_ts,
      });
      if (files.length > 0) {
        await Promise.all(
          files.map(file =>
            sendMessageMutation({
              attachments: [file],
              channel: id,
              ulid: ulid(),
            }),
          ),
        );
      }
    } else {
      if (files.length > 0) {
        await Promise.all(
          files.map((file, index) =>
            sendMessageMutation({
              ...(index === 0 && {
                text: cleanedBody,
                reply_ts: messageToReply?.hu_data?.message_ts,
              }),
              attachments: [file],
              channel: id,
              ulid: ulid(),
            }),
          ),
        );
      } else {
        await sendMessageMutation({
          text: cleanedBody,
          reply_ts: messageToReply?.hu_data?.message_ts,
          channel: id,
          ulid: ulid(),
          attachments: [],
        });
      }
    }
    if (draftKey) {
      clearComposerDraft(draftKey);
    }

    if (attachments.length > 0) {
      updateAttachments();
    }
  };

  const handleOnCloseMenu = () => setAnchorEl(null);

  const handleOnOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) =>
    setAnchorEl(event.currentTarget);

  const handleFormSubmit = (e: React.FormEvent) => {
    // only necessary to prevent the submission when the message is being sent
    e.preventDefault();
    if (isLoading || isSubmitting) {
      return;
    }

    handleSubmit(handleSendMessage)(e);
  };

  const handleSendAudioMessage = (duration: number) => {
    handleSubmit(async () => {
      const audioBlob = await stopRecording();

      await sendMessageMutation({
        channel: id,
        reply_ts: messageToReply?.hu_data?.message_ts,
        text: '',
        ulid: ulid(),
        audio: {
          blob: audioBlob,
          duration: duration.toString(),
        },
      });
      closeSearch();
    })();
  };

  const open = Boolean(anchorEl);
  const hasFiles = !!attachments.length;
  const isLoading =
    isLoadingSendMessage || isLoadingUpload || isLoadingUploadGif;

  const isEnabledSendAudio = getEnabledSendAudio(hasFiles, body);

  if (isInactive || isDeleted) return <DisabledInput isDeleted={isDeleted} />;

  return (
    <FormProvider {...form}>
      <form
        onSubmit={handleFormSubmit}
        style={{ width: '100%' }}
      >
        <Stack
          id={CONVERSATIONS_THREAD_FOOTER_ID}
          ref={footerRef}
          sx={{
            position: 'relative',
            p: 2,
            backgroundColor: theme =>
              theme.palette.new.background.layout.tertiary,
          }}
        >
          {!inViewMessagesEnd && (
            <IconButton
              variant="secondary"
              sx={{
                position: 'absolute',
                width: '42px',
                height: '42px',
                right: '22px',
                zIndex: '200',
                transform: 'translateY(-80px)',
                borderRadius: '50%',
                alignItems: 'center',
                justifyContent: 'center',
                backgroundColor: theme =>
                  theme.palette.new.background.layout.default,
                opacity: '1',
                '&.MuiButtonBase-root:hover': {
                  bgcolor: theme => theme.palette.new.background.layout.default,
                },
              }}
              onClick={onScrollToBottom}
            >
              <IconChevronDown />
            </IconButton>
          )}
          {hasFiles && !isLoadingSendMessage && (
            <ShowAttachmentSelected
              isLoadingFiles={isLoading}
              attachments={attachments}
              updateAttachments={updateAttachments}
              cancelUpload={cancelUpload}
              body={body}
            />
          )}
          {messageToReply && (
            <ShowMessageToReplay messageToReply={messageToReply} />
          )}
          <Stack
            sx={{
              flexDirection: 'row',
              alignItems: 'flex-end',
              justifyContent: 'center',
              gap: 2,
              pt: messageToReply ? 2 : 0,
            }}
          >
            {!isIdleAudio && (
              <AudioRecorder
                audioUrl={audioUrl}
                isRecording={isRecording}
                onDelete={stopRecording}
                onPause={pauseRecording}
                onResume={resumeRecording}
                onSendMessage={handleSendAudioMessage}
              />
            )}
            {isIdleAudio && (
              <>
                {allowAttachmentsInChats && (
                  <SendMediaMenu
                    open={open}
                    disabled={isLoading}
                    anchorEl={anchorEl}
                    onOpen={handleOnOpenMenu}
                    onClose={handleOnCloseMenu}
                    onChangeImagesVideos={handleChangeImagesVideos}
                    onChangeFiles={handleChangeFiles}
                  />
                )}

                <InputEditor
                  name="body"
                  content={body}
                  disabled={isSubmitting}
                  handleAddGif={handleAddGif}
                  members={members}
                  handlePaste={handlePaste}
                  isGroupConversation={isGroupConversation}
                  persistDraft
                />
                <HuBadge
                  badgeContent={attachments.length}
                  color="primary"
                >
                  {!isEnabledSendAudio && (
                    <IconButton
                      type="submit"
                      variant="primary"
                      sx={{
                        height: '40px',
                        width: '40px',
                      }}
                      disabled={
                        isSubmitting ||
                        isLoading ||
                        (!body.trim() && !hasFiles) ||
                        !isNetworkOnline
                      }
                    >
                      <IconSend />
                    </IconButton>
                  )}
                  {isEnabledSendAudio && (
                    <IconButton
                      disabled={isSubmitting || isLoading}
                      onClick={startRecording}
                      variant="tertiary"
                      sx={{
                        height: '40px',
                        width: '40px',
                      }}
                    >
                      <IconMicrophone />
                    </IconButton>
                  )}
                </HuBadge>
              </>
            )}
          </Stack>
        </Stack>
      </form>
    </FormProvider>
  );
};

export default ConversationsThreadFooter;
