import React, { useEffect, useState, useRef } from 'react';
// eslint-disable-next-line you-dont-need-lodash-underscore/get
import get from 'lodash-es/get';
import uniqueId from 'lodash-es/uniqueId';
import classNames from 'classnames';
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons/faFolderOpen';
import { faXmark } from '@fortawesome/free-solid-svg-icons/faXmark';
import { useTranslation } from '../hooks/use-translation';
import { FontAwesomeIcon } from '../font-awesome-icon';
import { TruncateWithTooltip } from '../truncate-with-tooltip';
import { Message, MESSAGE_TYPES } from '../message';
import { DragNDropWrapper } from '../drag-and-drop-wrapper';
import { ProgressBar } from '../progress-bar';
import { BUTTON_TYPES } from '../button';
import { DropdownMenu } from '../dropdown-menu';
import { NotificationService } from '../notification-popup';
import { LoadingIcon } from '../loading-icon';
import { DEFAULT_ACCEPTED_FILES } from './file-upload-constants';
import { TOOLTIP_PLACEMENT_TYPES } from '../tooltip';
import { getNonNativeButtonAttrs } from '../hooks';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
const isFileAccepted = (acceptedFileTypes, file) => acceptedFileTypes?.some(fileType => get(file, 'name', '').endsWith(fileType));
/** File upload action indicator.
 * [CAPITALIZATION] Use sentence case for input label, no colon
 * [CAPITALIZATION] Helper text usually a complete sentence with a period. Don't have mixed format in one text block. Can be list item with colon (as in "Accepted formats" example), no punctuation at end.
 */
