import { type FC, useMemo } from 'react';
import {
  type ErrorCode,
  type FileRejection,
  useDropzone,
} from 'react-dropzone';
import { Controller, useFormContext } from 'react-hook-form';

import { Upload } from '@mui/icons-material';
import {
  alpha,
  Box,
  Button,
  FormHelperText,
  Link,
  Stack,
  Typography,
  useTheme,
} from '@mui/material';

import { useModal } from '../../../hooks/useModal';
import CroppingModal from '../../composed-components/CroppingModal';
import { type CroppingModalProps } from '../../composed-components/CroppingModal/types';
import { DocumentItem, DocumentItemTypes } from '../DocumentItem';

import {
  ACCEPT_BY_TYPE,
  DOCUMENT_TYPES,
  MAX_SIZE_BY_TYPE,
  RECOMMENDED_HEIGHT,
  RECOMMENDED_WIDTH,
} from './constants';
import { type FormDropProps, FormDropTypes, type FormDropValue } from './types';

/**
 * @deprecated Use HuFormUploader component instead
 */
export const FormDrop: FC<FormDropProps> = props => {
  const {
    name,
    rules,
    maxSize: maxSizeProp,
    recommendedWidth = RECOMMENDED_WIDTH,
    recommendedHeight = RECOMMENDED_HEIGHT,
    getErrorMessage = () => '',
    altLabel = () => '',
    deleteLabel = () => '',
    helpTextLabel = () => '',
    linkLabel = () => '',
    sizeLabel = () => '',
    openLabel = () => '',
    label = () => '',
    accept: acceptProp,
    type = FormDropTypes.IMAGE,
    onDrop = () => null,
    withCrop,
    cancelLabel,
    saveLabel,
    cropLabel,
    sliderLabel,
    attachmentFormatEnabled = false,
  } = props;

  const theme = useTheme();

  const accept = acceptProp || ACCEPT_BY_TYPE[type];
  const maxSize = maxSizeProp || MAX_SIZE_BY_TYPE[type];

  const { control, trigger, setError, getFieldState } = useFormContext();

  const errorMessage = getFieldState(name)?.error?.message;

  return (
    <Controller
      name={name}
      control={control}
      rules={rules}
      render={({ field: { onChange, value } }) => {
        const dropValue = value as FormDropValue;

        const context = {
          maxSize,
          recommendedHeight,
          recommendedWidth,
          type,
          value,
        };

        const handleSaveCropping = (file: File) => {
          onChange({ file, url: null, attachment: null });
          trigger(name);
        };

        const { modal: croppingModal, showModal: showCroppingModal } =
          useModal<CroppingModalProps>(
            CroppingModal,
            {
              fullWidth: true,
              maxWidth: 'md',
            },
            {
              onSave: handleSaveCropping,
              recommendedWidth,
              recommendedHeight,
              title: cropLabel,
              cancelLabel,
              saveLabel,
              sliderLabel,
            },
          );

        const handleDrop = (files: File[]) => {
          if (!files[0]) return;

          if (type === FormDropTypes.IMAGE && withCrop) {
            showCroppingModal({ file: files[0] });
            return;
          }

          onDrop({ file: files[0], url: null, attachment: null });
          onChange({ file: files[0], url: null, attachment: null });
          trigger(name);
        };

        const handleDelete = () => {
          onChange(null);
          trigger(name);
        };

        const handleError = (fileRejections: FileRejection[]) => {
          if (!fileRejections?.length && !fileRejections[0]?.errors?.length)
            return;

          setError(name, {
            type: 'custom',
            message: getErrorMessage(
              fileRejections[0].errors[0].code as ErrorCode,
              context,
            ),
          });
        };

        const { getRootProps, getInputProps, isDragActive } = useDropzone({
          onDrop: handleDrop,
          onDropRejected: handleError,
          accept,
          maxFiles: 1,
          multiple: false,
          maxSize,
        });

        const hasValue = attachmentFormatEnabled
          ? !!dropValue?.file ||
            (!!dropValue?.attachment && !!dropValue.attachment.url)
          : !!dropValue?.file || !!dropValue?.url;

        const src = useMemo(() => {
          if (!dropValue) return undefined;

          if (attachmentFormatEnabled) {
            const { attachment, file } = dropValue;
            return attachment?.url || (file && URL.createObjectURL(file));
          } else {
            const { url, file } = dropValue;
            return url || (file && URL.createObjectURL(file));
          }
        }, [hasValue, attachmentFormatEnabled]);

        return (
          <Stack
            spacing={3}
            width="100%"
          >
            {type === FormDropTypes.IMAGE && withCrop && croppingModal}
            {hasValue && !DOCUMENT_TYPES.includes(type) && (
              <>
                <Box
                  component={type === FormDropTypes.IMAGE ? 'img' : 'video'}
                  src={src}
                  alt={altLabel(context)}
                  controls
                  sx={{
                    width: '100%',
                    height: 'auto',
                    aspectRatio: `${recommendedWidth}/${recommendedHeight}`,
                    display: 'block',
                    objectFit: 'cover',
                    borderRadius: '20px',
                  }}
                />
                <Button
                  onClick={handleDelete}
                  sx={{ width: 'fit-content' }}
                >
                  {deleteLabel(context)}
                </Button>
              </>
            )}
            {hasValue && DOCUMENT_TYPES.includes(type) && (
              <Stack
                sx={{
                  gap: 1,
                }}
              >
                <DocumentItem
                  name={value.file?.name || ''}
                  size={sizeLabel(context)}
                  url={src}
                  openLabel={openLabel(context)}
                  deleteLabel={deleteLabel(context)}
                  onDelete={handleDelete}
                  type={
                    type === FormDropTypes.PDF
                      ? DocumentItemTypes.PDF
                      : DocumentItemTypes.FILE
                  }
                />
              </Stack>
            )}
            {!hasValue && (
              <>
                <Box
                  aria-describedby="drop-picture-error-text"
                  sx={{
                    borderWidth: '1px',
                    borderRadius: '20px',
                    borderColor: theme.palette.divider,
                    borderStyle: 'dashed',
                    height: '162px',
                    width: '100%',
                    cursor: 'pointer',
                    display: 'flex',
                    flexDirection: 'row',
                    justifyContent: 'center',
                    alignItems: 'center',
                    backgroundColor: isDragActive
                      ? alpha(theme.palette.action.active, 0.05)
                      : 'transparent',
                    '&:hover': {
                      backgroundColor: alpha(theme.palette.action.active, 0.05),
                    },
                  }}
                  {...getRootProps()}
                >
                  <input {...getInputProps()} />
                  <Box
                    sx={{
                      display: 'flex',
                      justifyContent: 'center',
                      alignItems: 'center',
                      height: '64px',
                      width: '64px',
                      borderRadius: '64px',
                      backgroundColor: '#e5e7eb',
                      marginRight: theme.spacing(2),
                      '& .MuiSvgIcon-root': {
                        width: '40px',
                        height: '40px',
                        color: theme.palette.action.active,
                      },
                    }}
                  >
                    <Upload />
                  </Box>
                  <Stack spacing={1}>
                    <Typography
                      variant="h6"
                      component="span"
                    >
                      <Link color="primary">{linkLabel(context)}</Link>
                      {label(context)}
                    </Typography>
                    <Typography
                      variant="body2"
                      component="span"
                      color="textSecondary"
                    >
                      {helpTextLabel(context)}
                    </Typography>
                  </Stack>
                </Box>
                {!!errorMessage && (
                  <FormHelperText
                    error
                    id="drop-picture-error-text"
                  >
                    {errorMessage}
                  </FormHelperText>
                )}
              </>
            )}
          </Stack>
        );
      }}
    />
  );
};
export default FormDrop;
