import { type FC } from 'react';
import { useDropzone } from 'react-dropzone';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';

import { IconButton, Stack } from '@mui/material';
import { IconCamera, IconFileUpload } from '@tabler/icons-react';
import { sumBy, uniqueId } from 'lodash';

import {
  type CompleteFile,
  type FileCompleterFunction,
} from '../../../types/attachments';
import { bytesToMB } from '../../../utils/bytes';
import useSnackbar from '../../design-system/Snackbar';

import { type FieldValues } from './CreatePost';

export type CreatePostProps = {
  uploadMedia?: FileCompleterFunction;
  uploadFile?: FileCompleterFunction;
  maxAttachedSize: number;
};

export const AddMediaButtons: FC<CreatePostProps> = ({
  uploadMedia,
  uploadFile,
  maxAttachedSize,
}) => {
  const { t } = useTranslation('material_hu_only');
  const { enqueueSnackbar } = useSnackbar();
  const form = useFormContext<FieldValues>();

  const { files: filesValue, media: mediaValue } = form.watch();

  const options = {
    media: {
      field: 'media',
      upload: uploadMedia,
    },
    files: {
      field: 'files',
      upload: uploadFile,
    },
  } as const;

  const handleFileDropAccepted =
    (option: (typeof options)[keyof typeof options]) => (newFiles: File[]) => {
      const { field, upload } = option;

      const newFilesSize = sumBy(newFiles, f => f.size);
      const oldFilesSize = sumBy(
        [...filesValue, ...mediaValue],
        f => f.file?.size || f.attachment!.bytes,
      );
      if (bytesToMB(newFilesSize + oldFilesSize) > maxAttachedSize) {
        form.setError('files', { type: 'max', message: `${Math.random()}` });
        return;
      }

      const filesWithId = newFiles.map(file => ({
        file,
        id: uniqueId(Math.random().toString()),
      }));
      form.setValue(field, form.getValues(field).concat(filesWithId), {
        shouldDirty: true,
      });
      filesWithId.map(async newFile => {
        const newUploadedFile = await upload!(newFile);
        form.setValue(
          field,
          form
            .getValues(field)
            .map((mediaFile: CompleteFile) =>
              mediaFile.file === newFile.file ? newUploadedFile : mediaFile,
            ),
        );
      });
    };

  const handleDropRejected = () => {
    enqueueSnackbar({
      title: t('posts.size_and_type_error'),
      variant: 'error',
    });
  };

  const types = {
    'video/mp4': ['.mp4'],
    'video/avi': ['.avi'],
    'video/mpeg': ['.mpeg'],
    'video/webm': ['.webm'],
    'image/jpeg': ['.jpg', '.jpeg'],
    'image/png': ['.png'],
    'image/webp': ['.webp'],
  };

  const mediaDropzone = useDropzone({
    noClick: true,
    onDropAccepted: handleFileDropAccepted(options.media),
    onDropRejected: handleDropRejected,
    accept: types,
    multiple: true,
  });

  const filesDropzone = useDropzone({
    noClick: true,
    onDropAccepted: handleFileDropAccepted(options.files),
    onDropRejected: handleDropRejected,
    multiple: true,
  });

  const actions = [
    {
      dropZone: mediaDropzone,
      Icon: IconCamera,
      action: uploadMedia,
    },
    {
      dropZone: filesDropzone,
      Icon: IconFileUpload,
      action: uploadFile,
    },
  ].filter(({ action }) => !!action);

  return (
    <Stack>
      {actions.map((action, index) => (
        <div
          key={index}
          {...action.dropZone.getRootProps()}
        >
          <input {...action.dropZone.getInputProps()} />
          <IconButton onClick={action.dropZone.open}>
            <action.Icon size={24} />
          </IconButton>
        </div>
      ))}
    </Stack>
  );
};

export default AddMediaButtons;