function FileUpload({
  label,
  onFileUploadSuccess,
  serviceHandler,
  acceptedFiles = DEFAULT_ACCEPTED_FILES,
  onFileUploadFailure,
  isFileValid,
  initialFile,
  inputTestId = 'input-file',
  clearTestId = 'clear-file',
  isLoading,
  uploadPercent,
  isDisabled = false,
  disableDragNDrop = false,
  sourceOptions,
  children,
  triggerTestId = 'custom-source-trigger',
  loadingIconTestId = '',
  loadingIconId = loadingIconTestId,
  showSupportedFilesLabel = true,
  displayValidationErrorsLimit = 10,
  helperText = '',
  disableLocalFileUploading = false,
  tooltipForLocalFileOption = '',
  className = '',
  fileNameTestId = 'file-name-test-id',
  placeholderLabel: placeholderLabelParams,
  uploadProgressLabel: uploadProgressLabelParams,
  failedUploadMessage: failedUploadMessageParams,
  invalidFileTypeMessage: invalidFileTypeMessageParams,
  invalidFileMessage: invalidFileMessageParams,
  acceptedFilesMessage: acceptedFilesMessageParams,
  sourceOptionsTriggerText: sourceOptionsTriggerTextParams,
  clearSelectionText: clearSelectionTextParams,
  localFileOptionText: localFileOptionTextParams,
  browseText: browseTextParams,
  restErrorsAmountMessage: restErrorsAmountMessageParams
}) {
  const {
    t
  } = useTranslation();

  // Set default values for text props using the t function with parameters
  const defaultPlaceholderLabel = sourceOptions && sourceOptions.length ? t('Drag and drop a new dataset or select an option from the right') : t('Drag and drop a file here or browse');
  const defaultUploadProgressLabel = t('Uploading file...');
  const defaultFailedUploadMessage = t('Upload failed');
  const defaultInvalidFileTypeMessage = t('Invalid file type, ');
  const defaultInvalidFileMessage = t('Invalid file, ');
  const defaultAcceptedFilesMessage = t('Accepted formats: {{formats}}', {
    formats: acceptedFiles.join(', ')
  });
  const defaultSourceOptionsTriggerText = t('Import from');
  const defaultClearSelectionText = t('Clear selection');
  const defaultLocalFileOptionText = t('Local File');
  const defaultBrowseText = t('Browse');
  const defaultRestErrorsAmountMessage = restErrorsAmount => t('and {{items}} more...', {
    items: restErrorsAmount
  });

  // Use provided values or defaults with nullish coalescing operator
  const placeholderLabel = placeholderLabelParams ?? defaultPlaceholderLabel;
  const uploadProgressLabel = uploadProgressLabelParams ?? defaultUploadProgressLabel;
  const failedUploadMessage = failedUploadMessageParams ?? defaultFailedUploadMessage;
  const invalidFileTypeMessage = invalidFileTypeMessageParams ?? defaultInvalidFileTypeMessage;
  const invalidFileMessage = invalidFileMessageParams ?? defaultInvalidFileMessage;
  const acceptedFilesMessage = acceptedFilesMessageParams ?? defaultAcceptedFilesMessage;
  const sourceOptionsTriggerText = sourceOptionsTriggerTextParams ?? defaultSourceOptionsTriggerText;
  const clearSelectionText = clearSelectionTextParams ?? defaultClearSelectionText;
  const localFileOptionText = localFileOptionTextParams ?? defaultLocalFileOptionText;
  const browseText = browseTextParams ?? defaultBrowseText;
  const restErrorsAmountMessage = restErrorsAmountMessageParams ?? defaultRestErrorsAmountMessage;
  const [entity, setEntityState] = useState(initialFile);
  const [error, setErrorState] = useState('');
  const [isUploadPending, setIsUploadPendingState] = useState(false);
  const [fileInputKey, setFileInputKey] = useState(uniqueId());
  const fileInputRef = useRef(null);
  useEffect(() => {
    if (!entity) {
      setEntityState(initialFile);
    }
  }, [initialFile]);

  // Unique Id prevents <Label htmlFor={ID}> to be linked to another <Input[file] id={ID}> on the page
  const uniqueInputIdRef = useRef(uniqueId('file-upload-input-'));
  const uniqueLabelIdRef = useRef(uniqueId('file-upload-label-'));
  const resetStates = () => {
    // reset the file state clear the value
    setEntityState(null);
    setErrorState('');
    // reset file input field
    setFileInputKey(uniqueId);
  };
  const onClearFile = () => {
    resetStates();
    if (onFileUploadSuccess) {
      onFileUploadSuccess(null);
    }
  };
  const handleFileUpload = uploadFile => {
    const onHandleFileUploadSuccess = response => {
      if (onFileUploadSuccess) {
        onFileUploadSuccess(response);
      }
    };
    const onHandleFileUploadFailure = err => {
      if (Array.isArray(err)) {
        // throwing an array of file's validation errors
        return setErrorState(err);
      }
      NotificationService.error(get(err, 'message', failedUploadMessage));
      resetStates();
      if (onFileUploadFailure) {
        onFileUploadFailure(err);
      }
    };
    const onHandleFileUploadDone = () => {
      setEntityState(uploadFile);
      setIsUploadPendingState(false);
    };
    if (serviceHandler) {
      setIsUploadPendingState(true);
      serviceHandler(uploadFile).then(onHandleFileUploadSuccess).catch(onHandleFileUploadFailure).finally(onHandleFileUploadDone);
    } else {
      setEntityState(uploadFile);
      if (onFileUploadSuccess) {
        onFileUploadSuccess(uploadFile);
      }
    }
  };
  const handleFileUploadValidation = selectedFile => {
    setErrorState('');
    if (acceptedFiles.length && !isFileAccepted(acceptedFiles, selectedFile)) {
      return setErrorState(invalidFileTypeMessage);
    }

    // if upload prop validator provided
    if (typeof isFileValid === 'function' && selectedFile && !isFileValid(selectedFile, acceptedFiles)) {
      return setErrorState(invalidFileMessage);
    }
    return handleFileUpload(selectedFile);
  };
  const onFileUploaded = e => {
    e.preventDefault();
    const selectedFile = e.target?.files?.[0];
    return handleFileUploadValidation(selectedFile);
  };
  const onDrop = ({
    files
  }) => {
    const selectedFile = files && files[0];
    setEntityState(null);
    handleFileUploadValidation(selectedFile);
  };
  const hasCustomSelector = () => sourceOptions && sourceOptions.length;
  const renderPlaceholder = () => {
    const fileName = entity?.name || placeholderLabel;
    return /*#__PURE__*/_jsx("div", {
      className: "file-placeholder placeholder",
      "test-id": "file-placeholder",
      children: /*#__PURE__*/_jsx(TruncateWithTooltip, {
        tooltipPlacement: TOOLTIP_PLACEMENT_TYPES.BOTTOM,
        className: "file-name",
        children: /*#__PURE__*/_jsx("span", {
          "test-id": fileNameTestId,
          children: fileName
        })
      })
    });
  };
  const renderLayout = selector => {
    return /*#__PURE__*/_jsxs(_Fragment, {
      children: [renderPlaceholder(), !entity && selector]
    });
  };
  const renderDefaultFileInput = () => {
    const attrs = getNonNativeButtonAttrs({
      isDisabled,
      onKeyDown: () => {
        fileInputRef.current?.click?.();
      }
    });
    return /*#__PURE__*/_jsx("label", {
      className: classNames('button command choose-file-btn', {
        disabled: isDisabled
      }),
      "test-id": "choose-file-btn-label",
      htmlFor: uniqueInputIdRef.current,
      children: renderLayout(/*#__PURE__*/_jsxs("div", {
        className: "browse-button",
        ...attrs,
        "aria-describedby": uniqueLabelIdRef.current,
        children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
          icon: faFolderOpen
        }), /*#__PURE__*/_jsx("span", {
          "test-id": "browse-text",
          children: browseText
        })]
      }))
    });
  };
  const renderSourceOptions = () => {
    const options = [{
      id: 'local-file-option',
      key: 'local-file-option',
      testId: 'local-file-option',
      title: localFileOptionText,
      onOptionSelect: () => {
        if (fileInputRef.current) {
          fileInputRef.current.click();
        }
      },
      disabled: disableLocalFileUploading,
      tooltipText: tooltipForLocalFileOption
    }];
    if (sourceOptions?.length) {
      options.push(...sourceOptions);
    }
    return renderLayout(/*#__PURE__*/_jsx(DropdownMenu, {
      isDisabled: isDisabled,
      options: options,
      defaultTriggerText: sourceOptionsTriggerText,
      triggerTestId: triggerTestId,
      onSelect: option => {
        if (option?.onOptionSelect) {
          option.onOptionSelect();
        }
      },
      contentTestId: "file-upload-dropdown-menu"
    }));
  };
  const renderProgress = () => {
    const isProgressTracking = uploadPercent || uploadPercent === 0;
    return /*#__PURE__*/_jsxs("div", {
      className: classNames('file-upload-progress', isProgressTracking && 'file-upload-percent'),
      children: [/*#__PURE__*/_jsx(LoadingIcon, {
        message: uploadProgressLabel,
        testId: loadingIconTestId,
        id: loadingIconId
      }), isProgressTracking && /*#__PURE__*/_jsxs(_Fragment, {
        children: [/*#__PURE__*/_jsx(ProgressBar, {
          max: 100,
          value: uploadPercent,
          ariaLabelledBy: loadingIconId
        }), /*#__PURE__*/_jsxs("span", {
          className: "file-upload-percent-text",
          "test-id": "file-upload-percent-text",
          children: [uploadPercent, "%"]
        })]
      })]
    });
  };
  const renderContent = () => {
    return /*#__PURE__*/_jsxs(_Fragment, {
      children: [hasCustomSelector() ? renderSourceOptions() : renderDefaultFileInput(), /*#__PURE__*/_jsx("input", {
        type: "file",
        id: uniqueInputIdRef.current,
        ref: fileInputRef,
        "test-id": inputTestId,
        onChange: onFileUploaded,
        disabled: isDisabled,
        accept: acceptedFiles.toString()
      }, fileInputKey)]
    });
  };
  const renderServerValidationErrors = errors => {
    const restErrorsAmount = errors.length - displayValidationErrorsLimit;
    return /*#__PURE__*/_jsxs("div", {
      className: "validation-errors",
      "test-id": "file-upload-validation-errors",
      children: [errors.slice(0, displayValidationErrorsLimit).map((err, i) => /*#__PURE__*/_jsx(Message, {
        type: MESSAGE_TYPES.ERROR,
        testId: "file-upload-message-error",
        children: err
      }, i)), restErrorsAmount > 0 && /*#__PURE__*/_jsx(Message, {
        type: MESSAGE_TYPES.ERROR,
        children: restErrorsAmountMessage(restErrorsAmount)
      })]
    });
  };
  return /*#__PURE__*/_jsxs("div", {
    className: classNames('file-upload-input', className),
    "test-id": "file-upload-input",
    children: [label && /*#__PURE__*/_jsx("label", {
      className: classNames('file-upload-field-label', {
        'supported-files': showSupportedFilesLabel && Boolean(acceptedFiles.length)
      }),
      htmlFor: uniqueInputIdRef.current,
      children: label
    }), helperText && /*#__PURE__*/_jsx("div", {
      className: "file-upload-helper-text",
      children: helperText
    }), showSupportedFilesLabel && Boolean(acceptedFiles.length) && /*#__PURE__*/_jsx("label", {
      className: "supported-files-label",
      "test-id": "supported-files-label",
      id: uniqueLabelIdRef.current,
      children: acceptedFilesMessage
    }), /*#__PURE__*/_jsx(DragNDropWrapper, {
      onDropAction: onDrop,
      isDisabled: disableDragNDrop,
      children: /*#__PURE__*/_jsxs("div", {
        className: classNames('file-input-group', {
          disabled: isDisabled || isLoading || isUploadPending
        }),
        "test-id": "file-input-group-container",
        children: [isUploadPending || isLoading ? renderProgress() : renderContent(), entity && !(isUploadPending || isLoading) && !isDisabled && /*#__PURE__*/_jsxs("button", {
          type: BUTTON_TYPES.BUTTON,
          className: "button command choose-file-btn",
          "test-id": clearTestId,
          onClick: onClearFile,
          disabled: isDisabled,
          children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
            icon: faXmark
          }), /*#__PURE__*/_jsx("span", {
            children: clearSelectionText
          })]
        })]
      })
    }), Boolean(error) && (Array.isArray(error) ? renderServerValidationErrors(error) : /*#__PURE__*/_jsxs(Message, {
      type: MESSAGE_TYPES.ERROR,
      testId: "file-upload-message-error",
      children: [error, acceptedFilesMessage]
    })), hasCustomSelector() && typeof children === 'function' && !entity && children({
      handleEntitySelected: setEntityState
    })]
  });
}
export default FileUpload;