import _extends from "@babel/runtime/helpers/esm/extends";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
var _excluded = ["disabled", "error", "warning", "withValidationTooltip", "validationTooltipPosition", "withWarningIcon", "multiple", "uploaderText", "uploaderIcon", "view", "uploadButtonPosition", "validationSummary", "validationSummaryStart", "width", "hideFiles", "onBlur", "onFocus", "onChange", "request", "validateBeforeUpload", "onRequestSuccess", "onRequestError", "size", "renderFile"];
import _regeneratorRuntime from "@babel/runtime/regenerator";
import React, { useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { globalObject, isBrowser } from '@skbkontur/global-object';
import { FileUploaderFileStatus, getAttachedFile } from "../../../internal/FileUploaderControl/fileUtils";
import { cx } from "../../../lib/theming/Emotion";
import { useMemoObject } from "../../../hooks/useMemoObject";
import { FileUploaderControlContext } from "../../../internal/FileUploaderControl/FileUploaderControlContext";
import { useControlLocale } from "../../../internal/FileUploaderControl/hooks/useControlLocale";
import { useUpload } from "../../../internal/FileUploaderControl/hooks/useUpload";
import { useDrop } from "../../../hooks/useDrop";
import { ThemeContext } from "../../../lib/theming/ThemeContext";
import { withFileUploaderControlProvider } from "../../../internal/FileUploaderControl/withFileUploaderControlProvider";
import { keyListener } from "../../../lib/events/keyListener";
import { FileUploaderFile } from "../../../internal/FileUploaderControl/FileUploaderFile/FileUploaderFile";
import { FileUploaderFileList } from "../../../internal/FileUploaderControl/FileUploaderFileList/FileUploaderFileList";
import { CommonWrapper } from "../../../internal/CommonWrapper";
import { FileUploaderFileValidationResult } from "../../../internal/FileUploaderControl/FileUploaderFileValidationResult";
import { useFileUploaderSize } from "../../../internal/FileUploaderControl/hooks/useFileUploaderSize";
import { forwardRefAndName } from "../../../lib/forwardRefAndName";
import { FocusControlWrapper } from "../../../internal/FocusControlWrapper";
import { isThemeGTE } from "../../../lib/theming/ThemeHelpers";
import { UploadIcon } from "../UploadIcon";
import { globalClasses, jsStyles, jsRowStyles, jsTileStyles } from "../FileUploader.styles";
var stopPropagation = function stopPropagation(e) {
  return e.stopPropagation();
};
export var FileUploaderDataTids = {
  root: 'FileUploader__root',
  content: 'FileUploader__content',
  link: 'FileUploader__link',
  input: 'FileUploader__input'
};
var defaultRenderFile = function defaultRenderFile(_file, _fileNode, props) {
  return /*#__PURE__*/(
    React.createElement(FileUploaderFile, props)
  );
};
var _FileUploader = forwardRefAndName('FileUploader', function (props, ref) {
  var _files$, _files$2, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _cx;
  var theme = useContext(ThemeContext);
  var disabled = props.disabled,
    error = props.error,
    warning = props.warning,
    _props$withValidation = props.withValidationTooltip,
    withValidationTooltip = _props$withValidation === void 0 ? false : _props$withValidation,
    validationTooltipPosition = props.validationTooltipPosition,
    _props$withWarningIco = props.withWarningIcon,
    withWarningIcon = _props$withWarningIco === void 0 ? false : _props$withWarningIco,
    _props$multiple = props.multiple,
    multiple = _props$multiple === void 0 ? false : _props$multiple,
    uploaderText = props.uploaderText,
    uploaderIcon = props.uploaderIcon,
    _props$view = props.view,
    view = _props$view === void 0 ? 'row' : _props$view,
    _props$uploadButtonPo = props.uploadButtonPosition,
    uploadButtonPosition = _props$uploadButtonPo === void 0 ? 'start' : _props$uploadButtonPo,
    _props$validationSumm = props.validationSummary,
    validationSummary = _props$validationSumm === void 0 ? 'auto' : _props$validationSumm,
    _props$validationSumm2 = props.validationSummaryStart,
    validationSummaryStart = _props$validationSumm2 === void 0 ? 5 : _props$validationSumm2,
    _props$width = props.width,
    width = _props$width === void 0 ? theme.fileUploaderWidth : _props$width,
    _props$hideFiles = props.hideFiles,
    hideFiles = _props$hideFiles === void 0 ? false : _props$hideFiles,
    onBlur = props.onBlur,
    onFocus = props.onFocus,
    onChange = props.onChange,
    request = props.request,
    validateBeforeUpload = props.validateBeforeUpload,
    onRequestSuccess = props.onRequestSuccess,
    onRequestError = props.onRequestError,
    _props$size = props.size,
    size = _props$size === void 0 ? 'small' : _props$size,
    _props$renderFile = props.renderFile,
    renderFile = _props$renderFile === void 0 ? defaultRenderFile : _props$renderFile,
    inputProps = _objectWithoutPropertiesLoose(props, _excluded);
  var _useContext = useContext(FileUploaderControlContext),
    files = _useContext.files,
    setFiles = _useContext.setFiles,
    removeFile = _useContext.removeFile,
    reset = _useContext.reset,
    setFileValidationResult = _useContext.setFileValidationResult;
  var versionGTE5_5 = isThemeGTE(theme, '5.5');
  var locale = useControlLocale(versionGTE5_5);
  var inputRef = useRef(null);
  var fileDivRef = useRef(null);
  var isAsync = !!request;
  var isSingleMode = !multiple;
  var _useState = useState(false),
    hovered = _useState[0],
    setHovered = _useState[1];
  var upload = useUpload(request, onRequestSuccess, onRequestError);
  var tryValidateAndUpload = useCallback(function (files) {
    files.forEach( /*#__PURE__*/function () {
      var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(file) {
        var validationMessage;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) switch (_context.prev = _context.next) {
            case 0:
              _context.t0 = validateBeforeUpload;
              if (!_context.t0) {
                _context.next = 5;
                break;
              }
              _context.next = 4;
              return validateBeforeUpload(file);
            case 4:
              _context.t0 = _context.sent;
            case 5:
              validationMessage = _context.t0;
              if (!validationMessage) {
                isAsync && upload(file);
              } else if (typeof validationMessage === 'object') {
                setFileValidationResult(file.id, FileUploaderFileValidationResult.error(validationMessage.message), validationMessage.status);
              } else {
                setFileValidationResult(file.id, FileUploaderFileValidationResult.error(validationMessage), FileUploaderFileStatus.Error);
              }
            case 7:
            case "end":
              return _context.stop();
          }
        }, _callee);
      }));
      return function (_x) {
        return _ref.apply(this, arguments);
      };
    }());
  }, [validateBeforeUpload, isAsync, upload, setFileValidationResult]);
  var isTileView = view === 'tile';
  var jsViewStyles = versionGTE5_5 && isTileView ? jsTileStyles : jsRowStyles;
  var sizeClassName = useFileUploaderSize(size, {
    small: jsViewStyles.sizeSmall(theme),
    medium: jsViewStyles.sizeMedium(theme),
    large: jsViewStyles.sizeLarge(theme)
  });
  var uploadButtonTileWithFileClassName = useFileUploaderSize(size, {
    small: jsTileStyles.uploadButtonTileWithFileSmall(theme),
    medium: jsTileStyles.uploadButtonTileWithFileMedium(theme),
    large: jsTileStyles.uploadButtonTileWithFileLarge(theme)
  });
  var uploadButtonIconGapClass = useFileUploaderSize(size, {
    small: jsViewStyles.uploadButtonIconGapSmall(theme),
    medium: jsViewStyles.uploadButtonIconGapMedium(theme),
    large: jsViewStyles.uploadButtonIconGapLarge(theme)
  });
  var sizeIconClass = useFileUploaderSize(size, {
    small: versionGTE5_5 ? jsStyles.iconSmall5_5(theme) : jsStyles.iconSmall(theme),
    medium: versionGTE5_5 ? jsStyles.iconMedium5_5(theme) : jsStyles.iconMedium(theme),
    large: versionGTE5_5 ? jsStyles.iconLarge5_5(theme) : jsStyles.iconLarge(theme)
  });
  var sizeWrapperClass = useFileUploaderSize(size, {
    small: jsTileStyles.uploadButtonWrapperSmall(theme),
    medium: jsTileStyles.uploadButtonWrapperMedium(theme),
    large: jsTileStyles.uploadButtonWrapperLarge(theme)
  });
  var sizeWrapperEmptyFileClass = useFileUploaderSize(size, {
    small: jsTileStyles.uploadButtonWrapperEmptyFileSmall(theme),
    medium: jsTileStyles.uploadButtonWrapperEmptyFileMedium(theme),
    large: jsTileStyles.uploadButtonWrapperEmptyFileLarge(theme)
  });
  var contentInnerClass = useFileUploaderSize(size, {
    small: jsStyles.contentInnerSmall(theme),
    medium: jsStyles.contentInnerMedium(theme),
    large: jsStyles.contentInnerLarge(theme)
  });

  /** common part **/
  var handleChange = useCallback(function (newFiles) {
    if (!newFiles || !newFiles.length) {
      return;
    }
    var filesArray = Array.from(newFiles);
    if (isSingleMode) {
      filesArray = [filesArray[0]];
    }
    var attachedFiles = filesArray.map(getAttachedFile);
    if (isSingleMode && attachedFiles.length && files.length) {
      removeFile(files[0].id);
    }
    if (attachedFiles.length) {
      setFiles(attachedFiles);
      tryValidateAndUpload(attachedFiles);
    }
  }, [tryValidateAndUpload, setFiles, isSingleMode, files, removeFile]);
  var handleDrop = useCallback(function (event) {
    if (disabled) {
      return;
    }
    var dataTransfer = event.dataTransfer;
    if (dataTransfer) {
      var _dataTransfer$files;
      if (isSingleMode && dataTransfer.files.length > 1) {
        dataTransfer.dropEffect = 'none';
        return;
      }
      if (((_dataTransfer$files = dataTransfer.files) == null ? void 0 : _dataTransfer$files.length) > 0) {
        inputRef.current && (inputRef.current.files = dataTransfer.files);
        handleChange(dataTransfer.files);
      }
    }
  }, [handleChange, disabled]);
  var _useDrop = useDrop({
      onDrop: handleDrop
    }),
    isDraggable = _useDrop.isDraggable,
    labelRef = _useDrop.ref;
  var _useDrop2 = useDrop(),
    isWindowDraggable = _useDrop2.isDraggable,
    windowRef = _useDrop2.ref;
  if (isBrowser(globalObject)) {
    windowRef.current = globalObject.document;
  }
  var focus = useCallback(function () {
    var _inputRef$current;
    keyListener.isTabPressed = true;
    (_inputRef$current = inputRef.current) == null || _inputRef$current.focus();
  }, []);
  var blur = useCallback(function () {
    var _inputRef$current2;
    (_inputRef$current2 = inputRef.current) == null || _inputRef$current2.blur();
  }, []);
  var removeFileFromNativeInput = useCallback(function (fileId) {
    var dataTransfer = new DataTransfer();
    files.filter(function (f) {
      return f.id !== fileId;
    }).forEach(function (file) {
      dataTransfer.items.add(file.originalFile);
    });
    inputRef.current && (inputRef.current.files = dataTransfer.files);
  }, [files]);
  var handleRemoveFile = useCallback(function (fileId) {
    removeFile(fileId);
    removeFileFromNativeInput(fileId);
  }, [removeFileFromNativeInput, removeFile]);
  var handleReset = useCallback(function () {
    reset();
    var dataTransfer = new DataTransfer();
    inputRef.current && (inputRef.current.files = dataTransfer.files);
  }, [reset, handleRemoveFile]);
  useImperativeHandle(ref, function () {
    return {
      focus: focus,
      blur: blur,
      reset: handleReset,
      removeFile: handleRemoveFile,
      getRootNode: function getRootNode() {
        return rootNodeRef.current;
      }
    };
  }, [ref, blur, focus, handleReset, handleRemoveFile]);
  var _useState2 = useState(false),
    focusedByTab = _useState2[0],
    setFocusedByTab = _useState2[1];
  var handleInputChange = function handleInputChange(event) {
    onChange == null || onChange(event);
    handleChange(event.target.files);
    setHovered(false);
  };
  var handleFocus = function handleFocus(e) {
    if (!disabled) {
      // focus event fires before keyDown eventlistener
      // so we should check tabPressed in async way
      globalObject.requestAnimationFrame == null || globalObject.requestAnimationFrame(function () {
        if (keyListener.isTabPressed) {
          setFocusedByTab(true);
        }
      });
      onFocus == null || onFocus(e);
    }
  };
  var handleBlur = function handleBlur(e) {
    setFocusedByTab(false);
    if (!disabled) {
      onBlur == null || onBlur(e);
    }
  };
  var hasFiles = files.length > 0;
  var hasOneFile = files.length === 1;
  var hasOneFileForSingle = isSingleMode && hasOneFile && !hideFiles;
  var hasError = !!error || ((_files$ = files[0]) == null ? void 0 : _files$.status) === FileUploaderFileStatus.Error;
  var hasWarning = !!warning || ((_files$2 = files[0]) == null ? void 0 : _files$2.status) === FileUploaderFileStatus.Warning;
  var uploadButtonClassNames = cx(jsStyles.uploadButton(theme), jsViewStyles.uploadButton(), sizeClassName, versionGTE5_5 && hasOneFileForSingle && jsViewStyles.uploadButtonWithFile(theme), focusedByTab && jsStyles.uploadButtonFocus(theme), disabled && (_ref2 = {}, _ref2[jsStyles.disabled(theme)] = true, _ref2[jsStyles.disabledBackground(theme)] = !versionGTE5_5 || !hasFiles, _ref2), (focusedByTab || !hasOneFileForSingle || !versionGTE5_5) && (_ref3 = {}, _ref3[jsStyles.warningButton(theme)] = hasWarning, _ref3[jsStyles.errorButton(theme)] = hasError, _ref3), versionGTE5_5 && hasOneFileForSingle && (_ref4 = {}, _ref4[uploadButtonTileWithFileClassName] = isTileView, _ref4[jsStyles.warningFile(theme)] = (!isTileView || hovered) && hasWarning, _ref4[jsStyles.errorFile(theme)] = (!isTileView || hovered) && hasError, _ref4), !disabled && hovered && (_ref5 = {}, _ref5[jsStyles.hovered(theme)] = true, _ref5[jsStyles.hoveredBorderColor(theme)] = !versionGTE5_5, _ref5), isDraggable && !disabled && jsStyles.dragOver(theme));
  var canDrop = isWindowDraggable && !disabled;
  var uploadButtonWrapperClassNames = cx(isTileView && (_ref6 = {}, _ref6[sizeWrapperClass] = true, _ref6[sizeWrapperEmptyFileClass] = !hasOneFileForSingle, _ref6), jsViewStyles.uploadButtonWrapper(), canDrop && jsStyles.windowDragOver(theme));
  var uploadButtonIconClassNames = cx(jsStyles.icon(theme), sizeIconClass, disabled && jsStyles.iconDisabled(theme), !versionGTE5_5 && jsStyles.iconRight(), versionGTE5_5 && uploadButtonIconGapClass);
  var rootClassNames = cx(jsStyles.root(theme), versionGTE5_5 && (_ref7 = {}, _ref7[jsStyles.root5_5()] = true, _ref7[jsRowStyles.root()] = !isTileView, _ref7));
  var contentClassNames = cx(jsViewStyles.content(), (_cx = {}, _cx[jsViewStyles.contentWithFiles()] = hasOneFileForSingle, _cx[contentInnerClass] = !isTileView && (!files.length || !isSingleMode), _cx));
  var afterLinkTextClassNames = cx(globalClasses.afterLinkText, hasOneFileForSingle ? jsStyles.afterLinkText_HasFiles() : jsStyles.afterLinkText(), !versionGTE5_5 && jsStyles.afterLinkTextColor(theme));
  var linkClassNames = cx(jsStyles.link(theme), !disabled && hovered && jsStyles.linkHovered(theme), disabled && jsStyles.linkDisabled(theme));
  useEffect(function () {
    if (!files || !files.length || !inputRef.current) {
      return;
    }
    var dataTransfer = new DataTransfer();
    files.forEach(function (file) {
      return dataTransfer.items.add(file.originalFile);
    });
    inputRef.current.files = dataTransfer.files;
  }, []);
  var rootNodeRef = useRef(null);
  var icon = uploaderIcon != null ? uploaderIcon : /*#__PURE__*/React.createElement(UploadIcon, {
    size: size,
    view: view
  });
  var chooseFileText = uploaderText != null ? uploaderText : locale.chooseFile;
  var chooseFileLocale = "" + chooseFileText + String.fromCharCode(0xa0); /* &nbsp; */
  var hideUploaderText = versionGTE5_5 && isTileView && uploaderText === '';
  var renderChooseFileText = function renderChooseFileText() {
    return !hideUploaderText && /*#__PURE__*/
    React.createElement("span", {
      "data-tid": FileUploaderDataTids.link,
      className: linkClassNames
    }, versionGTE5_5 && !hasOneFileForSingle && chooseFileLocale, !versionGTE5_5 && (hasOneFileForSingle ? locale.choosedFile : locale.chooseFile), versionGTE5_5 ? null : String.fromCharCode(0xa0) /* &nbsp; */);
  };
  var renderFileList = function renderFileList() {
    var propsVersionGTE5_5 = {
      withValidationTooltip: withValidationTooltip,
      validationSummary: validationSummary,
      validationSummaryStart: validationSummaryStart,
      withWarningIcon: withWarningIcon,
      disabled: disabled
    };
    return !hideFiles && !isSingleMode && !!files.length && /*#__PURE__*/
    React.createElement(FileUploaderFileList, _extends({
      renderFile: renderFile,
      size: size,
      view: view,
      onRemove: handleRemoveFile,
      validationTooltipPosition: validationTooltipPosition
    }, versionGTE5_5 && propsVersionGTE5_5));
  };
  var fileProps = {
    file: files[0],
    size: size,
    view: view,
    onRemove: handleRemoveFile,
    error: error,
    warning: warning,
    withValidationTooltip: withValidationTooltip,
    validationTooltipPosition: validationTooltipPosition,
    withWarningIcon: withWarningIcon,
    hovered: hovered,
    disabled: disabled
  };
  var fileElement = renderFile(files[0], /*#__PURE__*/React.createElement(FileUploaderFile, fileProps), fileProps);
  return /*#__PURE__*/(
    React.createElement(CommonWrapper, props, /*#__PURE__*/
    React.createElement("div", {
      "data-tid": FileUploaderDataTids.root,
      className: rootClassNames,
      style: useMemoObject({
        width: isTileView && !multiple ? theme.fileUploaderTileWidth : width
      }),
      ref: rootNodeRef
    }, (!versionGTE5_5 || uploadButtonPosition === 'end') && renderFileList(), /*#__PURE__*/
    React.createElement("div", {
      className: uploadButtonWrapperClassNames
    }, /*#__PURE__*/
    React.createElement("label", {
      onMouseEnter: function onMouseEnter() {
        return setHovered(true);
      },
      onMouseLeave: function onMouseLeave() {
        return setHovered(false);
      },
      ref: labelRef,
      className: uploadButtonClassNames
    }, versionGTE5_5 && !hasOneFileForSingle && /*#__PURE__*/React.createElement("div", {
      className: uploadButtonIconClassNames
    }, icon), /*#__PURE__*/
    React.createElement("div", {
      "data-tid": FileUploaderDataTids.content,
      className: contentClassNames
    }, renderChooseFileText(), /*#__PURE__*/
    React.createElement("div", {
      className: afterLinkTextClassNames
    }, hasOneFileForSingle ? /*#__PURE__*/
    React.createElement("div", {
      ref: fileDivRef,
      className: jsStyles.singleFile()
    }, fileElement) : !versionGTE5_5 && /*#__PURE__*/
    React.createElement(React.Fragment, null, locale.orDragHere, "\xA0", /*#__PURE__*/
    React.createElement("div", {
      className: uploadButtonIconClassNames
    }, icon)))), /*#__PURE__*/
    React.createElement(FocusControlWrapper, {
      onBlurWhenDisabled: function onBlurWhenDisabled() {
        return setFocusedByTab(false);
      }
    }, /*#__PURE__*/
    React.createElement("input", _extends({}, inputProps, {
      "data-tid": FileUploaderDataTids.input,
      ref: inputRef,
      tabIndex: disabled ? -1 : 0,
      type: "file",
      disabled: disabled,
      multiple: multiple,
      className: jsStyles.visuallyHidden(),
      onClick: stopPropagation,
      onChange: handleInputChange,
      onFocus: handleFocus,
      onBlur: handleBlur
    }))))), versionGTE5_5 && uploadButtonPosition === 'start' && renderFileList()))
  );
});

/**
 * `FileUploader` — контрол для выбора пользователем файла на компьютере и отображения статуса его отправки на сервер.
 *
 * Можно использовать для синхронной отправки данных, например, в форме. Или же можно использовать в асинхронном режиме.
 */
export var FileUploader = withFileUploaderControlProvider( /*#__PURE__*/
React.memo(_FileUploader));
FileUploader.displayName = 'FileUploader';