import { useCallback, useRef } from 'react';
import { type FileRejection } from 'react-dropzone';
import { Controller, useFormContext } from 'react-hook-form';

import InputFile from '@material-hu/components/composed-components/dynamic-forms/components/FormInputs/InputFile';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import { type FormFile } from '@material-hu/types/attachments';

import { uploadFiles } from 'src/services/attachments';
import { bytesFrom, bytesToSize } from 'src/utils/bytes';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { MAX_ATTACHMENTS, MAX_ATTACHMENTS_SIZE } from '../../constants';
import { getUploadingFieldName } from '../../utils';

const MAX_SIZE_PER_FILE = bytesFrom(100, 'MB');

type Props = {
  name: string;
  required?: boolean;
  formFilled?: boolean;
};

const UploadFileInput = ({ name, required, formFilled }: Props) => {
  const { t } = useLokaliseTranslation(['service_management', 'validations']);

  const { enqueueSnackbar } = useSnackbar();

  const { control, watch, setValue } = useFormContext();

  const activeUploadsRef = useRef(0);

  const handleUploadFiles = useCallback(
    async (files: FormFile[]) => {
      activeUploadsRef.current++;
      setValue(getUploadingFieldName(name), true);
      try {
        return await uploadFiles(files);
      } finally {
        activeUploadsRef.current--;
        if (activeUploadsRef.current === 0) {
          setValue(getUploadingFieldName(name), false);
        }
      }
    },
    [name, setValue],
  );

  const uploadedAssets = watch(name);

  const handleDropRejected = (errors: FileRejection[]) => {
    const hasTooManyFiles = errors.some(rejection =>
      rejection.errors.some(e => e.code === 'too-many-files'),
    );
    const hasFileTooLarge = errors.some(rejection =>
      rejection.errors.some(e => e.code === 'file-too-large'),
    );

    if (hasTooManyFiles) {
      enqueueSnackbar({
        title: t('service_management:max_attachments_exceeded', {
          count: MAX_ATTACHMENTS,
        }),
        variant: 'error',
      });
    }

    if (hasFileTooLarge) {
      enqueueSnackbar({
        title: t('service_management:max_attachments_size_exceeded', {
          size: bytesToSize(MAX_ATTACHMENTS_SIZE),
        }),
        variant: 'error',
      });
    }
  };

  return (
    <Controller
      name={name}
      control={control}
      rules={{
        required: required ? t('validation:required') : false,
      }}
      render={() => (
        <InputFile
          name={name}
          readOnly={formFilled}
          disabled={formFilled}
          initialFiles={uploadedAssets}
          uploadFn={handleUploadFiles}
          acceptedTypes={[
            'image',
            'pdf',
            'msword',
            'video',
            'compressed',
            'xml',
          ]}
          maxFiles={MAX_ATTACHMENTS}
          fileSizeLimit={MAX_SIZE_PER_FILE}
          slotProps={{
            uploader: {
              onDropRejected: handleDropRejected,
              disabled: formFilled,
              sx: {
                width: '100%',
              },
            },
          }}
        />
      )}
    />
  );
};

export default UploadFileInput;
