/**
 * Lightweight SVG sanitizer for server-side use (no DOM dependency).
 * Strips dangerous elements and attributes from SVG markup using allowlists.
 */

const ALLOWED_ELEMENTS = new Set([
  'svg', 'g', 'path', 'circle', 'ellipse', 'rect', 'line', 'polyline',
  'polygon', 'text', 'tspan', 'textPath', 'defs', 'use', 'symbol',
  'clipPath', 'mask', 'pattern', 'linearGradient', 'radialGradient', 'stop',
  'marker', 'image', 'title', 'desc', 'metadata',
  'animate', 'animateTransform', 'animateMotion', 'set',
  'filter', 'feGaussianBlur', 'feOffset', 'feMerge', 'feMergeNode',
  'feFlood', 'feComposite', 'feBlend', 'feColorMatrix', 'feComponentTransfer',
  'feFuncR', 'feFuncG', 'feFuncB', 'feFuncA', 'feConvolveMatrix',
  'feDiffuseLighting', 'feDisplacementMap', 'feDropShadow', 'feImage',
  'feMorphology', 'fePointLight', 'feSpecularLighting', 'feSpotLight',
  'feTile', 'feTurbulence',
])

const FORBIDDEN_ELEMENTS = new Set([
  'script', 'foreignObject', 'iframe', 'object', 'embed', 'applet',
])

/** Matches event handler attributes: on* */
const EVENT_HANDLER_RE = /\bon\w+\s*=/gi

/** Matches javascript: URLs in href/xlink:href */
const JS_URL_RE = /(href\s*=\s*["'])\s*javascript:/gi

/** Matches a full element tag (opening or self-closing) */
const TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:\s[^>]*)?)>/g

/** Matches complete forbidden element blocks including content */
function stripForbiddenBlocks(svg: string): string {
  for (const tag of FORBIDDEN_ELEMENTS) {
    // Strip both <tag>...</tag> and self-closing <tag ... />
    const blockRe = new RegExp(`<${tag}[\\s>][\\s\\S]*?</${tag}>`, 'gi')
    svg = svg.replace(blockRe, '')
    const selfCloseRe = new RegExp(`<${tag}[\\s/][^>]*/?>`, 'gi')
    svg = svg.replace(selfCloseRe, '')
  }
  return svg
}

/**
 * Sanitize SVG markup by removing dangerous elements and attributes.
 * Uses an allowlist approach — only known-safe SVG elements are kept.
 */
export function sanitizeSvg(svg: string): string {
  if (!svg) return ''

  // 1. Strip forbidden element blocks (script, foreignObject, etc.)
  let clean = stripForbiddenBlocks(svg)

  // 2. Strip event handler attributes
  clean = clean.replace(EVENT_HANDLER_RE, '')

  // 3. Strip javascript: URLs
  clean = clean.replace(JS_URL_RE, '$1')

  // 4. Remove any elements not in the allowlist
  clean = clean.replace(TAG_RE, (match, tagName: string) => {
    const lower = tagName.toLowerCase()
    if (ALLOWED_ELEMENTS.has(lower) || ALLOWED_ELEMENTS.has(tagName)) {
      return match
    }
    return ''
  })

  return clean.trim()
}
