"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.BLOCK_STYLE_ATTRIBUTES = void 0;
exports.getBlockColors = getBlockColors;
exports.getBlockPaddings = getBlockPaddings;
exports.getBlockTypography = getBlockTypography;
exports.getColorsAndGradients = getColorsAndGradients;
exports.getGlobalStyles = getGlobalStyles;
exports.getMappedValues = getMappedValues;
exports.parseStylesVariables = parseStylesVariables;
exports.useEditorColorScheme = void 0;
exports.useMobileGlobalStylesColors = useMobileGlobalStylesColors;
var _changeCase = require("change-case");
var _reactNative = require("react-native");
var _colord = require("colord");
var _blockEditor = require("@wordpress/block-editor");
var _compose = require("@wordpress/compose");
var _index = require("./index.native");
/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

const BLOCK_STYLE_ATTRIBUTES = ['textColor', 'backgroundColor', 'style', 'color', 'fontSize'];

// Mapping style properties name to native.
exports.BLOCK_STYLE_ATTRIBUTES = BLOCK_STYLE_ATTRIBUTES;
const BLOCK_STYLE_ATTRIBUTES_MAPPING = {
  textColor: 'color',
  text: 'color',
  background: 'backgroundColor',
  link: 'linkColor',
  placeholder: 'placeholderColor'
};
const PADDING = 12; // $solid-border-space
const UNKNOWN_VALUE = 'undefined';
const DEFAULT_FONT_SIZE = 16;
function getBlockPaddings(mergedStyle, wrapperPropsStyle, blockStyleAttributes, blockColors) {
  const blockPaddings = {};
  if (!mergedStyle.padding && (wrapperPropsStyle?.backgroundColor || blockStyleAttributes?.backgroundColor || blockColors?.backgroundColor)) {
    blockPaddings.padding = PADDING;
    return blockPaddings;
  }

  // Prevent adding extra paddings to inner blocks without background colors.
  if (mergedStyle?.padding && !wrapperPropsStyle?.backgroundColor && !blockStyleAttributes?.backgroundColor && !blockColors?.backgroundColor) {
    blockPaddings.padding = undefined;
  }
  return blockPaddings;
}
function getBlockColors(blockStyleAttributes, defaultColors, blockName, baseGlobalStyles) {
  const blockStyles = {};
  const customBlockStyles = blockStyleAttributes?.style?.color || {};
  const blockGlobalStyles = baseGlobalStyles?.blocks?.[blockName];

  // Global styles colors.
  if (blockGlobalStyles?.color) {
    Object.entries(blockGlobalStyles.color).forEach(([key, value]) => {
      const styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING[key];
      if (styleKey && value !== UNKNOWN_VALUE) {
        var _customBlockStyles$ke;
        const color = (_customBlockStyles$ke = customBlockStyles[key]) !== null && _customBlockStyles$ke !== void 0 ? _customBlockStyles$ke : value;
        blockStyles[styleKey] = color;
      }
    });
  } else if (baseGlobalStyles?.styles?.color?.text) {
    blockStyles[BLOCK_STYLE_ATTRIBUTES_MAPPING.text] = baseGlobalStyles?.styles?.color?.text;
  }

  // Global styles elements.
  if (blockGlobalStyles?.elements) {
    const linkColor = blockGlobalStyles.elements?.link?.color?.text;
    const styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING.link;
    if (styleKey && linkColor && linkColor !== UNKNOWN_VALUE) {
      blockStyles[styleKey] = linkColor;
    }
  }

  // Custom colors.
  Object.entries(blockStyleAttributes).forEach(([key, value]) => {
    const isCustomColor = value?.startsWith?.('#');
    let styleKey = key;
    if (BLOCK_STYLE_ATTRIBUTES_MAPPING[styleKey]) {
      styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING[styleKey];
    }
    if (!isCustomColor) {
      const mappedColor = Object.values(defaultColors !== null && defaultColors !== void 0 ? defaultColors : {}).find(({
        slug
      }) => slug === value);
      if (mappedColor) {
        blockStyles[styleKey] = mappedColor.color;
      }
    } else {
      blockStyles[styleKey] = value;
    }
  });

  // Color placeholder.
  if (blockStyles?.color) {
    blockStyles[BLOCK_STYLE_ATTRIBUTES_MAPPING.placeholder] = blockStyles.color;
  }
  return blockStyles;
}
function getBlockTypography(blockStyleAttributes, fontSizes, blockName, baseGlobalStyles) {
  const typographyStyles = {};
  const customBlockStyles = blockStyleAttributes?.style?.typography || {};
  const blockGlobalStyles = baseGlobalStyles?.blocks?.[blockName];
  const parsedFontSizes = Object.values(fontSizes !== null && fontSizes !== void 0 ? fontSizes : {});

  // Global styles.
  if (blockGlobalStyles?.typography) {
    const fontSize = blockGlobalStyles?.typography?.fontSize;
    const lineHeight = blockGlobalStyles?.typography?.lineHeight;
    if (fontSize) {
      if (parseInt(fontSize, 10)) {
        typographyStyles.fontSize = fontSize;
      } else {
        const mappedFontSize = parsedFontSizes.find(({
          slug
        }) => slug === fontSize);
        if (mappedFontSize) {
          typographyStyles.fontSize = mappedFontSize?.size;
        }
      }
    }
    if (lineHeight) {
      typographyStyles.lineHeight = lineHeight;
    }
  }
  if (blockStyleAttributes?.fontSize && baseGlobalStyles) {
    const mappedFontSize = parsedFontSizes.find(({
      slug
    }) => slug === blockStyleAttributes?.fontSize);
    if (mappedFontSize) {
      typographyStyles.fontSize = mappedFontSize?.size;
    }
  }

  // Custom styles.
  if (customBlockStyles?.fontSize) {
    typographyStyles.fontSize = customBlockStyles?.fontSize;
  }
  if (customBlockStyles?.lineHeight) {
    typographyStyles.lineHeight = customBlockStyles?.lineHeight;
  }
  return typographyStyles;
}

