const { h, register, preactHooks } = globalThis.ami
const { useRef, useEffect, useState } = preactHooks

function ZendeskChat ({ src, locale, department, 'button-label': buttonLabel }) {
  const ref = useRef()
  const [width, setWidth] = useState(148)

  useEffect(() => createWidget(ref.current, src, locale, department, buttonLabel, setWidth), [])

  // Use z-20 for floating elements.
  return h('div', {
    ref,
    className: 'box-content bg-transparent fixed bottom-0 end-24 z-20 print:hidden',
    _style: id => `
      ${id} { width: ${width}px; height: 70px }
      ${id}[data-mobile=true] { width: 88px }
      ${id}[data-open=true] { width: 374px; height: 600px; max-height: 100dvh }
      ${id}[data-open=true][data-mobile=true] {
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
      }
    `
  })
}

// Documentation: https://developer.zendesk.com/api-reference/widget/introduction/
function createWidget (div, src, locale, department, buttonLabel, setWidth) {
  div.style = 'margin: 0; padding: 0;'

  // Create inner iframe.
  // Outer div constraints the size.
  // Inner iframe is 100dvh to make sure retarded Zendesk 'responsiveness' works.
  const innerIframe = document.createElement('iframe')
  innerIframe.style = `border: none; width: ${window.innerWidth}px; height: 100%; position: absolute; bottom: 0; right: 0`
  div.appendChild(innerIframe)

  const resizeHandler = () => {
    innerIframe.style.height = `${window.innerHeight}px`
  }
  window.addEventListener('resize', resizeHandler)

  const innerWindow = innerIframe.contentWindow
  const innerDoc = innerWindow.document
  const innerBody = innerDoc.body
  innerBody.style = 'margin: 0; padding: 0;'

  const updateWidth = () => {
    const launcher = innerDoc.getElementById('launcher')
    const launcherWidth = launcher.clientWidth
    if (launcherWidth > 0) {
      // Add some padding as button is getting cropped in windows.
      setWidth(launcherWidth + 20)
    }
  }

  // Watch for changes and detect if chat is open and if the retarded 'responsiveness' is enabled.
  const observer = new MutationObserver(() => {
    const launcher = innerDoc.getElementById('launcher')
    const isOpen = innerDoc.getElementById('webWidget')
    const isMobile = launcher?.style.width === '48px'
    div.dataset.mobile = !!isMobile
    div.dataset.open = !!isOpen

    if (launcher && !isOpen) {
      updateWidth()
    }
  })

  // Start observing body.
  observer.observe(innerBody, { attributes: true, childList: true, subtree: true })

  // Add Zendesk configuration.
  innerWindow.zESettings = {
    webWidget: {
      ...(buttonLabel && {
        launcher: {
          label: {
            '*': buttonLabel
          }
        }
      }),
      chat: {
        departments: {
          enabled: department ? [''] : undefined,
          select: department
        }
      }
    }
  }

  // Add Zendesk script.
  // For some reason locale can only be set after the script is loaded.
  // There does not seem to be a setting for this in zESettings.
  const safeLocale = locale || document.documentElement.lang || navigator.language
  const script = innerDoc.createElement('script')
  script.src = src
  script.id = 'ze-snippet'
  script.addEventListener('load', () => {
    innerWindow.zE('webWidget', 'setLocale', safeLocale)
    const style = innerDoc.createElement('style')
    style.textContent = `
      #launcher {
        margin: 0;
      }
    `
    innerDoc.head.appendChild(style)

    // Suppress chat if the department is offline.
    if (!department) {
      return
    }

    innerWindow.zE('webWidget:on', 'chat:connected', () => {
      const offline = innerWindow.zE('webWidget:get', 'chat:department', department)?.status === 'offline'
      if (offline) {
        innerWindow.zE('webWidget', 'updateSettings', { webWidget: { chat: { suppress: true } } })
      }
    })
  })

  innerBody.appendChild(script)

  return () => {
    observer.disconnect()
    window.removeEventListener('resize', resizeHandler)
  }
}

register(ZendeskChat, 'zendesk-chat')
