import "server-only";

import { isTag, isText, type AnyNode, type Element } from "domhandler";
import { parseDocument } from "htmlparser2";

const SKIPPED_TAGS = new Set([
  "canvas",
  "head",
  "noscript",
  "script",
  "style",
  "svg",
  "title",
]);

const BLOCK_TAGS = new Set([
  "blockquote",
  "br",
  "div",
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "li",
  "p",
  "table",
  "td",
  "th",
  "tr",
]);

const URL_TOKEN_PATTERN = /(?:\[|\()?https?:\/\/[^\s\])>]+(?:\]|\))?/gi;
const TRACKING_URL_PATTERN = /^https?:\/\//i;

function isHiddenElement(element: Element) {
  const attributes = element.attribs ?? {};
  const style = (attributes.style ?? "").replace(/\s+/g, "").toLowerCase();

  return (
    "hidden" in attributes ||
    attributes["aria-hidden"]?.toLowerCase() === "true" ||
    /(?:^|;)display:none(?:!important)?(?:;|$)/.test(style) ||
    /(?:^|;)visibility:hidden(?:!important)?(?:;|$)/.test(style) ||
    /(?:^|;)mso-hide:all(?:!important)?(?:;|$)/.test(style) ||
    /(?:^|;)font-size:0(?:px|pt|em|rem|%)?(?:!important)?(?:;|$)/.test(style) ||
    /(?:^|;)opacity:0(?:!important)?(?:;|$)/.test(style) ||
    (/max-height:0(?:px)?/.test(style) && /overflow:hidden/.test(style))
  );
}

function appendBoundary(parts: string[]) {
  if (parts.length > 0 && parts[parts.length - 1] !== "\n") {
    parts.push("\n");
  }
}

function collectVisibleText(nodes: AnyNode[], parts: string[], hidden = false) {
  for (const node of nodes) {
    if (isText(node)) {
      if (!hidden) {
        const text = node.data.replace(/[\u200B-\u200D\uFEFF]/g, " ");
        if (text.trim() && !TRACKING_URL_PATTERN.test(text.trim())) {
          parts.push(text);
        }
      }
      continue;
    }

    if (!isTag(node)) {
      if ("children" in node && Array.isArray(node.children)) {
        collectVisibleText(node.children, parts, hidden);
      }
      continue;
    }

    const tagName = node.name.toLowerCase();
    const shouldSkip = hidden || SKIPPED_TAGS.has(tagName) || isHiddenElement(node);
    const isBlock = BLOCK_TAGS.has(tagName);
    if (isBlock) appendBoundary(parts);
    if (!shouldSkip) collectVisibleText(node.children, parts, false);
    if (isBlock) appendBoundary(parts);
  }
}

function cleanPreviewText(value: string) {
  return value
    .replace(URL_TOKEN_PATTERN, " ")
    .replace(/\(\s*\)/g, " ")
    .replace(/[\t\f\v ]+/g, " ")
    .replace(/\s*\n\s*/g, " ")
    .replace(/\s+/g, " ")
    .trim();
}

export function createMailboxSnippet(input: {
  bodyHtml?: string | null;
  bodyText?: string | null;
  limit?: number;
}) {
  const limit = Math.max(40, Math.min(300, input.limit ?? 140));
  let visibleText = "";

  if (input.bodyHtml?.trim()) {
    const documentNode = parseDocument(input.bodyHtml, { decodeEntities: true });
    const parts: string[] = [];
    collectVisibleText(documentNode.children, parts);
    visibleText = cleanPreviewText(parts.join(""));
  }

  if (!visibleText) {
    visibleText = cleanPreviewText(input.bodyText ?? "");
  }

  return visibleText.slice(0, limit);
}

export function shouldRepairMailboxSnippet(value: string) {
  const head = value.trim().slice(0, 220);
  return !head || /https?:\/\/|\bEmail Template\b/i.test(head);
}