/**
 * Return a value from a certain path of the object.
 * Path is specified as an array of properties, like: [ 'parent', 'child' ].
 *
 * @param {Object} object Input object.
 * @param {Array}  path   Path to the object property.
 * @return {*} Value of the object property at the specified path.
 */
const getValueFromObjectPath = (object, path) => {
  let value = object;
  path.forEach(fieldName => {
    value = value?.[fieldName];
  });
  return value;
};
function parseStylesVariables(styles, mappedValues, customValues) {
  let stylesBase = styles;
  const variables = ['preset', 'custom', 'var', 'fontSize'];
  if (!stylesBase) {
    return styles;
  }
  variables.forEach(variable => {
    // Examples
    // var(--wp--preset--color--gray)
    // var(--wp--custom--body--typography--font-family)
    // var:preset|color|custom-color-2
    const regex = new RegExp(`var\\(--wp--${variable}--(.*?)\\)`, 'g');
    const varRegex = /\"var:preset\|color\|(.*?)\"/gm;
    const fontSizeRegex = /"fontSize":"(.*?)"/gm;
    if (variable === 'preset') {
      stylesBase = stylesBase.replace(regex, (_$1, $2) => {
        const path = $2.split('--');
        const mappedPresetValue = mappedValues[path[0]];
        if (mappedPresetValue && mappedPresetValue.slug) {
          var _mappedPresetValue$va;
          const matchedValue = Object.values((_mappedPresetValue$va = mappedPresetValue.values) !== null && _mappedPresetValue$va !== void 0 ? _mappedPresetValue$va : {}).find(({
            slug
          }) => slug === path[1]);
          return matchedValue?.[mappedPresetValue.slug];
        }
        return UNKNOWN_VALUE;
      });
    }
    if (variable === 'custom') {
      const customValuesData = customValues !== null && customValues !== void 0 ? customValues : JSON.parse(stylesBase);
      stylesBase = stylesBase.replace(regex, (_$1, $2) => {
        const path = $2.split('--');

        // Supports cases for variables like var(--wp--custom--color--background)
        if (path[0] === 'color') {
          const colorKey = path[path.length - 1];
          if (mappedValues?.color) {
            const matchedValue = mappedValues.color?.values?.find(({
              slug
            }) => slug === colorKey);
            if (matchedValue) {
              return `${matchedValue?.color}`;
            }
          }
        }
        if (path.reduce((prev, curr) => prev && prev[curr], customValuesData)) {
          return getValueFromObjectPath(customValuesData, path);
        }

        // Check for camelcase properties.
        return getValueFromObjectPath(customValuesData, [...path.slice(0, path.length - 1), (0, _changeCase.camelCase)(path[path.length - 1])]);
      });
    }
    if (variable === 'var') {
      stylesBase = stylesBase.replace(varRegex, (_$1, $2) => {
        if (mappedValues?.color) {
          const matchedValue = mappedValues.color?.values?.find(({
            slug
          }) => slug === $2);
          return `"${matchedValue?.color}"`;
        }
        return UNKNOWN_VALUE;
      });
    }
    if (variable === 'fontSize') {
      const {
        width,
        height
      } = _reactNative.Dimensions.get('window');
      stylesBase = stylesBase.replace(fontSizeRegex, (_$1, $2) => {
        const parsedFontSize = (0, _blockEditor.getPxFromCssUnit)($2, {
          width,
          height,
          fontSize: DEFAULT_FONT_SIZE
        }) || `${DEFAULT_FONT_SIZE}px`;
        return `"fontSize":"${parsedFontSize}"`;
      });
    }
  });
  return JSON.parse(stylesBase);
}
function getMappedValues(features, palette) {
  const typography = features?.typography;
  const colors = [...(palette?.theme || []), ...(palette?.custom || []), ...(palette?.default || [])];
  const fontSizes = {
    ...typography?.fontSizes?.theme,
    ...typography?.fontSizes?.custom
  };
  const mappedValues = {
    color: {
      values: colors,
      slug: 'color'
    },
    'font-size': {
      values: fontSizes,
      slug: 'size'
    }
  };
  return mappedValues;
}

