/* global DOMParser, Node */
import h from '../shared/h.js'
import { Link } from '../atoms/link.js'
import { Heading } from '../atoms/heading.js'
import { Table } from '../atoms/table.js'
import { List } from '../atoms/list.js'
import { Img } from '../atoms/img.js'

// Rich text provides basic typography rules for HTML content.
export function RichText ({ children: text, ...props }) {
  if (text) {
    const dp = new DOMParser()
    const doc = dp.parseFromString(text, 'text/html')
    const parsedChildren = [...doc.body.childNodes].map(child => getNode(child))

    return h('div', {
      ...props,
      className: 'space-y-4',
      _style: id => `
        ${id} :is(h1, h2, h3, h4, h5, h6):not(:first-child) { margin-top: 24px }
        ${id} pre { background-color: hsla(var(--color-txa), 0.05) }
        ${id} pre code { background: none; margin: 0; padding: 0; }
        ${id} code { background-color: hsla(var(--color-txa), 0.05) }
        ${id} details[open] > summary::after { rotate: 270deg }
        ${id} details[open] > *:not(:last-child) { margin-bottom: 8px }
        ${id} details > summary::after {
          position: absolute;
          top: 0;
          right: 0;
          height: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
          content: '❯';
          transition: var(--anim-time);
          rotate: 90deg;
          width: 12px;
          font-weight: normal;
          margin-right: 8px;
        }
      `,
      children: parsedChildren
    })
  }

  return null
}

function getNode (parent) {
  if (parent.nodeType === Node.ELEMENT_NODE) {
    const children = [...parent.childNodes].map(child => getNode(child))
    const tag = parent.tagName.toLowerCase()

    // Pass all attributes except style and class.
    const attrs = parent.getAttributeNames().reduce((obj, name) => {
      if (!['style', 'class'].includes(name)) {
        obj[name] = parent.getAttribute(name)
      }

      return obj
    }, { id: parent.id || undefined })

    const dispatcher = [{
      tags: ['a'],
      handler: () => {
        const _model = { value: parent.getAttribute('href') }

        // Text links.
        if (children.length === 1 && typeof children[0] === 'string') {
          _model.name = parent.text
        }

        return h(Link, {
          ...attrs,
          name: parent.name || undefined,
          target: parent.target || undefined,
          children,
          _model,
          _variant: 'underline'
        })
      }
    }, {
      tags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
      handler: () => h(Heading, { _level: tag.substr(1), ...attrs }, children)
    }, {
      tags: ['table'],
      handler: () => h(Table, attrs, h('tbody', {}, children))
    }, {
      tags: ['thead', 'tbody'],
      handler: () => children
    }, {
      tags: ['ol', 'ul'],
      handler: () => h(List, { _ordered: tag === 'ol' }, children)
    }, {
      tags: ['hr'],
      handler: () => h('hr', { className: 'w-6 h-1 bg-bgb' }, children)
    }, {
      tags: ['img'],
      handler: () => h('div', { className: 'rounded-lg overflow-hidden' },
        h(Img, { _model: { src: parent.src, alt: parent.alt } })
      )
    }, {
      tags: ['pre'],
      handler: () => h('pre', { className: 'p-2 rounded-lg' }, children)
    }, {
      tags: ['code'],
      handler: () => h('code', { className: 'inline-block rounded-sm font-mono text-sm px-1 py-px m-px break-all whitespace-pre-wrap' }, children)
    }, {
      tags: ['details'],
      handler: () => h('details', { className: 'rounded-md border border-txa/20 p-2', open: parent.open }, children)
    }, {
      tags: ['summary'],
      handler: () => h('summary', { className: 'clickable rounded-md py-2 ps-2 pe-6 -m-2 relative block pe-7 cursor-pointer font-bold' }, children)
    }]

    // Use predefined components if available.
    const route = dispatcher.find(item => item.tags.includes(tag))
    if (route) {
      return route.handler()
    }

    // Everything else.
    return h(tag, attrs, children)
  }

  // Text nodes.
  return parent.data
}
