import { useMemo, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useMutation, useQueryClient } from 'react-query';

import { type EmojiClickData } from 'emoji-picker-react';
import { useFileAssetUploader } from '@material-hu/hooks/FileAssetUploader/useFileAssetUploader';
import { type FileAsset } from '@material-hu/types/attachments';

import { logEvent } from 'src/config/logging';
import { useAuth } from 'src/contexts/JWTContext';
import { serviceManagementKeys } from 'src/pages/dashboard/serviceManagement/queries';
import { signedUploadWithOptions } from 'src/pages/dashboard/serviceManagement/utils';
import { sendComments } from 'src/pages/dashboard/serviceManagement/services';
import {
  ServiceManagementRole,
  type Task,
} from 'src/pages/dashboard/serviceManagement/types';
import { EventName } from 'src/types/amplitude';
import { FileTypes } from 'src/types/attachments';
import { getFileToPaste } from 'src/utils/attachments';
import { bytesToSize, sizeToBytes } from 'src/utils/bytes';
import { getFileNameExtension, isPdf } from 'src/utils/files';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { MAX_ATTACHMENTS, MAX_ATTACHMENTS_SIZE } from '../../../../constants';
import useSnackbar from '../../../../hooks/useSnackbar';

import { useAttachmentModal } from './AttachmentModal';
import {
  type AttachmentType,
  type CommentFormValues,
  getAttachmentType,
  getEmojiCategories,
} from './utils';

type UseCommentFormParams = {
  task: Task;
  isAgentWorkspace: boolean;
  onScrollToBottom: () => void;
};

