import React, { useImperativeHandle, useRef, useState } from 'react';
import { useDidUpdateEffect } from '@devesharp/react-hooks/lib/useDidUpdateEffect';
import { useEventListener } from '@devesharp/react-hooks/lib/useEventListener';
import { UploadManager, IFile, IUploadManagerOptions } from '@devesharp/upload-files-js';
import Style from './UploadFiles.style';

interface IPropsUploadFiles {
   drag?: boolean;
   multiple?: boolean;
   options: IUploadManagerOptions;
   children: any;
}

export interface IRefUploadFiles {
   cancelFile: (file: IFile) => void;
   retryFilesError: () => void;
}

export const UploadFiles = React.forwardRef<IRefUploadFiles, IPropsUploadFiles>(function UploadFiles(
   { drag = false, multiple = false, options, children }: IPropsUploadFiles,
   ref: any,
) {
   const inputRef = useRef<any>();

   const uploadManager = useRef<UploadManager>(new UploadManager(options));
   const [dragging, setDragging] = useState(false);

   useDidUpdateEffect(() => {
      uploadManager.current = new UploadManager(options);
   }, [options]);

   function dropFile(ev: any): void {
      if (drag) {
         ev.preventDefault();
         setDragging(false);
         Array.from(ev.dataTransfer.files).forEach((file) => uploadManager.current.addFile(file as File));
      }
   }

   function onChangeFile(ev: any): void {
      Array.from(ev.target.files).forEach((file) => uploadManager.current.addFile(file as File));
      if (inputRef.current) {
         inputRef.current.value = '';
      }
   }

   useEventListener(
      'drop',
      (ev) => {
         if (!drag) {
            ev.preventDefault();
         }
      },
      inputRef,
   );

   useImperativeHandle(
      ref,
      () => ({
         cancelFile: (file: IFile) => {
            uploadManager.current.cancelFile(file);
         },
         retryFilesError: () => {
            uploadManager.current.retryFilesError();
         },
      }),
      [],
   );

   return (
      <Style
         onDragEnter={() => drag && setDragging(true)}
         onDragLeave={() => drag && setDragging(false)}
         onDrop={dropFile}
      >
         <input type="file" ref={inputRef} onChange={onChangeFile} multiple={multiple} />
         {children({ dragging })}
      </Style>
   );
});
