/**
 * Remove scripts and other executable markup before displaying mail HTML.
 * DOM-only (no broad regex) so newsletter markup is not corrupted.
 */

const EXECUTABLE_SELECTOR =
  "script, iframe, object, embed, frame, frameset, link[rel='import'], link[as='script']"

const EVENT_HANDLER_ATTR = /^on/i
const URI_ATTRS = /^(?:href|src|srcset|data|action|formaction|xlink:href)$/i
const JAVASCRIPT_URI = /^javascript:/i

function stripExecutableFromDocument(doc: Document): void {
  doc.querySelectorAll(EXECUTABLE_SELECTOR).forEach((el) => el.remove())
  doc.querySelectorAll("svg script").forEach((el) => el.remove())

  // <noscript> content is visible when scripts are blocked — unwrap it
  for (const ns of doc.querySelectorAll("noscript")) {
    const fragment = doc.createDocumentFragment()
    const tpl = doc.createElement("template")
    tpl.innerHTML = ns.textContent ?? ""
    fragment.append(...Array.from(tpl.content.childNodes))
    ns.replaceWith(fragment)
  }

  for (const el of doc.querySelectorAll("*")) {
    for (const attr of [...el.attributes]) {
      if (EVENT_HANDLER_ATTR.test(attr.name)) {
        el.removeAttribute(attr.name)
        continue
      }
      if (URI_ATTRS.test(attr.name) && JAVASCRIPT_URI.test(attr.value.trim())) {
        el.removeAttribute(attr.name)
      }
    }
    const style = el.getAttribute("style")
    if (style && JAVASCRIPT_URI.test(style)) {
      el.setAttribute(
        "style",
        style.replace(/javascript:[^;'")]+/gi, "about:blank")
      )
    }
  }

  for (const meta of doc.querySelectorAll('meta[http-equiv]')) {
    if (meta.getAttribute("http-equiv")?.toLowerCase() !== "refresh") continue
    const content = meta.getAttribute("content") ?? ""
    if (JAVASCRIPT_URI.test(content)) meta.remove()
  }
}

/** Strip scripts, nested frames, and inline handlers from an HTML fragment. */
export function stripExecutableEmailHtml(html: string): string {
  if (!html || !html.trim()) return html

  if (typeof DOMParser === "undefined") {
    return html
  }

  try {
    const doc = new DOMParser().parseFromString(html, "text/html")
    stripExecutableFromDocument(doc)
    return doc.body?.innerHTML ?? html
  } catch {
    return html
  }
}