/**
 * Returns the normalized fontSizes to include the sizePx value for each of the different sizes.
 *
 * @param {Object} fontSizes found in global styles.
 * @return {Object} normalized sizes.
 */
function normalizeFontSizes(fontSizes) {
  // Adds normalized PX values for each of the different keys.
  if (!fontSizes) {
    return fontSizes;
  }
  const normalizedFontSizes = {};
  const dimensions = _reactNative.Dimensions.get('window');
  ['default', 'theme', 'custom'].forEach(key => {
    if (fontSizes[key]) {
      normalizedFontSizes[key] = fontSizes[key]?.map(fontSizeObject => {
        fontSizeObject.sizePx = (0, _blockEditor.getPxFromCssUnit)(fontSizeObject.size, {
          width: dimensions.width,
          height: dimensions.height,
          fontSize: DEFAULT_FONT_SIZE
        });
        return fontSizeObject;
      });
    }
  });
  return normalizedFontSizes;
}
function useMobileGlobalStylesColors(type = 'colors') {
  const colorGradientSettings = (0, _blockEditor.useMultipleOriginColorsAndGradients)();
  const availableThemeColors = colorGradientSettings?.[type]?.reduce((colors, origin) => colors.concat(origin?.[type]), []);
  // Default editor colors/gradients if it's not a block-based theme.
  const defaultPaletteSetting = type === 'colors' ? 'color.palette' : 'color.gradients';
  const [defaultPaletteValue] = (0, _blockEditor.useSettings)(defaultPaletteSetting);
  // In edge cases, the default palette might be undefined. To avoid
  // exceptions across the editor in that case, we explicitly return
  // the default editor colors.
  const defaultPalette = defaultPaletteValue !== null && defaultPaletteValue !== void 0 ? defaultPaletteValue : _blockEditor.SETTINGS_DEFAULTS.colors;
  return availableThemeColors.length >= 1 ? availableThemeColors : defaultPalette;
}
function getColorsAndGradients(defaultEditorColors = [], defaultEditorGradients = [], rawFeatures) {
  const features = rawFeatures ? JSON.parse(rawFeatures) : {};
  return {
    __experimentalGlobalStylesBaseStyles: null,
    __experimentalFeatures: {
      color: {
        ...(!features?.color ? {
          text: true,
          background: true,
          palette: {
            default: defaultEditorColors
          },
          gradients: {
            default: defaultEditorGradients
          }
        } : features?.color),
        defaultPalette: defaultEditorColors?.length > 0,
        defaultGradients: defaultEditorGradients?.length > 0
      }
    }
  };
}
function getGlobalStyles(rawStyles, rawFeatures) {
  var _features$color$text, _features$color$backg, _features$color$defau, _features$color$defau2;
  const features = rawFeatures ? JSON.parse(rawFeatures) : {};
  const mappedValues = getMappedValues(features, features?.color?.palette);
  const colors = parseStylesVariables(JSON.stringify(features?.color), mappedValues);
  const gradients = parseStylesVariables(JSON.stringify(features?.color?.gradients), mappedValues);
  const customValues = parseStylesVariables(JSON.stringify(features?.custom), mappedValues);
  const globalStyles = parseStylesVariables(rawStyles, mappedValues, customValues);
  const fontSizes = normalizeFontSizes(features?.typography?.fontSizes);
  return {
    __experimentalFeatures: {
      color: {
        palette: colors?.palette,
        gradients,
        text: (_features$color$text = features?.color?.text) !== null && _features$color$text !== void 0 ? _features$color$text : true,
        background: (_features$color$backg = features?.color?.background) !== null && _features$color$backg !== void 0 ? _features$color$backg : true,
        defaultPalette: (_features$color$defau = features?.color?.defaultPalette) !== null && _features$color$defau !== void 0 ? _features$color$defau : true,
        defaultGradients: (_features$color$defau2 = features?.color?.defaultGradients) !== null && _features$color$defau2 !== void 0 ? _features$color$defau2 : true
      },
      typography: {
        fontSizes,
        customLineHeight: features?.custom?.['line-height']
      },
      spacing: features?.spacing
    },
    __experimentalGlobalStylesBaseStyles: globalStyles
  };
}

