import { useUserHasResponded } from 'domains/app/hooks'
import { useConfig } from 'domains/config/hooks'
import { useI18n } from 'domains/i18n/hooks'
import { selectLastUnreadEvent } from 'domains/store/selectors'
import { useTranslatedEventData } from 'domains/translations/hooks'
import { useVisibility } from 'domains/visibility/hooks'
import { className } from 'lib/css'
import { RefCallback } from 'preact'
import { useCallback, useEffect, useMemo, useRef } from 'preact/hooks'
import { useSelector } from 'react-redux'
import AppView from 'ui/components/view/app-view'
import InlineView from 'ui/components/view/inline-view'
import WindowView from 'ui/components/view/window-view'
import { useSeamlyAppContainerClassNames } from 'ui/hooks/component-helper-hooks'
import { useSeamlyContainerElement } from 'ui/hooks/focus-helper-hooks'
import {
  useSeamlyCurrentAgent,
  useSeamlyServiceInfo,
} from 'ui/hooks/seamly-state-hooks'
import useNotification from 'ui/hooks/use-notifications'

const ViewComponentsMap = {
  app: AppView,
  inline: InlineView,
  window: WindowView,
}

function stripHtml(html?: string) {
  const tmp = document.createElement('div')
  tmp.innerHTML = html || ''
  return tmp.textContent || tmp.innerText || ''
}

const View = ({ children = undefined }) => {
  const { sendNotification } = useNotification()
  const [, setSeamlyContainerElement] = useSeamlyContainerElement()
  const config = useConfig()
  const currentAgent = useSeamlyCurrentAgent()
  const { proactiveMessages } = useSeamlyServiceInfo()
  const { isOpen, isVisible } = useVisibility()
  const appContainerClassNames = useSeamlyAppContainerClassNames()
  const userHasResponded = useUserHasResponded()
  const lastUnreadEvent = useSelector(selectLastUnreadEvent)
  const { body } = useTranslatedEventData(lastUnreadEvent)
  const { userLocale } = useI18n()
  const prevLastUnreadEventId = useRef<string | undefined>(undefined)

  const notificationBody = useMemo(() => {
    if (!body) return ''
    if (typeof body === 'string') return stripHtml(body)
    if ('text' in body) return stripHtml(body.text)
    if ('prompt' in body && body.prompt && 'text' in body.prompt)
      return stripHtml(body.prompt?.text)
    return ''
  }, [body])

  useEffect(() => {
    if (
      !currentAgent?.name ||
      !notificationBody ||
      !proactiveMessages ||
      !lastUnreadEvent ||
      prevLastUnreadEventId.current === lastUnreadEvent.payload?.id
    ) {
      return
    }

    sendNotification(currentAgent.name, {
      body: notificationBody,
      icon: currentAgent?.avatar || undefined,
    })

    prevLastUnreadEventId.current = lastUnreadEvent.payload.id
  }, [
    currentAgent?.avatar,
    currentAgent?.name,
    lastUnreadEvent,
    notificationBody,
    proactiveMessages,
    sendNotification,
  ])
  const ViewComponent = ViewComponentsMap[config.layoutMode]

  const containerElementRef = useCallback<RefCallback<HTMLDivElement>>(
    (container) => {
      if (typeof setSeamlyContainerElement !== 'function') return
      setSeamlyContainerElement(container)
    },
    [setSeamlyContainerElement],
  )

  const blockLang = useMemo(() => {
    if (userLocale) {
      const htmlElementLang = document
        .querySelector('html')
        ?.getAttribute('lang')
      if (htmlElementLang !== userLocale) {
        return userLocale
      }
    }
    return undefined
  }, [userLocale])

  if (!ViewComponent) {
    console.warn('"layoutMode" should be one of "app", "inline" or "window"')
    return null
  }

  const defaultClassNames = [
    `app--layout-${config.layoutMode}`,
    `namespace--${config.namespace}`,
  ]

  const classNames = ['app', ...defaultClassNames]

  if (typeof appContainerClassNames !== 'function') {
    classNames.push(...appContainerClassNames)
  } else {
    classNames.push(...appContainerClassNames(config))
  }

  if (!isOpen && config.layoutMode !== 'app') {
    classNames.push('app--collapsed')
  }

  if (userHasResponded) {
    classNames.push('app--user-responded')
  }

  return isVisible ? (
    <div
      className={className(classNames)}
      lang={blockLang}
      tabIndex={-1}
      data-nosnippet
      style={{ zIndex: config?.zIndex }}
      ref={containerElementRef}
    >
      {children || <ViewComponent />}
    </div>
  ) : null
}

export default View