export const useCommentForm = ({
  task,
  isAgentWorkspace,
  onScrollToBottom,
}: UseCommentFormParams) => {
  const { t } = useLokaliseTranslation(['service_management', 'general']);
  const queryClient = useQueryClient();
  const { showSnackbar } = useSnackbar();
  const { user } = useAuth();

  const inputRef = useRef<HTMLInputElement>(null);
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const [pickerOpen, setPickerOpen] = useState(false);
  const [pdfFileToPreview, setPdfFileToPreview] = useState<FileAsset | null>(
    null,
  );
  const [attachmentTypeToAdd, setAttachmentTypeToAdd] =
    useState<AttachmentType | null>(null);

  const form = useForm<CommentFormValues>({
    defaultValues: { message: '', images: [], files: [] },
  });
  const { handleSubmit, reset, watch, setValue, getValues } = form;
  const { images, files, message: watchedMessage } = watch();

  const currentAttachmentsLength = images.length + files.length;
  const currentAttachmentsSize = useMemo(() => {
    const imagesSize = images.reduce(
      (acc, image) => acc + sizeToBytes(image.size),
      0,
    );
    const filesSize = files.reduce(
      (acc, file) => acc + sizeToBytes(file.size),
      0,
    );
    return imagesSize + filesSize;
  }, [images, files]);

  const validAttachmentSize = (filesToValidate: File[]) => {
    const totalCount = filesToValidate.length + currentAttachmentsLength;
    if (totalCount > MAX_ATTACHMENTS) {
      showSnackbar({
        title: t('MAX_ATTACHMENTS_EXCEEDED', { count: MAX_ATTACHMENTS }),
        variant: 'warning',
      });
      return false;
    }
    const totalSize = filesToValidate.reduce(
      (acc, file) => acc + Number(file.size),
      currentAttachmentsSize,
    );
    if (totalSize > MAX_ATTACHMENTS_SIZE) {
      showSnackbar({
        title: t('MAX_ATTACHMENTS_SIZE_EXCEEDED', {
          size: bytesToSize(MAX_ATTACHMENTS_SIZE),
        }),
        variant: 'warning',
      });
      return false;
    }
    return true;
  };

  const { uploadFiles, loadingFiles } = useFileAssetUploader(
    signedUploadWithOptions,
    {
      onSuccess: newAttachments => {
        const type = getAttachmentType(newAttachments);
        const currentAttachmentsByType = getValues(type) as FileAsset[];
        setValue(type, [...currentAttachmentsByType, ...newAttachments]);
      },
      onError: () => {
        closeAttachmentModal();
        showSnackbar({ title: t('FILE_UPLOAD_FAILED'), variant: 'error' });
      },
    },
  );

  const getAttachmentValue = (type: FileAsset['type']) => {
    if (type === FileTypes.IMAGE)
      return { list: images, name: 'images' } as const;
    return { list: files, name: 'files' } as const;
  };

  const handleDeleteAttachment = (attachment: FileAsset, index: number) => {
    const { name, list } = getAttachmentValue(attachment.type);
    const newList = [...list];
    newList.splice(index, 1);
    setValue(name, newList);
  };

  const resetAttachments = () => {
    setValue('images', []);
    setValue('files', []);
  };

  const { openAttachmentModal, closeAttachmentModal } = useAttachmentModal({
    type: attachmentTypeToAdd || 'files',
    images,
    files,
    loadingFiles,
    onDelete: handleDeleteAttachment,
    onAccept: () => setAnchorEl(null),
    onAddMore: (newFiles: File[]) => {
      if (validAttachmentSize(newFiles)) uploadFiles(newFiles);
    },
    addMoreDisabled: false,
    onCancel: resetAttachments,
  });

  const handleOpenAttachmentMenu = (
    event: React.MouseEvent<HTMLButtonElement>,
  ) => {
    setAnchorEl(event.currentTarget);
  };

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

  const handleAddImages = (imagesToAdd: File[]) => {
    if (!validAttachmentSize(imagesToAdd)) return;
    handleCloseAttachmentMenu();
    openAttachmentModal();
    uploadFiles(imagesToAdd);
  };

  const handleAddFiles = (filesToAdd: File[]) => {
    if (!validAttachmentSize(filesToAdd)) return;
    handleCloseAttachmentMenu();
    openAttachmentModal();
    uploadFiles(filesToAdd);
  };

  const handleRemoveAttachment = (index: number, type: AttachmentType) => {
    const currentAttachments = getValues(type) as FileAsset[];
    const newAttachments = [...currentAttachments];
    newAttachments.splice(index, 1);
    setValue(type, newAttachments);
  };

  const handleOpenFilePreview = (file: FileAsset) => {
    if (isPdf(getFileNameExtension(file.name))) {
      setPdfFileToPreview(file);
    } else {
      window.open(file.url, '_blank', 'noopener,noreferrer');
    }
  };

  const handleSelectEmoji = (emojiObject: EmojiClickData) => {
    const currentMessage = getValues('message') || '';
    setValue('message', `${currentMessage}${emojiObject.emoji}`);
    if (inputRef.current) inputRef.current.focus();
  };

  const handlePaste = async (event: React.ClipboardEvent<HTMLInputElement>) => {
    if (event.clipboardData?.items) {
      const items = Array.from(event.clipboardData.items);
      if (items.some((item: DataTransferItem) => item.kind === 'file')) {
        event.preventDefault();
        const newFile = await getFileToPaste(event);
        if (newFile?.fileObject) {
          if (newFile.type === FileTypes.IMAGE)
            handleAddImages([newFile.fileObject]);
          else handleAddFiles([newFile.fileObject]);
        }
      }
    }
  };

  const isAgent = task?.assignee?.id === user?.id;

  const mutation = useMutation(
    (formData: CommentFormValues) => sendComments(task.id, formData),
    {
      onSuccess: async () => {
        reset({ message: '', images: [], files: [] });
        await queryClient.invalidateQueries(
          serviceManagementKeys.comments.list(task.id),
        );
        requestAnimationFrame(() => {
          setTimeout(() => {
            inputRef.current?.focus();
            onScrollToBottom();
          }, 0);
        });
        logEvent(EventName.SERVICE_MGMT_COMMENT_SENT, {
          role: isAgentWorkspace
            ? ServiceManagementRole.AGENT
            : ServiceManagementRole.INITIATOR,
          serviceId: task.catalogItem?.id,
          serviceName: task.catalogItem?.name,
          requestId: task.id,
          approver_role: isAgent
            ? ServiceManagementRole.AGENT
            : ServiceManagementRole.APPROVER,
        });
      },
    },
  );

  const submit = (data: CommentFormValues) => {
    if (!data || (!data.message && !data.images.length && !data.files.length))
      return;
    if (data.message) data.message = data.message.replace(/\n+$/, '');
    if (pickerOpen) setPickerOpen(false);
    mutation.mutate(data);
  };

  const emojiCategories = useMemo(() => getEmojiCategories(t), [t]);
  const showCommentAttachments =
    images?.length > 0 || files?.length > 0 || loadingFiles?.length > 0;
  const isSendDisabled =
    mutation.isLoading ||
    (!watchedMessage.trim() && !images.length && !files.length);

  return {
    form,
    inputRef,
    anchorEl,
    open: Boolean(anchorEl),
    pickerOpen,
    setPickerOpen,
    pdfFileToPreview,
    setPdfFileToPreview,
    attachmentTypeToAdd,
    setAttachmentTypeToAdd,
    images,
    files,
    loadingFiles,
    watchedMessage,
    mutation,
    emojiCategories,
    showCommentAttachments,
    isSendDisabled,
    handleOpenAttachmentMenu,
    handleCloseAttachmentMenu,
    handleAddImages,
    handleAddFiles,
    handleRemoveAttachment,
    handleOpenFilePreview,
    handleSelectEmoji,
    handlePaste,
    handleSubmit,
    submit,
  };
};
