/** 去除 HTML 标签，用于列表摘要与跑马灯纯文本 */
export function stripHtml(html: string): string {
  if (!html) return '';
  if (!/[<>]/.test(html)) return html.trim();
  const doc = new DOMParser().parseFromString(html, 'text/html');
  return (doc.body.textContent ?? '').replace(/\s+/g, ' ').trim();
}

/** 判断富文本是否实质为空 */
export function isHtmlEmpty(html: string): boolean {
  return !stripHtml(html);
}

const ALLOWED_TAGS = new Set([
  'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'ul', 'ol', 'li',
  'img', 'a', 'h2', 'h3', 'blockquote', 'div', 'span',
]);

function sanitizeNode(node: Node): Node | null {
  if (node.nodeType === Node.TEXT_NODE) {
    return node.cloneNode(false);
  }
  if (node.nodeType !== Node.ELEMENT_NODE) return null;

  const el = node as HTMLElement;
  const tag = el.tagName.toLowerCase();
  if (!ALLOWED_TAGS.has(tag)) {
    const frag = document.createDocumentFragment();
    for (const child of Array.from(el.childNodes)) {
      const safe = sanitizeNode(child);
      if (safe) frag.appendChild(safe);
    }
    return frag;
  }

  const out = document.createElement(tag);
  if (tag === 'img') {
    const src = el.getAttribute('src')?.trim();
    if (!src || /^javascript:/i.test(src)) return null;
    out.setAttribute('src', src);
    const alt = el.getAttribute('alt');
    if (alt) out.setAttribute('alt', alt);
    return out;
  }
  if (tag === 'a') {
    const href = el.getAttribute('href')?.trim();
    if (!href || /^javascript:/i.test(href)) return null;
    out.setAttribute('href', href);
    out.setAttribute('target', '_blank');
    out.setAttribute('rel', 'noopener noreferrer');
  }
  for (const child of Array.from(el.childNodes)) {
    const safe = sanitizeNode(child);
    if (safe) out.appendChild(safe);
  }
  return out;
}

/** 富文本 HTML 白名单净化（公告/站内信预览） */
export function sanitizeAnnouncementHtml(html: string): string {
  if (!html?.trim()) return '';
  if (!/[<>]/.test(html)) return html;

  const doc = new DOMParser().parseFromString(html, 'text/html');
  const container = document.createElement('div');
  for (const child of Array.from(doc.body.childNodes)) {
    const safe = sanitizeNode(child);
    if (safe) container.appendChild(safe);
  }
  return container.innerHTML;
}
