/**
 * Normalize policy copy to plain text with meaningful line breaks.
 *
 * Policies arrive as rich text (HTML) from the hub, but both places that render
 * them - the full policy page and the popup shown from the registration forms -
 * lay the copy out themselves: they look for numbered headings ("1. About these
 * terms") to build sections and a table of contents. Those headings sit inside
 * tags (`<h3>1. About these terms</h3>`), so the markup has to come off first
 * or the heading never matches and the tags are printed to the visitor as text.
 *
 * Block elements become blank lines so the section split still works, the
 * remaining tags are dropped, and the entities a rich-text editor emits are
 * decoded. Plain-text copy is returned untouched, so this is safe to apply to
 * content from any source.
 */

/**
 * Tables have to be flattened before the general block rules run.
 *
 * The Cookie Notice lays out what the site stores as a "Type / Purpose / Set
 * by" table, and the editor wraps every cell's text in its own <p>. Left to
 * the block rule below, each </p> becomes a paragraph break *inside* the cell,
 * so a three-column row was rendering as three separate paragraphs each led by
 * a stray separator - the row read as a list of fragments rather than a row.
 *
 * So collapse each table first: paragraphs inside a cell are not breaks, cells
 * are joined with " · ", and each row becomes one line.
 */
function flattenTables(html: string): string {
  return html.replace(/<table[\s\S]*?<\/table>/gi, (table) =>
    table
      // Inside a cell, a paragraph is just text - not a new block.
      .replace(/<\/?\s*(p|div)[^>]*>/gi, " ")
      .replace(/<\/\s*(td|th)\s*>/gi, " · ")
      .replace(/<\/\s*tr\s*>/gi, "\n")
      .replace(/<[^>]+>/g, "")
      // Every row ends with a separator from its last cell; drop it.
      .replace(/[^\S\n]*·[^\S\n]*(?=\n|$)/g, "")
      .replace(/[^\S\n]{2,}/g, " ")
      // Keep the table as one block, set off from the copy around it.
      .replace(/\n{2,}/g, "\n")
      // Cells open with the space left by their stripped <p>; without this
      // every row after the header starts indented by one space.
      .replace(/^[^\S\n]+/gm, "")
      .replace(/^\s+|\s+$/g, "")
      .concat("\n\n"),
  );
}

export function normalizePolicyContent(raw: string): string {
  if (!/<[a-z][\s\S]*?>/i.test(raw)) return raw; // already plain text

  return flattenTables(raw)
    .replace(/<\s*br\s*\/?>/gi, "\n")
    .replace(/<\/\s*(p|div|h[1-6]|li|ul|ol|section|article)\s*>/gi, "\n\n")
    .replace(/<[^>]+>/g, "") // strip any remaining tags
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/&quot;/gi, '"')
    .replace(/&#0?39;|&apos;|&rsquo;/gi, "'")
    .replace(/\n{3,}/g, "\n\n") // collapse excess blank lines
    .trim();
}
