import DOMPurify from "dompurify"

const HTML_TAG_RE = /<\/?[a-z][\s\S]*>/i
const IMG_TAG_RE = /<img\b[^>]*\bsrc=/i
const IMG_SRC_RE = /<img\b([^>]*)\bsrc="([^"]*)"/gi
const ABSOLUTE_URL_RE = /^[a-z][a-z\d+\-.]*:/i
const DEV_BACKEND_ORIGIN = ((import.meta.env.VITE_DEV_BACKEND_ORIGIN as string | undefined)?.trim() || "http://127.0.0.1:8000").replace(/\/+$/, "")
const MEDIA_PATH_RE = /^(\/media\/?)/

function escapeHtml(value: string) {
  return value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;")
}

/**
 * Normalize a single media URL so it's absolute and reachable.
 */
export function normalizeMediaUrl(value?: string | null) {
  const url = (value || "").trim()
  if (!url) return ""
  if (ABSOLUTE_URL_RE.test(url) || url.startsWith("//")) return url
  if (!MEDIA_PATH_RE.test(url)) return url

  const apiBase = import.meta.env.VITE_API_BASE_URL || "/api"
  if (/^https?:\/\//i.test(apiBase)) {
    try {
      return new URL(url, new URL(apiBase).origin).toString()
    } catch {
      return url
    }
  }
  if (import.meta.env.DEV && typeof window !== "undefined") {
    return `${DEV_BACKEND_ORIGIN}${url}`
  }
  return url
}

/**
 * Normalize media URLs in rich text using a fast string-based approach.
 * Avoids creating DOM elements on every call — much faster for large
 * content with many images.
 */
function normalizeRichTextMediaUrls(value: string): string {
  if (!value.includes("/media")) return value

  // Fast path: replace media src attributes with a regex approach
  // This avoids the cost of innerHTML + querySelectorAll + outerHTML
  let hadMediaSrc = false
  const result = value.replace(IMG_SRC_RE, (match: string, _before: string, src: string) => {
    if (MEDIA_PATH_RE.test(src)) {
      hadMediaSrc = true
      const normalizedSrc = normalizeMediaUrl(src)
      if (normalizedSrc !== src) {
        return match.replace(`src="${src}"`, `src="${normalizedSrc}"`)
      }
    }
    return match
  })

  // If there were /media references but none were normalized (unusual quoting),
  // fall back to DOM-based normalization
  if (hadMediaSrc && result === value) {
    const el = document.createElement("div")
    el.innerHTML = value
    let changed = false
    el.querySelectorAll("img").forEach((img) => {
      const src = img.getAttribute("src")
      if (src && MEDIA_PATH_RE.test(src)) {
        const normalized = normalizeMediaUrl(src)
        if (normalized !== src) {
          img.setAttribute("src", normalized)
          changed = true
        }
      }
    })
    if (changed) return el.innerHTML
  }

  return result
}

/**
 * Sanitize rich text input — strips XSS, restricts tags, normalizes media URLs.
 * The result is safe to render via dangerouslySetInnerHTML.
 */
export function sanitizeRichText(value?: string | null) {
  if (!value) return ""
  const source = HTML_TAG_RE.test(value)
    ? value
    : escapeHtml(value).replace(/\r?\n/g, "<br />")

  const clean = DOMPurify.sanitize(source, {
    ADD_DATA_URI_TAGS: ["img"],
    ALLOWED_TAGS: [
      "a",
      "b",
      "blockquote",
      "br",
      "code",
      "div",
      "em",
      "h1",
      "h2",
      "h3",
      "h4",
      "i",
      "img",
      "li",
      "ol",
      "p",
      "pre",
      "s",
      "span",
      "strike",
      "strong",
      "u",
      "ul",
    ],
    ALLOWED_ATTR: ["alt", "class", "height", "href", "loading", "rel", "src", "target", "title", "width"],
  })
  return normalizeRichTextMediaUrls(clean)
}

export function richTextToPlainText(value?: string | null) {
  const clean = sanitizeRichText(value)
  if (!clean) return ""
  if (typeof document === "undefined") {
    return clean.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
  }
  const el = document.createElement("div")
  el.innerHTML = clean
  return (el.textContent || "").replace(/\u00a0/g, " ").replace(/\s+/g, " ").trim()
}

export function isRichTextEmpty(value?: string | null) {
  const clean = sanitizeRichText(value)
  if (IMG_TAG_RE.test(clean)) return false
  return richTextToPlainText(clean).length === 0
}
