import { useConfig } from 'domains/config/hooks'
import { useVisibility } from 'domains/visibility/hooks'
import { className } from 'lib/css'
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import IdleDetachWarning from 'ui/components/warnings/idle-detach-warning'
import ResumeConversationPrompt from 'ui/components/warnings/resume-conversation-prompt'
import { useSeamlyEntry } from 'ui/hooks/seamly-entry-hooks'
import {
  useFileUploadMeta,
  useSeamlyIdleDetachCountdown,
  useSeamlyResumeConversationPrompt,
  useSkiplinkTargetFocusing,
} from 'ui/hooks/seamly-hooks'
import { runIfElementContainsOrHasFocus } from 'ui/utils/general-utils'
import { entryTypes } from 'ui/utils/seamly-utils'
import TextEntry from './text-entry'
import Upload from './upload'
import UploadToggle from './upload-toggle'

const EntryContainer = () => {
  const { isOpen } = useVisibility()
  const entryContainer = useRef<HTMLDivElement>(null)
  const { hasCountdown } = useSeamlyIdleDetachCountdown()
  const [showCountdown, setShowCountDown] = useState(hasCountdown)
  const { hasPrompt: hasResumeConversationPrompt } =
    useSeamlyResumeConversationPrompt()
  const [showResumeConversationPrompt, setShowResumeConversationPrompt] =
    useState(hasResumeConversationPrompt)
  const focusSkiplinkTarget = useSkiplinkTargetFocusing()
  const containedFocus = useRef(false)
  const { activeEntry, activeEntryOptions } = useSeamlyEntry()
  const [entryComponents, setEntryComponents] = useState({
    text: TextEntry,
    upload: Upload,
  })
  const [renderEntry, setRenderEntry] = useState(() => activeEntry)
  const config = useConfig()
  const { accountAllowsUploads } = useFileUploadMeta()

  const focusFn = useCallback(() => {
    runIfElementContainsOrHasFocus(entryContainer.current, focusSkiplinkTarget)
  }, [focusSkiplinkTarget])

  useEffect(() => {
    const { customComponents } = config
    const { entry } = customComponents || {}

    if (entry) {
      setEntryComponents((c) => ({
        ...c,
        ...entry,
      }))
    }
  }, [config])

  useEffect(() => {
    // Focus the current target of the skip link if focus was inside the
    // container before this effect change.
    focusFn()
    setShowCountDown(hasCountdown)
    setShowResumeConversationPrompt(hasResumeConversationPrompt)
  }, [hasCountdown, hasResumeConversationPrompt, focusFn])

  useEffect(() => {
    setRenderEntry(activeEntry)
    // This focus action is required for auto entry changes. User driven
    // changes should be handled in the originating components.
    focusFn()
  }, [activeEntry, focusFn, entryContainer])

  // Check if the active element is inside this container and save it.
  containedFocus.current = !!(
    entryContainer.current &&
    entryContainer.current.contains(document.activeElement)
  )

  // Everything other than `text` and `upload` will fallback to `TextEntry` for now.
  // This is also done for `choice_prompt`, see comment above `allowManualInput` below.
  // At a later stage we could implement components like `DateTime` or `PhoneNumber`.
  const EntryComponent = entryComponents[renderEntry] || TextEntry

  // Currently we do not have an actual ChoicePrompt entry component.
  // If we ever do, this property should be moved to that component instead.
  // The current ChoicePrompt component is only responsible for the rendering of the buttons/choose again option.
  const { allowManualInput = true } = activeEntryOptions

  return (
    <div className={className('chat__entry')} ref={entryContainer}>
      {showCountdown && <IdleDetachWarning />}
      {showResumeConversationPrompt && <ResumeConversationPrompt />}
      <div
        className={className([
          'entry__body',
          ...(hasCountdown ||
          hasResumeConversationPrompt ||
          allowManualInput === false
            ? ['entry__body--hidden']
            : []),
        ])}
      >
        {renderEntry !== entryTypes.upload && accountAllowsUploads && isOpen ? (
          <UploadToggle />
        ) : null}
        <EntryComponent />
      </div>
    </div>
  )
}

export default EntryContainer
