import lodash from "lodash";
import { Decoration_Type, Node_Type } from "./../../../../ricos-schema/legacy/wix/rich_content/v1/index.js";
import {
  createTextNode,
  generateRangeMap,
  mergeOverlappingEntityRanges,
  removeOverlappingRangesWithSameStyle
} from "../../node-utils.js";
import { TO_RICOS_DECORATION_TYPE, TO_RICOS_INLINE_STYLE_TYPE } from "../consts.js";
import { getEntity } from "./get-ricos-entity-data.js";
const HEX_COLOR_REGEXP = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
const isEmptyTextNode = (node) => node.type === Node_Type.TEXT && node.textData?.text === "";
const removeUnsupportedEntities = (entityRanges, entityMap) => entityRanges.filter(
  (range) => TO_RICOS_DECORATION_TYPE[entityMap[range.key]?.type] !== void 0
);
const removeUnsupportedDecorations = (inlineStyleRanges) => inlineStyleRanges.filter((range) => isDecorationType(range.style));
const mergeColorDecorations = (decorations) => {
  const colorDecorations = decorations.filter(
    (decoration) => decoration.type === Decoration_Type.COLOR
  );
  const otherDecorations = decorations.filter(
    (decoration) => decoration.type !== Decoration_Type.COLOR
  );
  return colorDecorations.length > 0 ? otherDecorations.concat([lodash.merge({}, ...colorDecorations)]) : otherDecorations;
};
const removeDuplicateDecorations = (decorations) => {
  const seenDecorations = /* @__PURE__ */ new Set();
  return [...decorations.reverse()].filter((decoration) => {
    if (seenDecorations.has(decoration.type)) {
      return false;
    }
    seenDecorations.add(decoration.type);
    return true;
  }).reverse();
};
const isDecorationType = (decorationType = "") => TO_RICOS_DECORATION_TYPE[decorationType] !== void 0 || TO_RICOS_INLINE_STYLE_TYPE[decorationType] !== void 0 || Object.keys(dynamicDecorationGetters).some(
  (dynamicType) => decorationType.includes(dynamicType) && isValidDecorationColor(decorationType)
) || HEX_COLOR_REGEXP.test(decorationType);
const getTextNodesWithLineBreaks = (textNodes) => textNodes.map(
  (node) => extractLineBreaks(node.textData?.text ?? "").map(
    (text) => ({
      ...createTextNode(text),
      textData: {
        text,
        decorations: text === "\n" ? [] : [...node.textData?.decorations ?? []]
      }
    })
  )
).reduce((nodes, nodesArr) => [...nodes, ...nodesArr], []);
const extractLineBreaks = (text) => {
  if (!text.includes("\n") || text === "\n") {
    return [text];
  }
  const texts = text.split(/(\\*\n)/);
  const newLineRegex = /\\(\\)*\n$/;
  return texts.filter((text2) => text2.length !== 0).map((text2) => {
    return newLineRegex.test(text2) ? [text2.replace("\n", ""), "\n"] : [text2];
  }).reduce((acc, val) => [...acc, ...val], []).reduce((allTexts, current, index, array) => {
    if (index === 0) {
      return [current];
    }
    if (current === "\n") {
      return [...allTexts, current];
    }
    if (array[index - 1] === "\n") {
      return [...allTexts, current];
    }
    return [...allTexts.slice(0, -1), allTexts[allTexts.length - 1] + current];
  }, []);
};
const dynamicDecorationGetters = {
  FG: (style) => {
    return {
      type: Decoration_Type.COLOR,
      colorData: { foreground: style }
    };
  },
  BG: (style) => {
    return {
      type: Decoration_Type.COLOR,
      colorData: { background: style }
    };
  },
  "font-size": (style) => {
    const [value, unit] = style.split(/(px|em)/gi);
    return {
      type: Decoration_Type.FONT_SIZE,
      fontSizeData: {
        unit: unit.toUpperCase(),
        value: parseInt(value)
      }
    };
  }
};
const getTextNodes = (block, entityMap, { ignoreUnsupportedValues } = {}, withLineBreaks = true) => {
  const createTextNodeWithDecorations = ({
    text: text2,
    styles: styles2 = [],
    keys: keys2 = []
  }) => {
    const normalizedText = normalizeText(text2);
    const textNode = createTextNode(normalizedText);
    let decorations = [];
    const keysDecorations = removeDuplicateDecorations(
      keys2.map((key) => getEntity(key, entityMap)).filter((x) => x)
    );
    const stylesDecorations = lodash.flowRight(
      removeDuplicateDecorations,
      mergeColorDecorations
    )(styles2.map((style) => getDecoration(style)));
    decorations = [...decorations, ...keysDecorations, ...stylesDecorations].sort(
      decorationComparator
    );
    if (!lodash.isEmpty(decorations) && textNode.textData) {
      textNode.textData.decorations = decorations;
    }
    return textNode;
  };
  const getDecoration = (style) => {
    let decoration;
    try {
      const isLegacyFontColorDecoration = HEX_COLOR_REGEXP.test(style);
      const styleObj = isLegacyFontColorDecoration ? { FG: style } : JSON.parse(style);
      const type = Object.keys(styleObj)[0];
      const value = Object.values(styleObj)[0];
      decoration = dynamicDecorationGetters[type](value);
    } catch {
      if (!isDecorationType(style) && !ignoreUnsupportedValues) {
        throw Error(`Unknown decoration type "${style}"!`);
      }
      decoration = TO_RICOS_INLINE_STYLE_TYPE[style] || {
        type: TO_RICOS_DECORATION_TYPE[style]
      };
    }
    return decoration;
  };
  const { text = "", inlineStyleRanges, entityRanges } = block;
  if (text.length === 0) {
    return [];
  }
  const dedupedStyleRanges = removeOverlappingRangesWithSameStyle(inlineStyleRanges);
  const supportedInlineStyleRanges = ignoreUnsupportedValues ? removeUnsupportedDecorations(dedupedStyleRanges) : dedupedStyleRanges;
  const mergedEntityRanges = mergeOverlappingEntityRanges(entityRanges);
  const rangeMap = generateRangeMap([
    ...supportedInlineStyleRanges,
    ...removeUnsupportedEntities(mergedEntityRanges, entityMap)
  ]);
  const textNodes = [];
  let styles = [];
  let keys = [];
  const numbers = Object.keys(rangeMap).map(Number);
  numbers.forEach((point, i) => {
    if (numbers[i] < text.length) {
      rangeMap[point].forEach((entry) => {
        if (entry.action === "start") {
          if ("style" in entry) {
            styles.push(entry.style);
          } else {
            keys.push(entry.key);
          }
        } else if ("style" in entry) {
          styles = styles.filter((s) => s !== entry.style);
        } else {
          keys = keys.filter((s) => s !== entry.key);
        }
      });
      textNodes.push(
        createTextNodeWithDecorations({
          text: Array.from(text).slice(numbers[i], numbers[i + 1]).join(""),
          styles,
          keys
        })
      );
    }
  });
  const nonEmptyTextNodes = textNodes.filter((node) => !isEmptyTextNode(node));
  return withLineBreaks ? getTextNodesWithLineBreaks(nonEmptyTextNodes) : nonEmptyTextNodes;
};
const decorationComparator = (a, b) => a.type.localeCompare(b.type);
const isValidDecorationColor = (style) => {
  try {
    const styleObj = JSON.parse(style);
    const value = Object.values(styleObj)[0];
    if (value.startsWith("#")) {
      return HEX_COLOR_REGEXP.test(value);
    }
    return true;
  } catch {
    return false;
  }
};
const normalizeText = (text) => {
  return removeHeadingMarkers(removeUnsupportedUnicodeChars(text));
};
const removeUnsupportedUnicodeChars = (text) => {
  return text.replace(/[\u2028\u2029]/g, "");
};
const removeHeadingMarkers = (text) => {
  return text.replace(
    /^\{\$h([1-5])\}(.*?)\{\$h\}/g,
    (matchedText) => matchedText.replace(/^\{\$h[1-5]\}|\{\$h\}$/g, "")
  );
};
export {
  getTextNodes
};
//# sourceMappingURL=get-text-nodes.js.map
