/* wp:polyfill */
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _i18n = require("@wordpress/i18n");
var _components = require("@wordpress/components");
var _element = require("@wordpress/element");
var _constants = require("./utils/constants");
var _context = require("./context");
var _libFont = require("../../../../lib/lib-font.browser");
var _makeFamiliesFromFaces = _interopRequireDefault(require("./utils/make-families-from-faces"));
var _utils = require("./utils");
var _jsxRuntime = require("react/jsx-runtime");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

function UploadFonts() {
  const {
    installFonts
  } = (0, _element.useContext)(_context.FontLibraryContext);
  const [isUploading, setIsUploading] = (0, _element.useState)(false);
  const [notice, setNotice] = (0, _element.useState)(false);
  const handleDropZone = files => {
    handleFilesUpload(files);
  };
  const onFilesUpload = event => {
    handleFilesUpload(event.target.files);
  };

  /**
   * Filters the selected files to only allow the ones with the allowed extensions
   *
   * @param {Array} files The files to be filtered
   * @return {void}
   */
  const handleFilesUpload = async files => {
    setNotice(null);
    setIsUploading(true);
    const uniqueFilenames = new Set();
    const selectedFiles = [...files];
    let hasInvalidFiles = false;

    // Use map to create a promise for each file check, then filter with Promise.all.
    const checkFilesPromises = selectedFiles.map(async file => {
      const isFont = await isFontFile(file);
      if (!isFont) {
        hasInvalidFiles = true;
        return null; // Return null for invalid files.
      }
      // Check for duplicates
      if (uniqueFilenames.has(file.name)) {
        return null; // Return null for duplicates.
      }
      // Check if the file extension is allowed.
      const fileExtension = file.name.split('.').pop().toLowerCase();
      if (_constants.ALLOWED_FILE_EXTENSIONS.includes(fileExtension)) {
        uniqueFilenames.add(file.name);
        return file; // Return the file if it passes all checks.
      }
      return null; // Return null for disallowed file extensions.
    });

    // Filter out the nulls after all promises have resolved.
    const allowedFiles = (await Promise.all(checkFilesPromises)).filter(file => null !== file);
    if (allowedFiles.length > 0) {
      loadFiles(allowedFiles);
    } else {
      const message = hasInvalidFiles ? (0, _i18n.__)('Sorry, you are not allowed to upload this file type.') : (0, _i18n.__)('No fonts found to install.');
      setNotice({
        type: 'error',
        message
      });
      setIsUploading(false);
    }
  };

  /**
   * Loads the selected files and reads the font metadata
   *
   * @param {Array} files The files to be loaded
   * @return {void}
   */
  const loadFiles = async files => {
    const fontFacesLoaded = await Promise.all(files.map(async fontFile => {
      const fontFaceData = await getFontFaceMetadata(fontFile);
      await (0, _utils.loadFontFaceInBrowser)(fontFaceData, fontFaceData.file, 'all');
      return fontFaceData;
    }));
    handleInstall(fontFacesLoaded);
  };

  /**
   * Checks if a file is a valid Font file.
   *
   * @param {File} file The file to be checked.
   * @return {boolean} Whether the file is a valid font file.
   */
  async function isFontFile(file) {
    const font = new _libFont.Font('Uploaded Font');
    try {
      const buffer = await readFileAsArrayBuffer(file);
      await font.fromDataBuffer(buffer, 'font');
      return true;
    } catch (error) {
      return false;
    }
  }

  // Create a function to read the file as array buffer
  async function readFileAsArrayBuffer(file) {
    return new Promise((resolve, reject) => {
      const reader = new window.FileReader();
      reader.readAsArrayBuffer(file);
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
    });
  }
  const getFontFaceMetadata = async fontFile => {
    const buffer = await readFileAsArrayBuffer(fontFile);
    const fontObj = new _libFont.Font('Uploaded Font');
    fontObj.fromDataBuffer(buffer, fontFile.name);
    // Assuming that fromDataBuffer triggers onload event and returning a Promise
    const onloadEvent = await new Promise(resolve => fontObj.onload = resolve);
    const font = onloadEvent.detail.font;
    const {
      name
    } = font.opentype.tables;
    const fontName = name.get(16) || name.get(1);
    const isItalic = name.get(2).toLowerCase().includes('italic');
    const fontWeight = font.opentype.tables['OS/2'].usWeightClass || 'normal';
    const isVariable = !!font.opentype.tables.fvar;
    const weightAxis = isVariable && font.opentype.tables.fvar.axes.find(({
      tag
    }) => tag === 'wght');
    const weightRange = weightAxis ? `${weightAxis.minValue} ${weightAxis.maxValue}` : null;
    return {
      file: fontFile,
      fontFamily: fontName,
      fontStyle: isItalic ? 'italic' : 'normal',
      fontWeight: weightRange || fontWeight
    };
  };

  /**
   * Creates the font family definition and sends it to the server
   *
   * @param {Array} fontFaces The font faces to be installed
   * @return {void}
   */
  const handleInstall = async fontFaces => {
    const fontFamilies = (0, _makeFamiliesFromFaces.default)(fontFaces);
    try {
      await installFonts(fontFamilies);
      setNotice({
        type: 'success',
        message: (0, _i18n.__)('Fonts were installed successfully.')
      });
    } catch (error) {
      setNotice({
        type: 'error',
        message: error.message,
        errors: error?.installationErrors
      });
    }
    setIsUploading(false);
  };
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
    className: "font-library-modal__tabpanel-layout",
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.DropZone, {
      onFilesDrop: handleDropZone
    }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalVStack, {
      className: "font-library-modal__local-fonts",
      children: [notice && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.Notice, {
        status: notice.type,
        __unstableHTML: true,
        onRemove: () => setNotice(null),
        children: [notice.message, notice.errors && /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
          children: notice.errors.map((error, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)("li", {
            children: error
          }, index))
        })]
      }), isUploading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.FlexItem, {
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
          className: "font-library-modal__upload-area",
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ProgressBar, {})
        })
      }), !isUploading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.FormFileUpload, {
        accept: _constants.ALLOWED_FILE_EXTENSIONS.map(ext => `.${ext}`).join(','),
        multiple: true,
        onChange: onFilesUpload,
        render: ({
          openFileDialog
        }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, {
          __next40pxDefaultSize: true,
          className: "font-library-modal__upload-area",
          onClick: openFileDialog,
          children: (0, _i18n.__)('Upload font')
        })
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalSpacer, {
        margin: 2
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, {
        className: "font-library-modal__upload-area__text",
        children: (0, _i18n.__)('Uploaded fonts appear in your library and can be used in your theme. Supported formats: .ttf, .otf, .woff, and .woff2.')
      })]
    })]
  });
}
var _default = exports.default = UploadFonts;
//# sourceMappingURL=upload-fonts.js.map