import { useLayoutEffect, useState } from 'preact/hooks'
import { Button } from '../atoms/button.js'
import { Heading } from '../atoms/heading.js'
import { Popup } from '../atoms/popup.js'
import { RichText } from '../atoms/rich-text.js'
import { Asset } from '../molecules/asset.js'
import { Links } from '../molecules/links.js'
import h from '../shared/h.js'
import { NAVIGATION_CLOSE } from '../shared/icons.js'
import t from '../shared/t.js'
import usePersistentState from '../shared/use-persistent-state.js'

const RETENTION = 8_640_000_000 // Expire after 100 days (the value is in milliseconds).
const STORAGE_KEY = 'suppressed_notifications'

export function Notification ({ _model, _variant, ...props }) {
  const { title, text, asset } = _model
  if (!title && !text) {
    return null
  }

  const [notifications, setNotifications] = usePersistentState(STORAGE_KEY, {})
  const [show, setShow] = useState(false)

  useLayoutEffect(() => {
    (async () => {
      const currentHash = await getHash(text)
      const updatedNotifications = { ...notifications }

      // Clean up expired notifications.
      for (const [hash, date] of Object.entries(notifications)) {
        if (new Date(date).getTime() + RETENTION < Date.now()) {
          delete updatedNotifications[hash]
        }
      }

      if (!updatedNotifications[currentHash]) {
        setShow(true)
        updatedNotifications[currentHash] = new Date().toISOString()
      }

      setNotifications(() => updatedNotifications)
    })().catch(console.error)
  }, [text])

  const _layout = _variant === 'center' ? 'center' : 'toast'
  const _modal = _variant === 'center'

  return h(Popup, { _show: show, _layout, _modal, 'aria-label': title, ...props },
    h('div', { className: 'flex gap-2' },
      h('div',
        h(Button, {
          _variant: 'plain',
          _textless: true,
          _size: 'xs',
          _model: {
            name: t('Dismiss'),
            value: '#',
            icon: NAVIGATION_CLOSE
          },
          onClick: event => {
            event.preventDefault()
            setShow(false)
          }
        })
      ),
      h('div', { className: 'grow order-first' },
        h(Heading, { _level: '3' }, title)
      )
    ),
    _layout === 'center' && asset.src && h('figure', { className: 'col-span-2 space-y-1' },
      h('div', { className: 'rounded-lg overflow-hidden' },
        h(Asset, { _model })
      ),
      asset.caption && h('figcaption', asset.caption)
    ),
    h(RichText, text),
    h(Links, { _model })
  )
}

async function getHash (str) {
  // crypto.subtle is only available on HTTPS (or literal localhost).
  const buf = await crypto?.subtle?.digest?.('SHA-256', new TextEncoder().encode(str))
  const arr = Array.from(new Uint8Array(buf))
  return arr.map(num => num.toString(16).padStart(2, '0')).join('')
}
