import { convertElement } from "../hast-util-is-element/lib-index.js";
import { findAfter } from "../unist-util-find-after/lib-index.js";
const searchLineFeeds = /\n/g;
const searchTabOrSpaces = /[\t ]+/g;
const br = convertElement("br");
const cell = convertElement(isCell);
const p = convertElement("p");
const row = convertElement("tr");
const notRendered = convertElement([
  // List from: <https://html.spec.whatwg.org/multipage/rendering.html#hidden-elements>
  "datalist",
  "head",
  "noembed",
  "noframes",
  "noscript",
  // Act as if we support scripting.
  "rp",
  "script",
  "style",
  "template",
  "title",
  // Hidden attribute.
  hidden,
  // From: <https://html.spec.whatwg.org/multipage/rendering.html#flow-content-3>
  closedDialog
]);
const blockOrCaption = convertElement([
  "address",
  // Flow content
  "article",
  // Sections and headings
  "aside",
  // Sections and headings
  "blockquote",
  // Flow content
  "body",
  // Page
  "caption",
  // `table-caption`
  "center",
  // Flow content (legacy)
  "dd",
  // Lists
  "dialog",
  // Flow content
  "dir",
  // Lists (legacy)
  "dl",
  // Lists
  "dt",
  // Lists
  "div",
  // Flow content
  "figure",
  // Flow content
  "figcaption",
  // Flow content
  "footer",
  // Flow content
  "form,",
  // Flow content
  "h1",
  // Sections and headings
  "h2",
  // Sections and headings
  "h3",
  // Sections and headings
  "h4",
  // Sections and headings
  "h5",
  // Sections and headings
  "h6",
  // Sections and headings
  "header",
  // Flow content
  "hgroup",
  // Sections and headings
  "hr",
  // Flow content
  "html",
  // Page
  "legend",
  // Flow content
  "li",
  // Lists (as `display: list-item`)
  "listing",
  // Flow content (legacy)
  "main",
  // Flow content
  "menu",
  // Lists
  "nav",
  // Sections and headings
  "ol",
  // Lists
  "p",
  // Flow content
  "plaintext",
  // Flow content (legacy)
  "pre",
  // Flow content
  "section",
  // Sections and headings
  "ul",
  // Lists
  "xmp"
  // Flow content (legacy)
]);
function toText(tree, options) {
  const options_ = options || {};
  const children = "children" in tree ? tree.children : [];
  const block = blockOrCaption(tree);
  const whitespace = inferWhitespace(tree, {
    whitespace: options_.whitespace || "normal"
  });
  const results = [];
  if (tree.type === "text" || tree.type === "comment") {
    results.push(
      ...collectText(tree, {
        breakBefore: true,
        breakAfter: true
      })
    );
  }
  let index = -1;
  while (++index < children.length) {
    results.push(
      ...renderedTextCollection(
        children[index],
        // @ts-expect-error: `tree` is a parent if we’re here.
        tree,
        {
          whitespace,
          breakBefore: index ? void 0 : block,
          breakAfter: index < children.length - 1 ? br(children[index + 1]) : block
        }
      )
    );
  }
  const result = [];
  let count;
  index = -1;
  while (++index < results.length) {
    const value = results[index];
    if (typeof value === "number") {
      if (count !== void 0 && value > count) count = value;
    } else if (value) {
      if (count !== void 0 && count > -1) {
        result.push("\n".repeat(count) || " ");
      }
      count = -1;
      result.push(value);
    }
  }
  return result.join("");
}
function renderedTextCollection(node, parent, info) {
  if (node.type === "element") {
    return collectElement(node, parent, info);
  }
  if (node.type === "text") {
    return info.whitespace === "normal" ? collectText(node, info) : collectPreText(node);
  }
  return [];
}
function collectElement(node, parent, info) {
  const whitespace = inferWhitespace(node, info);
  const children = node.children || [];
  let index = -1;
  let items = [];
  if (notRendered(node)) {
    return items;
  }
  let prefix;
  let suffix;
  if (br(node)) {
    suffix = "\n";
  } else if (row(node) && // @ts-expect-error: something up with types of parents.
  findAfter(parent, node, row)) {
    suffix = "\n";
  } else if (p(node)) {
    prefix = 2;
    suffix = 2;
  } else if (blockOrCaption(node)) {
    prefix = 1;
    suffix = 1;
  }
  while (++index < children.length) {
    items = items.concat(
      renderedTextCollection(children[index], node, {
        whitespace,
        breakBefore: index ? void 0 : prefix,
        breakAfter: index < children.length - 1 ? br(children[index + 1]) : suffix
      })
    );
  }
  if (cell(node) && // @ts-expect-error: something up with types of parents.
  findAfter(parent, node, cell)) {
    items.push("	");
  }
  if (prefix) items.unshift(prefix);
  if (suffix) items.push(suffix);
  return items;
}
function collectText(node, info) {
  const value = String(node.value);
  const lines = [];
  const result = [];
  let start = 0;
  while (start <= value.length) {
    searchLineFeeds.lastIndex = start;
    const match = searchLineFeeds.exec(value);
    const end = match && "index" in match ? match.index : value.length;
    lines.push(
      // Any sequence of collapsible spaces and tabs immediately preceding or
      // following a segment break is removed.
      trimAndCollapseSpacesAndTabs(
        // […] ignoring bidi formatting characters (characters with the
        // Bidi_Control property [UAX9]: ALM, LTR, RTL, LRE-RLO, LRI-PDI) as if
        // they were not there.
        value.slice(start, end).replace(/[\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, ""),
        start === 0 ? info.breakBefore : true,
        end === value.length ? info.breakAfter : true
      )
    );
    start = end + 1;
  }
  let index = -1;
  let join;
  while (++index < lines.length) {
    if (lines[index].charCodeAt(lines[index].length - 1) === 8203 || index < lines.length - 1 && lines[index + 1].charCodeAt(0) === 8203) {
      result.push(lines[index]);
      join = void 0;
    } else if (lines[index]) {
      if (typeof join === "number") result.push(join);
      result.push(lines[index]);
      join = 0;
    } else if (index === 0 || index === lines.length - 1) {
      result.push(0);
    }
  }
  return result;
}
function collectPreText(node) {
  return [String(node.value)];
}
function trimAndCollapseSpacesAndTabs(value, breakBefore, breakAfter) {
  const result = [];
  let start = 0;
  let end;
  while (start < value.length) {
    searchTabOrSpaces.lastIndex = start;
    const match = searchTabOrSpaces.exec(value);
    end = match ? match.index : value.length;
    if (!start && !end && match && !breakBefore) {
      result.push("");
    }
    if (start !== end) {
      result.push(value.slice(start, end));
    }
    start = match ? end + match[0].length : end;
  }
  if (start !== end && !breakAfter) {
    result.push("");
  }
  return result.join(" ");
}
function inferWhitespace(node, info) {
  if (node.type === "element") {
    const properties = node.properties || {};
    switch (node.tagName) {
      case "listing":
      case "plaintext":
      case "xmp": {
        return "pre";
      }
      case "nobr": {
        return "nowrap";
      }
      case "pre": {
        return properties.wrap ? "pre-wrap" : "pre";
      }
      case "td":
      case "th": {
        return properties.noWrap ? "nowrap" : info.whitespace;
      }
      case "textarea": {
        return "pre-wrap";
      }
    }
  }
  return info.whitespace;
}
function hidden(node) {
  return Boolean((node.properties || {}).hidden);
}
function isCell(node) {
  return node.tagName === "td" || node.tagName === "th";
}
function closedDialog(node) {
  return node.tagName === "dialog" && !(node.properties || {}).open;
}
export {
  toText
};
//# sourceMappingURL=lib-index.js.map
