/**
 * Allow a small HTML subset in thank-you messages (links styled as buttons).
 * Strips scripts, event handlers, and non-http(s)/mailto URLs.
 */
const ALLOWED_TAGS = new Set([
  "a",
  "p",
  "br",
  "strong",
  "b",
  "em",
  "i",
  "u",
  "span",
  "div",
  "ul",
  "ol",
  "li",
  "h3",
  "h4",
]);

const ALLOWED_ATTRS: Record<string, Set<string>> = {
  a: new Set(["href", "target", "rel", "class", "style", "title"]),
  p: new Set(["class", "style"]),
  span: new Set(["class", "style"]),
  div: new Set(["class", "style"]),
  strong: new Set(["class"]),
  b: new Set(["class"]),
  em: new Set(["class"]),
  i: new Set(["class"]),
  u: new Set(["class"]),
  ul: new Set(["class"]),
  ol: new Set(["class"]),
  li: new Set(["class"]),
  h3: new Set(["class", "style"]),
  h4: new Set(["class", "style"]),
  br: new Set([]),
};

function isSafeHref(href: string): boolean {
  const value = href.trim();
  if (!value) return false;
  const lower = value.toLowerCase();
  return (
    lower.startsWith("https://") ||
    lower.startsWith("http://") ||
    lower.startsWith("mailto:") ||
    lower.startsWith("/") ||
    lower.startsWith("#")
  );
}

function sanitizeStyle(style: string): string {
  const lower = style.toLowerCase();
  if (
    lower.includes("expression") ||
    lower.includes("url(") ||
    lower.includes("javascript") ||
    lower.includes("@import")
  ) {
    return "";
  }
  return style.slice(0, 500);
}

/** True when the string likely contains markup worth rendering as HTML. */
export function looksLikeHtml(value: string): boolean {
  return /<[a-z][\s\S]*>/i.test(value);
}

export function sanitizeThankYouHtml(dirty: string): string {
  if (!dirty) return "";
  if (typeof window === "undefined") {
    return sanitizeThankYouHtmlServer(dirty);
  }

  const template = document.createElement("template");
  template.innerHTML = dirty;
  sanitizeNode(template.content);
  return template.innerHTML;
}

function sanitizeThankYouHtmlServer(dirty: string): string {
  // Server fallback: strip dangerous tags/attrs without DOM.
  return dirty
    .replace(/<\/?(script|iframe|object|embed|link|meta|form|input|textarea|select|button|svg|math)[^>]*>/gi, "")
    .replace(/\son[a-z]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "")
    .replace(/javascript\s*:/gi, "")
    .slice(0, 8000);
}

function sanitizeNode(root: ParentNode) {
  const nodes = Array.from(root.childNodes);
  for (const node of nodes) {
    if (node.nodeType === Node.COMMENT_NODE) {
      node.parentNode?.removeChild(node);
      continue;
    }
    if (node.nodeType !== Node.ELEMENT_NODE) continue;

    const el = node as Element;
    const tag = el.tagName.toLowerCase();

    if (!ALLOWED_TAGS.has(tag)) {
      // Keep text content of disallowed elements.
      while (el.firstChild) {
        el.parentNode?.insertBefore(el.firstChild, el);
      }
      el.parentNode?.removeChild(el);
      continue;
    }

    const allowed = ALLOWED_ATTRS[tag] ?? new Set<string>();
    for (const attr of Array.from(el.attributes)) {
      const name = attr.name.toLowerCase();
      if (!allowed.has(name)) {
        el.removeAttribute(attr.name);
        continue;
      }
      if (name === "href") {
        if (!isSafeHref(attr.value)) {
          el.removeAttribute(attr.name);
        } else if (el.getAttribute("target") === "_blank") {
          el.setAttribute("rel", "noopener noreferrer");
        }
      }
      if (name === "style") {
        const cleaned = sanitizeStyle(attr.value);
        if (!cleaned) el.removeAttribute("style");
        else el.setAttribute("style", cleaned);
      }
    }

    sanitizeNode(el);
  }
}

/** Example snippet users can paste for a linked button on the end screen. */
export const THANK_YOU_BUTTON_HTML_EXAMPLE = `<p>Your feedback helps us build a better product.</p>
<p style="margin-top:16px">
  <a href="https://example.com" target="_blank" rel="noopener noreferrer"
     style="display:inline-block;padding:10px 18px;background:#0EA5E9;color:#fff;font-weight:700;text-decoration:none;border-radius:8px">
    Visit our website
  </a>
</p>`;
