"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ricos_truncate_exports = {};
__export(ricos_truncate_exports, {
  getFilteredNodes: () => getFilteredNodes,
  truncateRichContent: () => truncateRichContent
});
module.exports = __toCommonJS(ricos_truncate_exports);
var A = __toESM(require("fp-ts-esm/Array"));
var import_function = require("fp-ts-esm/function");
var import_Predicate = require("fp-ts-esm/Predicate");
var T = __toESM(require("fp-ts-esm/Tuple"));
var import_generate_random_id = require("./../converters/generate-random-id.js");
var import_v1 = require("./../../ricos-schema/legacy/wix/rich_content/v1/index.js");
var import_fp_utils = require("../fp-utils.js");
var import_extract = require("../RicosContentAPI/extract.js");
var import_modify = require("../RicosContentAPI/modify.js");
var import_utils = require("../utils.js");
var import_types = require("./types.js");
const visitNodes = (visitorFn) => ({ nodes }) => {
  const nodesToTasks = (nodes2, parents) => nodes2.map((node, i, nodes3) => [node, { parents, previousSibling: nodes3[i - 1] }]);
  let tasks = nodesToTasks(nodes ?? [], []);
  while (tasks.length) {
    const [node, context] = tasks.shift();
    visitorFn(node, context);
    const parents = [node, ...context.parents];
    tasks = [...nodesToTasks(node.nodes || [], parents), ...tasks];
  }
};
const getFilteredNodes = (filterFn) => (container) => {
  const result = [];
  visitNodes((node, context) => {
    if (filterFn(node, context)) {
      result.push(node);
    }
  })(container);
  return result;
};
const isNonTextualNode = (node) => (0, import_types.isNonTextual)(node.type);
const isTextualNode = (node) => (0, import_types.isTextContainer)(node.type);
const isEmptyParagraph = (node) => node.type === import_v1.Node_Type.PARAGRAPH && node.nodes?.length === 0;
const isTextNode = (node) => node.type === import_v1.Node_Type.TEXT;
const toId = (node) => node.id;
const toWords = (node) => (0, import_extract.extract)(node).map(({ textData }) => textData?.text ?? "").get().flat().join("").split(" ").filter((w) => w !== "");
const toTextLength = (node) => (0, import_extract.extract)(node).map(({ textData }) => textData?.text?.length ?? 0).get().flat().reduce((acc, l) => acc + l, 0);
const toWordCount = (0, import_function.flow)(toWords, A.size);
const toNodeWordCount = (node) => (0, import_function.pipe)([node, node], T.bimap(toWordCount, toId));
const generateNodeIds = (content) => {
  const generatedIds = /* @__PURE__ */ new Set();
  const modifiedContent = (0, import_modify.modify)(content).filter((node) => !node.id && !isTextNode(node)).set((node) => {
    const generatedId = (0, import_generate_random_id.generateId)();
    generatedIds.add(generatedId);
    return [{ ...node, id: generatedId }];
  });
  return [modifiedContent, generatedIds];
};
const restoreEmptyIds = (content, generatedIds) => (0, import_modify.modify)(content).filter((node) => generatedIds.has(node.id)).set((node) => [{ ...node, id: "" }]);
const limitToCount = (count) => (nodeWordCount) => nodeWordCount.reduce(
  ([acc, wordLimit], [id, nodeCount]) => [
    [...acc, [id, Math.min(wordLimit, nodeCount)]],
    Math.max(wordLimit - nodeCount, 0)
  ],
  [[], count]
)[0];
const limitWords = (node, count) => {
  const wordCount = toWordCount(node);
  if (wordCount === count) {
    return node;
  }
  const truncatedLength = toWords(node).slice(0, count).join(" ").length;
  const nodeTextLengths = node.nodes?.filter(isTextNode).map(toTextLength) ?? [];
  const reducedLengths = nodeTextLengths.reduce(
    ([reducedLengths2, limit], nodeLength) => [[...reducedLengths2, Math.min(nodeLength, limit)], Math.max(limit - nodeLength, 0)],
    [[], truncatedLength]
  )[0];
  const shouldAppendEllipsis = (i) => reducedLengths[i] > 0 && reducedLengths[i] < nodeTextLengths[i] || reducedLengths[i] > 0 && reducedLengths[i + 1] === 0;
  const nodes = node.nodes?.filter(isTextNode).map((n, i) => {
    return {
      ...n,
      textData: {
        ...n.textData,
        decorations: n.textData?.decorations ?? [],
        text: n.textData?.text?.slice(0, reducedLengths[i]).concat(shouldAppendEllipsis(i) ? "…" : "") ?? ""
      }
    };
  }).filter((n) => n.textData?.text?.length) ?? [];
  return { ...node, nodes };
};
const defaultSelectCountableNodes = (node) => !isEmptyParagraph(node) && import_types.DEFAULT_COUNTABLE_TYPES.includes(node.type);
const applyToContent = (content) => (nodeWordCount) => (0, import_modify.modify)(content).filter((n) => Object.keys(nodeWordCount).includes(n.id)).set((n) => nodeWordCount[n.id] === 0 ? [] : [limitWords(n, nodeWordCount[n.id])]);
const byNodeCount = (count, selectCountableNodes) => (content) => (0, import_function.pipe)(
  content,
  getFilteredNodes(selectCountableNodes),
  (nodes) => nodes.slice(count).map(toId),
  removeNodesById(content)
);
const byWordsCount = (count) => (content) => (0, import_function.pipe)(
  (0, import_extract.extract)(content.nodes ?? []).filter((0, import_fp_utils.and)([isTextualNode, (0, import_Predicate.not)(isEmptyParagraph)])).get(),
  A.map(toNodeWordCount),
  limitToCount(count),
  import_utils.fromEntries,
  applyToContent(content)
);
const removeNodesById = (content) => (ids) => (0, import_modify.modify)(content).set((n) => ids.includes(n.id) ? [] : [n]);
const byNonTextNodesCount = (count) => (content) => (0, import_function.pipe)(
  (0, import_extract.extract)(content?.nodes ?? []).filter(isNonTextualNode).map(toId).get().slice(count),
  removeNodesById(content)
);
const withFallback = (limits) => ({
  ...{
    nodeCount: Infinity,
    wordCount: Infinity,
    maxPlugins: Infinity
  },
  ...limits
});
const removeEmptyContainers = (content) => (0, import_modify.modify)(content).filter(
  (n) => [
    import_v1.Node_Type.LIST_ITEM,
    import_v1.Node_Type.ORDERED_LIST,
    import_v1.Node_Type.BULLETED_LIST,
    import_v1.Node_Type.BLOCKQUOTE,
    import_v1.Node_Type.TABLE,
    import_v1.Node_Type.COLLAPSIBLE_LIST
  ].includes(n.type)
).set(
  (n) => n.nodes?.length === 0 ? [] : n.type === import_v1.Node_Type.LIST_ITEM && n.nodes.every((nChild) => nChild.nodes.length === 0) ? [] : [n]
);
const removeEmptyCollapsibleListTitleAndBody = (content) => (0, import_modify.modify)(content).filter(
  (n) => [import_v1.Node_Type.COLLAPSIBLE_ITEM_TITLE, import_v1.Node_Type.COLLAPSIBLE_ITEM_BODY].includes(n.type)
).set((n) => !n.nodes || n.nodes.length === 0 ? [] : [n]);
const removeEmptyCollapsibleListItems = (content) => (0, import_modify.modify)(content).filter((n) => n.type === import_v1.Node_Type.COLLAPSIBLE_ITEM).set((n) => {
  if (!n.nodes || n.nodes.length === 0) {
    return [];
  }
  const hasTitleAndBody = (node) => Boolean(
    node.nodes && node.nodes.some((child) => child.type === import_v1.Node_Type.COLLAPSIBLE_ITEM_TITLE) && node.nodes.some((child) => child.type === import_v1.Node_Type.COLLAPSIBLE_ITEM_BODY)
  );
  return !hasTitleAndBody(n) ? [] : [n];
});
const removeEmptyCollapsibleLists = (content) => (0, import_modify.modify)(content).filter((n) => n.type === import_v1.Node_Type.COLLAPSIBLE_LIST).set((n) => !n.nodes || n.nodes?.length === 0 ? [] : [n]);
const removeInvalidCollapsibleLists = (content) => (0, import_function.pipe)(
  content,
  removeEmptyCollapsibleListTitleAndBody,
  removeEmptyCollapsibleListItems,
  removeEmptyCollapsibleLists
);
const removeEmptyRows = (content) => (0, import_modify.modify)(content).filter((n) => [import_v1.Node_Type.TABLE_ROW, import_v1.Node_Type.COLLAPSIBLE_ITEM].includes(n.type)).set((n) => n.nodes?.every((cell) => cell.nodes?.length === 0) ? [] : [n]);
const mergeEmptyParagraphs = (content) => (0, import_function.pipe)(
  content,
  getFilteredNodes(
    (node, { previousSibling }) => !!(isEmptyParagraph(node) && previousSibling && isEmptyParagraph(previousSibling))
  ),
  (nodes) => nodes.map(toId),
  removeNodesById(content)
);
const truncateRichContent = (content, limits, options) => {
  const { nodeCount, wordCount, maxPlugins } = withFallback(limits);
  const [contentWithIds, generatedIds] = generateNodeIds(content);
  const truncatedContent = (0, import_function.pipe)(
    contentWithIds,
    byNonTextNodesCount(maxPlugins),
    byNodeCount(nodeCount, options?.selectCountableNodes || defaultSelectCountableNodes),
    byWordsCount(wordCount),
    removeEmptyRows,
    removeEmptyContainers,
    removeInvalidCollapsibleLists,
    options?.keepEmptyParagraphs ? import_function.identity : mergeEmptyParagraphs
  );
  return restoreEmptyIds(truncatedContent, generatedIds);
};
//# sourceMappingURL=ricos-truncate.js.map
