/* global DOMParser */
import { useEffect, useState } from 'preact/hooks'
import getSizeClass from '../shared/get-size-class.js'
import h from '../shared/h.js'
import { tw } from '../shared/twind.js'

// Cache SVGs to prevent flickering.
const cache = {}

export function SVG ({ _model, _tall, ...props }) {
  const src = _model.src || ''
  const alt = _model.alt || ''
  const cacheKey = src + alt
  const sizeClass = getSizeClass(_tall)
  const [validSvg, setSvg] = useState(cache[cacheKey]) // Use the initial cached value.

  // The src might have changed. Use the current cached value.
  setSvg(cache[cacheKey])

  useEffect(() => {
    // Fetch if not cached.
    validSvg || (async function () {
      const isLink = src.endsWith('.svg') || src.startsWith('data:')
      const rawSvg = isLink ? await fetchSvg(src) : src
      cache[cacheKey] = getSvg(rawSvg, sizeClass, alt)
      setSvg(cache[cacheKey])
    })()
  }, [src, alt, sizeClass])

  return validSvg
    ? h('div', { ...props, className: `${sizeClass}`, dangerouslySetInnerHTML: { __html: validSvg } })
    : null
}

function getSvg (svgContent, sizeClass, alt) {
  const svgDoc = (new DOMParser()).parseFromString(svgContent, 'image/svg+xml')
  const parserError = svgDoc.getElementsByTagName('parsererror')[0]

  if (parserError) {
    console.warn(`Invalid SVG: ${svgContent}\n${parserError.innerText}`)
    return null
  }

  const svgEl = svgDoc.documentElement
  svgEl.setAttribute('class', tw(`block ${sizeClass}`))

  // Treat it like an image if alt is provided.
  if (alt) {
    svgEl.setAttribute('role', 'img')
    svgEl.setAttribute('title', alt)
  }

  return svgEl.outerHTML
}

async function fetchSvg (url) {
  try {
    const res = await fetch(url)
    return res.text()
  } catch (error) {
    console.warn('Unable to fetch SVG:', url)
    console.warn(error)
    return null
  }
}
