import {
  createContext,
  type FC,
  type PropsWithChildren,
  useContext,
  useEffect,
  useState,
} from 'react';

import { type IGif } from '@giphy/js-types';
import { useFileAssetUploader } from '@material-hu/hooks/FileAssetUploader/useFileAssetUploader';

import useGeneralError from 'src/hooks/useGeneralError';
import { useUploadGif } from 'src/pages/dashboard/Conversations/hooks/useConversationsQueries';
import { uploadConversationFile } from 'src/pages/dashboard/Conversations/services';
import {
  type Format,
  type PreviewFileItem,
  type SendFileItem,
  type UploadGifBody,
} from 'src/pages/dashboard/Conversations/types';
import {
  formatCompletedItem,
  isImageAttachment,
  isVideoAttachment,
  makePreviewItem,
} from 'src/pages/dashboard/Conversations/utils';
import { useLokaliseTranslation } from 'src/utils/i18n';

export type SendAttachmentsContextValue = {
  uploadFiles: (files: File[], forceFormat: Format) => void;
  isLoadingUpload: boolean;
  uploadGif: (gif: IGif) => Promise<UploadGifBody>;
  isLoadingUploadGif: boolean;
  updateAttachments: (array?: SendFileItem[]) => void;
  attachments: SendFileItem[];
  cancelUpload: (attachment: SendFileItem) => void;
};

const SendAttachmentsContext = createContext<SendAttachmentsContextValue>({
  uploadFiles: () => null,
  isLoadingUpload: false,
  uploadGif: async (_gif: IGif) => ({}) as UploadGifBody,
  isLoadingUploadGif: false,
  updateAttachments: () => null,
  attachments: [],
  cancelUpload: () => null,
});

export const SendAttachmentsProvider: FC<PropsWithChildren> = props => {
  const { children } = props;

  const { t } = useLokaliseTranslation(['chat', 'general']);
  const showGeneralError = useGeneralError();

  const [attachments, setAttachments] = useState<SendFileItem[]>([]);

  const {
    uploadFiles: hookUploadFiles,
    stopUpload,
    isLoading: isLoadingUpload,
    fileStates,
    reset: resetHook,
  } = useFileAssetUploader(uploadConversationFile, {
    onError: error => showGeneralError(error, t('chat:errors.upload_files')),
  });

  const { mutateAsync: uploadGif, isLoading: isLoadingUploadGif } =
    useUploadGif();

  useEffect(() => {
    setAttachments(currentAttachments => {
      let updatedAttachments = [...currentAttachments];

      for (const [fileId, fileState] of Object.entries(fileStates)) {
        const attachmentIndex = updatedAttachments.findIndex(
          attachment => String(attachment.id) === fileId,
        );
        if (attachmentIndex === -1) continue;

        if (
          fileState.status === 'success' &&
          fileState.result &&
          updatedAttachments[attachmentIndex].isLoading
        ) {
          const preview = updatedAttachments[
            attachmentIndex
          ] as PreviewFileItem;
          updatedAttachments[attachmentIndex] = formatCompletedItem(
            fileState.result,
            preview,
          );
        }

        if (
          (fileState.status === 'error' || fileState.status === 'aborted') &&
          updatedAttachments[attachmentIndex].isLoading
        ) {
          const preview = updatedAttachments[
            attachmentIndex
          ] as PreviewFileItem;
          URL.revokeObjectURL(preview.image_url || preview.video_url || '');
          updatedAttachments = updatedAttachments.filter(
            (_, index) => index !== attachmentIndex,
          );
        }
      }

      return updatedAttachments;
    });
  }, [fileStates]);

  const uploadFiles = (files: File[], forceFormat: Format) => {
    const fileMappings = hookUploadFiles(files, { forceFormat });
    const newPreviews: SendFileItem[] = fileMappings.map(
      ({ id: fileId, file }) => makePreviewItem(fileId, file, forceFormat),
    );
    setAttachments(currentAttachments => [
      ...currentAttachments,
      ...newPreviews,
    ]);
  };

  const cancelUpload = (attachment: SendFileItem) => {
    const fileId = String(attachment.id);
    stopUpload(fileId);
    if (attachment.isLoading) {
      const preview = attachment as PreviewFileItem;
      URL.revokeObjectURL(preview.image_url || preview.video_url || '');
    }
    setAttachments(currentAttachments =>
      currentAttachments.filter(
        currentAttachment => String(currentAttachment.id) !== fileId,
      ),
    );
  };

  const updateAttachments = (array: SendFileItem[] = []) => {
    if (array.length === 0) {
      attachments.forEach(attachment => {
        if (isImageAttachment(attachment)) {
          URL.revokeObjectURL(attachment.local_image_url || '');
        } else if (isVideoAttachment(attachment)) {
          URL.revokeObjectURL(attachment.local_video_url || '');
        }
      });
      resetHook();
      setAttachments([]);
    } else {
      setAttachments(array);
    }
  };

  return (
    <SendAttachmentsContext.Provider
      value={{
        uploadFiles,
        isLoadingUpload,
        uploadGif,
        isLoadingUploadGif,
        updateAttachments,
        attachments,
        cancelUpload,
      }}
    >
      {children}
    </SendAttachmentsContext.Provider>
  );
};

export const useSendAttachments = () => useContext(SendAttachmentsContext);

export const SendAttachmentsConsumer = SendAttachmentsContext.Consumer;

export default SendAttachmentsContext;