/**
 * Determine and apply appropriate color scheme based on global styles or device's light/dark mode.
 *
 * The function first attempts to retrieve the editor's background color from global styles.
 * If the detected background color is light, light styles are applied, and dark styles otherwise.
 * If no custom background color is defined, styles are applied using the device's dark/light setting.
 *
 * @param {Object} baseStyle - An object representing the base (light theme) styles for the editor.
 * @param {Object} darkStyle - An object representing the additional styles to apply when the editor is in dark mode.
 *
 * @return {Object} - The combined style object that should be applied to the editor.
 */
const useEditorColorScheme = (baseStyle, darkStyle) => {
  const globalStyles = (0, _index.useGlobalStyles)();
  const deviceColorScheme = (0, _compose.usePreferredColorSchemeStyle)(baseStyle, darkStyle);
  const editorColors = globalStyles?.baseColors?.color;
  const editorBackgroundColor = editorColors?.background;
  const isBackgroundColorDefined = typeof editorBackgroundColor !== 'undefined' && editorBackgroundColor !== 'undefined';
  if (isBackgroundColorDefined) {
    const isEditorBackgroundDark = (0, _colord.colord)(editorBackgroundColor).isDark();
    return isEditorBackgroundDark ? {
      ...baseStyle,
      ...darkStyle
    } : baseStyle;
  }
  return deviceColorScheme;
};
exports.useEditorColorScheme = useEditorColorScheme;
//# sourceMappingURL=utils.native.js.map