import { Plus } from '@transferwise/icons';
import { clsx } from 'clsx';
import { Component } from 'react';
import { injectIntl } from 'react-intl';
import '../common/theme.mjs';
import '../common/direction.mjs';
import '../common/propsValues/control.mjs';
import '../common/propsValues/breakpoint.mjs';
import '../common/propsValues/size.mjs';
import { Typography } from '../common/propsValues/typography.mjs';
import '../common/propsValues/width.mjs';
import '../common/propsValues/type.mjs';
import '../common/propsValues/dateMode.mjs';
import '../common/propsValues/monthFormat.mjs';
import '../common/propsValues/position.mjs';
import '../common/propsValues/layouts.mjs';
import '../common/propsValues/status.mjs';
import '../common/propsValues/sentiment.mjs';
import '../common/propsValues/profileType.mjs';
import '../common/propsValues/variant.mjs';
import '../common/propsValues/scroll.mjs';
import '../common/propsValues/markdownNodeType.mjs';
import '../common/fileType.mjs';
import '../common/closeButton/CloseButton.messages.mjs';
import { jsxs, jsx } from 'react/jsx-runtime';
import Title from '../title/Title.mjs';
import messages from './Upload.messages.mjs';
import UploadImageStep from './steps/uploadImageStep/uploadImageStep.mjs';
import ProcessingStep from './steps/processingStep/processingStep.mjs';
import CompleteStep from './steps/completeStep/completeStep.mjs';
import { postData, ResponseError } from './utils/postData/postData.mjs';
import { asyncFileRead } from './utils/asyncFileRead/asyncFileRead.mjs';
import { isSizeValid } from './utils/isSizeValid/isSizeValid.mjs';
import { isTypeValid } from './utils/isTypeValid/isTypeValid.mjs';
import { getFileType } from './utils/getFileType/getFileType.mjs';

