const ALLOWED_TAGS = new Set([
  "p",
  "br",
  "strong",
  "b",
  "em",
  "i",
  "u",
  "s",
  "blockquote",
  "code",
  "pre",
  "ul",
  "ol",
  "li",
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "a",
  "img",
  "iframe",
  "hr",
  "span",
  "div",
]);

const STRIP_ENTIRELY_TAGS = new Set([
  "script",
  "style",
  "link",
  "meta",
  "object",
  "embed",
  "svg",
  "math",
  "form",
  "input",
  "button",
  "textarea",
  "select",
  "option",
]);

const ALLOWED_ATTRIBUTES: Record<string, Set<string>> = {
  a: new Set(["href", "title", "target", "rel"]),
  img: new Set(["src", "alt", "title", "width", "height"]),
  iframe: new Set([
    "src",
    "title",
    "width",
    "height",
    "allow",
    "allowfullscreen",
    "frameborder",
    "loading",
    "referrerpolicy",
  ]),
  "*": new Set([]),
};

const YOUTUBE_HOSTS = new Set([
  "youtube.com",
  "www.youtube.com",
  "youtube-nocookie.com",
  "www.youtube-nocookie.com",
]);

function escapeHtml(raw: string): string {
  return raw
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

function isSafeHref(href: string): boolean {
  if (!href) return false;
  if (href.startsWith("#")) return true;
  if (href.startsWith("/")) return true;

  try {
    const url = new URL(href, "https://example.com");
    return ["http:", "https:", "mailto:", "tel:"].includes(url.protocol);
  } catch {
    return false;
  }
}

function isSafeImageSrc(src: string): boolean {
  if (!src) return false;
  if (src.startsWith("/")) return true;
  if (src.startsWith("data:image/")) return true;

  try {
    const url = new URL(src, "https://example.com");
    return ["http:", "https:"].includes(url.protocol);
  } catch {
    return false;
  }
}

function isSafeYoutubeEmbedSrc(src: string): boolean {
  if (!src) return false;
  try {
    const url = new URL(src);
    const host = url.hostname.toLowerCase();
    const isYoutubeHost = YOUTUBE_HOSTS.has(host);
    const isEmbedPath = url.pathname.startsWith("/embed/");
    return isYoutubeHost && isEmbedPath && url.protocol === "https:";
  } catch {
    return false;
  }
}

function sanitizeElementTree(root: ParentNode) {
  const children = Array.from(root.childNodes);

  for (const child of children) {
    if (child.nodeType === Node.COMMENT_NODE) {
      child.remove();
      continue;
    }

    if (child.nodeType !== Node.ELEMENT_NODE) {
      continue;
    }

    const el = child as HTMLElement;
    const tag = el.tagName.toLowerCase();

    if (!ALLOWED_TAGS.has(tag)) {
      if (STRIP_ENTIRELY_TAGS.has(tag)) {
        el.remove();
      } else {
        while (el.firstChild) {
          root.insertBefore(el.firstChild, el);
        }
        el.remove();
      }
      continue;
    }

    const allowedForTag = new Set([
      ...ALLOWED_ATTRIBUTES["*"],
      ...(ALLOWED_ATTRIBUTES[tag] || []),
    ]);

    for (const attr of Array.from(el.attributes)) {
      const attrName = attr.name.toLowerCase();
      const attrValue = attr.value.trim();

      if (attrName.startsWith("on")) {
        el.removeAttribute(attr.name);
        continue;
      }

      if (!allowedForTag.has(attrName)) {
        el.removeAttribute(attr.name);
        continue;
      }

      if (tag === "a" && attrName === "href" && !isSafeHref(attrValue)) {
        el.removeAttribute("href");
      }

      if (tag === "img" && attrName === "src" && !isSafeImageSrc(attrValue)) {
        el.removeAttribute("src");
      }

      if (tag === "iframe" && attrName === "src" && !isSafeYoutubeEmbedSrc(attrValue)) {
        el.remove();
        break;
      }
    }

    if (!el.isConnected) {
      continue;
    }

    if (tag === "a") {
      const target = (el.getAttribute("target") || "").toLowerCase();
      if (target === "_blank") {
        el.setAttribute("rel", "noopener noreferrer");
      }
    }

    if (tag === "img") {
      el.setAttribute("loading", "lazy");
      el.setAttribute("decoding", "async");
    }

    if (tag === "iframe") {
      if (!el.getAttribute("loading")) el.setAttribute("loading", "lazy");
      if (!el.getAttribute("referrerpolicy")) {
        el.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
      }
    }

    sanitizeElementTree(el);
  }
}

export function sanitizeBlogHtml(raw: string): string {
  if (!raw) return "";

  if (typeof window === "undefined") {
    return escapeHtml(raw).replaceAll("\n", "<br />");
  }

  const parser = new DOMParser();
  const doc = parser.parseFromString(raw, "text/html");
  sanitizeElementTree(doc.body);
  return doc.body.innerHTML;
}