const ANIMATION_FIX = 10;
const MAX_SIZE_DEFAULT = 5000000;
var UploadStep;
(function (UploadStep) {
  UploadStep["UPLOAD_IMAGE_STEP"] = "uploadImageStep";
})(UploadStep || (UploadStep = {}));
class Upload extends Component {
  static defaultProps = {
    animationDelay: 700,
    maxSize: MAX_SIZE_DEFAULT,
    psButtonDisabled: false,
    size: 'md',
    usAccept: 'image/*',
    usDisabled: false,
    usLabel: ''
  };
  dragCounter = 0;
  timeouts = 0;
  constructor(props) {
    super(props);
    this.state = {
      fileName: '',
      isDroppable: false,
      isComplete: false,
      isError: false,
      isImage: false,
      isProcessing: false,
      isSuccess: false,
      response: undefined,
      uploadedImage: undefined
    };
  }
  getErrorMessage(status) {
    const {
      csFailureText,
      csTooLargeMessage,
      csWrongTypeMessage,
      maxSize,
      intl
    } = this.props;
    switch (status) {
      case 413:
        return csTooLargeMessage || intl.formatMessage(messages.csTooLargeMessage, {
          maxSize: maxSize / 1000000
        });
      case 415:
        return csWrongTypeMessage || intl.formatMessage(messages.csWrongTypeMessage);
      default:
        return csFailureText || intl.formatMessage(messages.csFailureText);
    }
  }
  onDragLeave(event) {
    event.preventDefault();
    this.dragCounter -= 1;
    if (this.dragCounter === 0) {
      this.setState({
        isDroppable: false
      });
    }
  }
  onDragEnter(event) {
    event.preventDefault();
    this.dragCounter += 1;
    const {
      usDisabled
    } = this.props;
    const {
      isProcessing
    } = this.state;
    if (this.dragCounter === 1 && !usDisabled && !isProcessing) {
      this.setState({
        isDroppable: true
      });
    }
  }
  async onDrop(event) {
    const {
      isProcessing
    } = this.state;
    event.preventDefault();
    if (!isProcessing) {
      this.reset();
    }
    if (event.dataTransfer?.files?.[0]) {
      await this.fileDropped(event.dataTransfer.files[0]);
    }
  }
  onAnimationCompleted = async status => {
    const {
      response,
      isProcessing,
      fileName
    } = this.state;
    const {
      animationDelay
    } = this.props;
    if (isProcessing && status === 'succeeded') {
      const {
        onSuccess
      } = this.props;
      this.timeouts = window.setTimeout(() => {
        this.setState({
          isProcessing: false,
          isComplete: true
        }, onSuccess ? () => onSuccess(response, fileName) : undefined);
      }, animationDelay);
    }
    if (isProcessing && status === 'failed') {
      const {
        onFailure
      } = this.props;
      this.timeouts = window.setTimeout(() => {
        this.setState({
          isProcessing: false,
          isComplete: true
        }, onFailure ? () => onFailure(response) : undefined);
      }, animationDelay);
    }
  };
  asyncPost = async file => {
    const {
      httpOptions,
      fetcher
    } = this.props;
    if (httpOptions == null) {
      throw new Error('Cannot find HTTP options');
    }
    const {
      fileInputName = file.name,
      data = {}
    } = httpOptions;
    const formData = new FormData();
    formData.append(fileInputName, file);
    Object.keys(data).forEach(key => formData.append(key, data[key]));
    return postData(httpOptions, formData, fetcher);
  };
  asyncResponse = (response, type) => {
    // Gives time to the animation callback to fire.
    this.timeouts = window.setTimeout(() => {
      this.setState({
        response,
        isError: type === 'error',
        isSuccess: type === 'success'
      });
    }, ANIMATION_FIX);
  };
  handleOnClear = event => {
    event.preventDefault();
    const {
      onCancel
    } = this.props;
    onCancel?.();
    this.reset();
  };
  reset = () => {
    this.dragCounter = 0;
    window.clearTimeout(this.timeouts);
    this.setState({
      isComplete: false,
      isError: false,
      isProcessing: false,
      isSuccess: false
    });
  };
  showDataImage = dataUrl => {
    const {
      isImage
    } = this.state;
    if (isImage) {
      this.setState({
        uploadedImage: dataUrl
      });
    }
  };
  fileDropped = async file => {
    const {
      httpOptions,
      maxSize,
      onStart,
      usDisabled,
      usAccept
    } = this.props;
    const {
      isProcessing
    } = this.state;
    if (usDisabled || isProcessing) {
      return false;
    }
    if (!file) {
      throw new Error('Could not retrieve file');
    }
    this.setState({
      fileName: file.name,
      isDroppable: false,
      isProcessing: true
    });
    onStart?.(file);
    let file64 = null;
    try {
      file64 = await asyncFileRead(file);
    } catch (error) {
      this.asyncResponse(error, 'error');
    }
    if (!file64) {
      return false;
    }
    this.setState({
      isImage: getFileType(file, file64).includes('image')
    });
    if (!isTypeValid(file, usAccept, file64)) {
      this.asyncResponse(new ResponseError(new Response(null, {
        status: 415,
        statusText: 'Unsupported Media Type'
      })), 'error');
      return false;
    }
    if (!isSizeValid(file, maxSize)) {
      this.asyncResponse(new ResponseError(new Response(null, {
        status: 413,
        statusText: 'Request Entity Too Large'
      })), 'error');
      return false;
    }
    if (httpOptions) {
      // Post the file to provided endpoint
      let response;
      try {
        response = await this.asyncPost(file);
      } catch (error) {
        this.asyncResponse(error, 'error');
        return false;
      }
      this.asyncResponse(response, 'success');
      this.showDataImage(file64);
      return true;
    }
    // Post on form submit. And return the encoded image.
    this.showDataImage(file64);
    this.asyncResponse(file64, 'success');
    return true;
  };
  render() {
    const {
      maxSize,
      usDropMessage,
      usAccept,
      usButtonText,
      usButtonRetryText,
      usDisabled,
      usHelpImage,
      usLabel,
      usPlaceholder,
      psButtonText,
      psProcessingText,
      psButtonDisabled,
      csButtonText,
      csSuccessText,
      size,
      intl,
      errorIconLabel
    } = this.props;
    const {
      response,
      fileName,
      isComplete,
      isDroppable,
      isError,
      isImage,
      isProcessing,
      isSuccess,
      uploadedImage
    } = this.state;
    return /*#__PURE__*/jsxs("div", {
      className: clsx('droppable-area', {
        droppable: true,
        'tw-droppable-sm droppable-sm': size === 'sm',
        'tw-droppable-md droppable-md': size === 'md' || !size,
        'tw-droppable-lg droppable-lg': size === 'lg',
        'droppable-dropping': isDroppable,
        'droppable-processing': isProcessing,
        'droppable-complete': isComplete && !isError,
        'droppable-negative': isError && !isProcessing
      }),
      onDragEnter: event => this.onDragEnter(event),
      onDragLeave: event => this.onDragLeave(event),
      onDrop: async event => this.onDrop(event),
      onDragOver: event => event.preventDefault(),
      children: [!isProcessing && !isComplete && /*#__PURE__*/jsx(UploadImageStep, {
        fileDropped: async file => this.fileDropped(file),
        isComplete: isComplete,
        usAccept: usAccept,
        usButtonText: usButtonText || intl.formatMessage(messages.usButtonText),
        usDisabled: usDisabled,
        usHelpImage: usHelpImage,
        usLabel: usLabel,
        usPlaceholder: usPlaceholder || intl.formatMessage(messages.usPlaceholder, {
          maxSize: maxSize / 1000000
        })
      }), (isSuccess || isComplete) && !isError && /*#__PURE__*/jsx(CompleteStep, {
        fileName: fileName,
        isComplete: isComplete,
        isImage: isImage,
        csButtonText: csButtonText || intl.formatMessage(messages.csButtonText),
        csSuccessText: csSuccessText || intl.formatMessage(messages.csSuccessText),
        uploadedImage: uploadedImage,
        onClear: event => this.handleOnClear(event)
      }), isError && !isProcessing && /*#__PURE__*/jsx(UploadImageStep, {
        fileDropped: async file => {
          this.reset();
          await this.fileDropped(file);
        },
        isComplete: !isError,
        usAccept: usAccept,
        usButtonText: usButtonRetryText || intl.formatMessage(messages.retry),
        usDisabled: usDisabled,
        usHelpImage: null,
        usLabel: usLabel,
        usPlaceholder: usPlaceholder || intl.formatMessage(messages.usPlaceholder, {
          maxSize: maxSize / 1000000
        }),
        errorMessage: this.getErrorMessage(response != null && typeof response === 'object' && 'status' in response && typeof response.status === 'number' ? response.status : undefined),
        errorIconLabel: errorIconLabel
      }), isProcessing && /*#__PURE__*/jsx(ProcessingStep, {
        isComplete: isComplete,
        isError: isError,
        isSuccess: isSuccess,
        psButtonText: psButtonText || intl.formatMessage(messages.psButtonText),
        psProcessingText: psProcessingText || intl.formatMessage(messages.psProcessingText),
        psButtonDisabled: psButtonDisabled,
        onAnimationCompleted: async status => this.onAnimationCompleted(status),
        onClear: event => this.handleOnClear(event)
      }), !isProcessing && /*#__PURE__*/jsx("div", {
        className: "droppable-dropping-card droppable-card",
        "aria-live": "polite",
        children: /*#__PURE__*/jsxs("div", {
          className: "droppable-card-content",
          children: [/*#__PURE__*/jsx("div", {
            className: "circle circle-sm text-primary",
            children: /*#__PURE__*/jsx(Plus, {
              size: "16"
            })
          }), /*#__PURE__*/jsx(Title, {
            type: Typography.TITLE_BODY,
            className: "m-t-3",
            children: usDropMessage || intl.formatMessage(messages.usDropMessage)
          })]
        })
      })]
    });
  }
}
var Upload$1 = injectIntl(Upload);

export { MAX_SIZE_DEFAULT, Upload, UploadStep, Upload$1 as default };
//# sourceMappingURL=Upload.mjs.map
